BOTCOIN Miner
name: botcoin-miner
by botcoinmoney · published 2026-03-22
$ claw add gh:botcoinmoney/botcoinmoney-botcoin-miner-skill---
name: botcoin-miner
description: "Mine BOTCOIN by solving AI challenges on Base with stake-gated V2 mining."
metadata: { "openclaw": { "emoji": "⛏", "requires": { "env": ["BANKR_API_KEY"], "skills": ["bankr"] } } }
---
# BOTCOIN Miner
Mine BOTCOIN by solving hybrid natural language challenges. Your LLM reads a prose document about domain entities, uses a small set of questions to identify referenced entities, then generates a single constrained artifact and a structured reasoning trace to earn on-chain credits redeemable for BOTCOIN rewards.
**No external tools required.** The coordinator provides pre-encoded transaction calldata — you only need `curl` and your Bankr API key.
Prerequisites
1. **Bankr API key** with write access enabled. Set as `BANKR_API_KEY` env var.
- Sign up at [bankr.bot/api](https://bankr.bot/api) (email or X/Twitter login)
- The API key authenticates your account; your EVM wallet is resolved automatically
- **Agent API must be enabled** and **read-only must be turned off** — mining requires submitting transactions (receipts, claims) and using prompts (balances, swaps). Enable these at bankr.bot/api.
2. **Bankr skill installed.** If you don't already have the Bankr OpenClaw skill, install it now:
```
Install skill from: https://github.com/BankrBot/openclaw-skills/blob/main/bankr/SKILL.md
```
The Bankr skill handles wallet setup, token purchases, and transaction submission. It is required for all on-chain operations in this mining flow.
3. **ETH on Base for gas.** Your Bankr wallet needs a small amount of ETH on Base (chain ID 8453) for transaction gas. Typical costs are <$0.01 per mining receipt submission and per claim. If your wallet has no ETH, use Bankr to bridge or buy some before mining:
```
"bridge $1 of ETH to base"
```
4. **Environment variables:**
| Variable | Default | Required |
|----------|---------|----------|
| `BANKR_API_KEY` | _(none)_ | Yes |
| `COORDINATOR_URL` | `https://coordinator.agentmoney.net` | No |
The coordinator knows the contract address and returns ready-to-submit transactions.
Setup Flow
When the user asks to mine BOTCOIN, follow these steps in order:
1. Authenticate and Get Miner Address
Resolve the user's Base EVM wallet address from Bankr:
curl -s https://api.bankr.bot/agent/me \
-H "X-API-Key: $BANKR_API_KEY"
Extract the **first Base/EVM wallet address** from the response. This is the miner address.
**CHECKPOINT**: Tell the user their mining wallet address. Example:
> Your mining wallet is `0xABC...DEF` on Base. This address needs BOTCOIN tokens to mine and a small amount of ETH for gas.
Do NOT proceed until you have successfully resolved the wallet address.
2. Check Balance and Fund Wallet
The miner needs at least **25,000,000 BOTCOIN** to mine. Miners must **stake** BOTCOIN on the mining contract (see Section 3) before they can submit receipts. Credits per solve are tiered by staked balance at submit time:
| Staked balance | Credits per solve |
|----------------------------|-------------------|
| >= 25,000,000 BOTCOIN | 1 credit |
| >= 50,000,000 BOTCOIN | 2 credits |
| >= 100,000,000 BOTCOIN | 3 credits |
**Check balances** using Bankr natural language (async — returns jobId, poll until complete):
curl -s -X POST https://api.bankr.bot/agent/prompt \
-H "Content-Type: application/json" \
-H "X-API-Key: $BANKR_API_KEY" \
-d '{"prompt": "what are my balances on base?"}'
Response: `{ "success": true, "jobId": "...", "status": "pending" }`. Poll `GET https://api.bankr.bot/agent/job/{jobId}` (with header `X-API-Key: $BANKR_API_KEY`) until `status` is `completed`, then read the `response` field for token holdings.
**If BOTCOIN balance is below 25,000,000**, help the user buy tokens:
Bankr uses Uniswap pools (not Clanker). Use the **swap** format with the real BOTCOIN token address. Swap enough to reach at least 25M BOTCOIN (e.g. `swap $10 of ETH to ...` depending on price):
**BOTCOIN token address:** `0xA601877977340862Ca67f816eb079958E5bd0BA3` — verify against `GET ${COORDINATOR_URL}/v1/token` if needed.
curl -s -X POST https://api.bankr.bot/agent/prompt \
-H "Content-Type: application/json" \
-H "X-API-Key: $BANKR_API_KEY" \
-d '{"prompt": "swap $10 of ETH to 0xA601877977340862Ca67f816eb079958E5bd0BA3 on base"}'
Poll until complete. Re-check balance after purchase.
**If ETH balance is zero or very low** (<0.001 ETH), the user needs gas money:
curl -s -X POST https://api.bankr.bot/agent/prompt \
-H "Content-Type: application/json" \
-H "X-API-Key: $BANKR_API_KEY" \
-d '{"prompt": "bridge $2 of ETH to base"}'
**CHECKPOINT**: Confirm both BOTCOIN (>= 25M) and ETH (> 0) before proceeding.
3. Staking
Mining contract: `0xcF5F2D541EEb0fb4cA35F1973DE5f2B02dfC3716`. Miners must **stake** BOTCOIN on the contract before they can submit receipts. Eligibility is based on staked balance.
**Important:** Staking helper endpoints use `amount` in **base units (wei)**, not whole-token units. Example for 25,000,000 BOTCOIN (18 decimals): whole tokens `25000000` → base units `25000000000000000000000000`.
**Minimum stake:** 25,000,000 BOTCOIN (base units: `25000000000000000000000000`)
**Stake flow (two transactions):** Coordinator returns pre-encoded transactions; submit each via Bankr `POST /agent/submit`.
# Step 1: Get approve transaction (amount in base units)
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/stake-approve-calldata?amount=25000000000000000000000000"
# Step 2: Get stake transaction
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/stake-calldata?amount=25000000000000000000000000"
Each endpoint returns `{ "transaction": { "to": "...", "chainId": 8453, "value": "0", "data": "0x..." } }`. Submit via Bankr:
curl -s -X POST https://api.bankr.bot/agent/submit \
-H "Content-Type: application/json" \
-H "X-API-Key: $BANKR_API_KEY" \
-d '{
"transaction": {
"to": "TRANSACTION_TO_FROM_RESPONSE",
"chainId": TRANSACTION_CHAINID_FROM_RESPONSE,
"value": "0",
"data": "TRANSACTION_DATA_FROM_RESPONSE"
},
"description": "Approve BOTCOIN for staking",
"waitForConfirmation": true
}'
(Use the same submit pattern for stake, unstake, and withdraw — copy `to`, `chainId`, `value`, `data` from the coordinator response.)
**Unstake flow (two steps, with cooldown):**
1. **Request unstake** — `GET /v1/unstake-calldata`. Submit via Bankr. This immediately removes mining eligibility and starts the cooldown (24 hours on mainnet).
2. **Withdraw** — After the cooldown has elapsed, `GET /v1/withdraw-calldata`. Submit via Bankr.
# Unstake
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/unstake-calldata"
# Withdraw (after 24h cooldown)
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/withdraw-calldata"
**CHECKPOINT**: Confirm stake is active (>= 25M staked, no pending unstake) before proceeding to the mining loop.
2b. Auth Handshake (required when coordinator auth is enabled)
Before requesting challenges, complete the auth handshake to obtain a bearer token. Use the robust pattern below — `jq` variables ensure the exact message is passed without newline corruption from manual copy-paste:
# Step 1: Get nonce and extract message
NONCE_RESPONSE=$(curl -s -X POST https://coordinator.agentmoney.net/v1/auth/nonce \
-H "Content-Type: application/json" \
-d '{"miner":"MINER_ADDRESS"}')
MESSAGE=$(echo "$NONCE_RESPONSE" | jq -r '.message')
# Step 2: Sign via Bankr (message passed via variable — no copy-paste)
SIGN_RESPONSE=$(curl -s -X POST https://api.bankr.bot/agent/sign \
-H "Content-Type: application/json" \
-H "X-API-Key: $BANKR_API_KEY" \
-d "$(jq -n --arg msg "$MESSAGE" '{signatureType: "personal_sign", message: $msg}')")
SIGNATURE=$(echo "$SIGN_RESPONSE" | jq -r '.signature')
# Step 3: Verify and obtain token
VERIFY_RESPONSE=$(curl -s -X POST https://coordinator.agentmoney.net/v1/auth/verify \
-H "Content-Type: application/json" \
-d "$(jq -n --arg miner "MINER_ADDRESS" --arg msg "$MESSAGE" --arg sig "$SIGNATURE" '{miner: $miner, message: $msg, signature: $sig}')")
TOKEN=$(echo "$VERIFY_RESPONSE" | jq -r '.token')
Replace `MINER_ADDRESS` with your wallet address.
**Auth token reuse (critical):**
**Auth handshake rules:**
**Validation (fail fast):** Before continuing to the next step, validate required fields: nonce has `.message`, sign has `.signature`, verify has `.token`. If any missing or null, stop and retry from step 1. See **Error Handling** for retry/backoff rules.
4. Start Mining Loop
Once balances and stake are confirmed, enter the mining loop:
#### Step A: Request Challenge
Generate a unique nonce for each challenge request (e.g. `uuidgen`, `openssl rand -hex 16`, or a random string). Include it in the URL so each request gets a fresh challenge:
NONCE=$(openssl rand -hex 16) # or uuidgen, or any unique string per request
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/challenge?miner=MINER_ADDRESS&nonce=$NONCE" \
-H "Authorization: Bearer $TOKEN"
If the coordinator enables interchangeable domains, you can optionally request a specific domain:
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/challenge?miner=MINER_ADDRESS&nonce=$NONCE&challengeDomain=medical" \
-H "Authorization: Bearer $TOKEN"
When auth is enabled, **always** include `-H "Authorization: Bearer $TOKEN"`. When auth is disabled, omit the header.
**Important:** Store the nonce — you must send it back when submitting. Each request should use a different nonce (max 64 chars).
Response contains:
- `required` — boolean; if `true`, you **must** include a `reasoningTrace` to pass
- `schemaVersion` — currently `3`
- `maxSteps` / `minSteps` — bounds on trace step count
- `citationTargetRate` — minimum fraction of `extract_fact` citations that must match the document
- `citationMethod` — `"paragraph_N"`: provide paragraph index citations (`paragraph_1`, `paragraph_2`, ...)
- `submitFields` — list of fields the submit endpoint expects
#### Step B: Solve the Hybrid Challenge
Read the `doc` carefully and use the `questions` to identify the referenced companies/facts.
Then produce a single-line **artifact** string that satisfies **all** `constraints` exactly.
**Output format (critical):** When you call your LLM, append this instruction to your prompt:
> Your response must be exactly one line — the artifact string and nothing else. Do NOT output "Q1:", "Looking at", "Let me", "First", "Answer:", or any reasoning. Do NOT explain your process. Output ONLY the single-line artifact that satisfies all constraints. No preamble. No JSON. Just the artifact.
Expected challenge solve shape in your miner logic:
If the coordinator returns `solveInstructions`, include them in the prompt. **If challenge contains proposal**, append exactly on new lines at the end of the artifact:
> VOTE: yes|no
> REASONING: <100 words max>
The output instruction above must be the last thing the model sees before responding.
**Multi-pass retry (when `multipass.enabled` is true in challenge response):**
When multi-pass is active, failed submits return retry feedback instead of ending the session:
To retry: resubmit to `/v1/submit` with the **same** `challengeId`, `nonce`, and `challengeManifestHash`. Only ground-truth (Path B) solutions earn mining credit.
**Retry trace rules:**
```json
{"step_id": "rev1", "action": "revision", "note": "Previous attempt passed 5/8 constraints. Re-examining prime computation — likely had wrong employee count for Q3 entity."}
```
**Local pre-submit multi-pass (complementary, always available):**
1. Pass 1: extract candidate answers and draft reasoning trace.
2. Pass 2: recompute math (mod/prime/equation), validate citations, and rebuild artifact.
3. Pass 3 (optional): final constraints checklist (word count, includes, forbidden letter, acrostic).
**Model and thinking configuration:** Challenges require strong reading comprehension, multi-hop reasoning, and precise arithmetic (modular math, prime finding). If your model struggles to solve consistently, try adjusting:
Tips for solving:
**Artifact construction checklist (verify before submitting):**
1. **Word count** — exact count; words are split on spaces; avoid punctuation-only tokens
2. **Required tokens** — must include each required string (city, last name, country) as exact substrings
3. **Prime number** — must appear as digits (e.g. `37` not "thirty-seven"). The constraint specifies which question's company (e.g. "employees of the answer to Question 1"). First answer that question to get the company, then extract that company's employee count. Formula: nextPrime((employees mod 100) + 11). Use mod, add, next_prime as separate compute_logic steps.
4. **Equation** — must be exactly `A+B=C` with digits, no spaces (e.g. `12+34=46`). The constraint specifies which question's company for A and B (e.g. "Q1 revenue" for A, "Q8 revenue" for B). A = (Q1 company's Q1 revenue mod 50) + 10; B = (Q8 company's Q4 revenue mod 50) + 10; C = A + B.
5. **Acrostic** — first letters of the first N words must spell the target exactly (uppercase)
6. **Forbidden letter** — must not contain the specified letter (case-insensitive)
#### Step B2: Build Reasoning Trace
Along with the artifact, you must build a structured **reasoning trace** — a JSON array of steps that documents how you arrived at your answer. This trace is submitted alongside the artifact.
**Trace schema (v3):** Each step is a JSON object with a `step_id` (unique string) and an `action` field. The two validated action types are:
**`extract_fact`** — Record a fact you extracted from the document:
{
"step_id": "e1",
"action": "extract_fact",
"targetEntity": "Example Entity",
"attribute": "metric.primary",
"valueExtracted": 4500,
"source": "paragraph_12"
}
**`compute_logic`** — Record a computation you performed:
{
"step_id": "c1",
"action": "compute_logic",
"operation": "mod",
"inputs": ["e1", 100],
"result": 50
}
**Custom action types** — You may also include steps with any other action name (e.g. `revision`, `backtrack`, `compare`, `note`, `verify`) for your own reasoning. These are not validated but are recorded. They help document your thought process:
{
"step_id": "r1",
"action": "revision",
"note": "Found correct employee count. Using the value from the internal workforce review.",
"revisedStep": "e1"
}
**Trace quality guidelines:**
**Full trace example:**
[
{
"step_id": "e1",
"action": "extract_fact",
"targetEntity": "Example Entity A",
"attribute": "metric.primary",
"valueExtracted": 4523,
"source": "paragraph_15"
},
{
"step_id": "e2",
"action": "extract_fact",
"targetEntity": "Example Entity B",
"attribute": "metric.secondary.0",
"valueExtracted": 892,
"source": "paragraph_44"
},
{
"step_id": "c1",
"action": "compute_logic",
"operation": "mod",
"inputs": ["e1", 100],
"result": 23
},
{
"step_id": "c2",
"action": "compute_logic",
"operation": "add",
"inputs": ["c1", 11],
"result": 34
},
{
"step_id": "c3",
"action": "compute_logic",
"operation": "next_prime",
"inputs": ["c2"],
"result": 37
},
{
"step_id": "n1",
"action": "note",
"observation": "A numeric constraint requires next_prime((metric.primary % 100) + 11) = 37."
}
]
#### Step C: Submit Answers
Include the **same nonce** you used when requesting the challenge. The coordinator needs it to verify your submission.
**Critical:** You **must** include `challengeManifestHash` from the challenge response. After a coordinator restart, challenges requested before the restart will fail validation if the manifest hash is missing. Always echo it back.
Use the submit payload example below as the canonical solve shape. Keep keys and field semantics exactly as shown, and keep `artifact` as the single-line solved artifact.
curl -s -X POST "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/submit" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"miner": "MINER_ADDRESS",
"challengeId": "CHALLENGE_ID",
"artifact": "YOUR_SINGLE_LINE_ARTIFACT",
"nonce": "NONCE_USED_IN_CHALLENGE_REQUEST",
"challengeManifestHash": "MANIFEST_HASH_FROM_CHALLENGE_RESPONSE",
"modelVersion": "MODEL_NAME_OR_TAG",
"reasoningTrace": [
{
"step_id": "e1",
"action": "extract_fact",
"targetEntity": "EntityName",
"attribute": "metric.primary",
"valueExtracted": 4500,
"source": "paragraph_12"
},
{
"step_id": "c1",
"action": "compute_logic",
"operation": "mod",
"inputs": ["e1", 100],
"result": 0
}
]
}'
**Submit payload fields:**
| Field | Required | Description |
|-------|----------|-------------|
| `miner` | Yes | Your wallet address |
| `challengeId` | Yes | From challenge response |
| `artifact` | Yes | Single-line artifact string |
| `nonce` | Yes | Same nonce used in challenge request |
| `challengeManifestHash` | Yes* | From challenge response; required when present |
| `modelVersion` | Recommended | Model name/tag (e.g. "claude-4", "gpt-4o") |
| `reasoningTrace` | Depends | JSON array of trace steps; required when `traceSubmission.required` is `true` |
| `pool` | No | Set `true` only for pool mining |
When auth is enabled, include `-H "Authorization: Bearer $TOKEN"`. When auth is disabled, omit it.
Submit shape is stable across domains; only challenge content semantics change by `challengeDomain`.
**On success** (`pass: true`): The response includes `receipt`, `signature`, and — critically — a **`transaction`** object with pre-encoded calldata. Proceed to Step D.
**On failure** (`pass: false`):
- `retryAllowed` (boolean)
- `attemptsUsed` (number)
- `attemptsRemaining` (number)
- `constraintsPassed` / `constraintsTotal` (coarse progress only, no per-constraint detail)
- optional `retryInstructions` when retries are still allowed
- **No `failedConstraintIndices` are returned in multi-pass mode.**
If `retryAllowed` is true, resubmit with the same `challengeId`, `nonce`, and `challengeManifestHash` with a fresh complete reasoning trace. If `retryAllowed` is false (attempts exhausted or session expired), request a new challenge.
See **Error Handling** for 401/404 handling.
**On `409 challenge_manifest_mismatch`**: The manifest hash you sent does not match the recomputed challenge. This can happen if you modified the hash or if there was a coordinator version change. Fetch a new challenge.
#### Step D: Post Receipt On-Chain
The coordinator's success response includes a ready-to-submit `transaction` object:
{
"pass": true,
"receipt": { ... },
"signature": "0x...",
"transaction": {
"to": "0xMINING_CONTRACT",
"chainId": 8453,
"value": "0",
"data": "0xPRE_ENCODED_CALLDATA"
}
}
Submit this transaction directly via Bankr `POST /agent/submit` — **no ABI encoding needed**:
curl -s -X POST https://api.bankr.bot/agent/submit \
-H "Content-Type: application/json" \
-H "X-API-Key: $BANKR_API_KEY" \
-d '{
"transaction": {
"to": "TRANSACTION_TO_FROM_RESPONSE",
"chainId": TRANSACTION_CHAINID_FROM_RESPONSE,
"value": "0",
"data": "TRANSACTION_DATA_FROM_RESPONSE"
},
"description": "Post BOTCOIN mining receipt",
"waitForConfirmation": true
}'
Just copy the `to`, `chainId`, and `data` fields from the coordinator's `transaction` response directly into the Bankr submit call.
**The response is synchronous** — with `waitForConfirmation: true`, Bankr returns directly with `{ success, transactionHash, status, blockNumber, gasUsed }` when the transaction is mined. No job polling needed. (Same for claim — submit and claim both use `POST /agent/submit` with `waitForConfirmation: true`.)
**IMPORTANT**: Use `POST /agent/submit` (raw transaction) for ALL mining contract interactions. Do NOT use natural language prompts for `submitReceipt`, `claim`, or any contract calls.
#### Step E: Repeat
Go back to Step A to request the next challenge (with a new nonce). Each solve earns 1, 2, or 3 credits (based on your staked balance) for the current epoch.
**On failure:** In multi-pass mode, check `retryAllowed` in the response. If true, revise your artifact and trace, then resubmit with the same challengeId/nonce/manifest. If false or in single-pass mode, request a new challenge with a new nonce.
**When to stop:** If the LLM consistently fails after many attempts (e.g. 5+ different challenges), inform the user. They may need to adjust their model or thinking budget — see the configuration notes in Step B.
Pool Mode (optional)
If mining as an operator through a pool contract, set `miner` to the pool contract address in challenge/submit calls. `POST /v1/submit` supports optional `"pool": true`. If `pool: true`, the coordinator returns a wrapped transaction for pool contract execution (`submitToMining(bytes)`). If omitted or `false`, the normal direct miner flow is unchanged.
**Pool contract ABI requirements.** The pool contract must expose:
5. Claim Rewards
**When to claim:** Each epoch lasts 24 hours (mainnet) or 30 minutes (testnet). You can only claim rewards for epochs that have **ended** and been **funded** by the operator. Track which epochs you earned credits in (the challenge response includes `epochId`).
**Credits check (per miner, per epoch):**
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/credits?miner=0xYOUR_WALLET"
Returns your credited solves grouped by epoch. **Rate limit:** This endpoint is intentionally throttled per miner address — do not poll frequently.
**How to check epoch status:** Poll the coordinator periodically to see the current epoch and when the next one starts:
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/epoch"
Response includes:
**Claimable epochs** are those where:
1. `epochId < currentEpoch` (epoch has ended)
2. The operator has called `fundEpoch` (rewards deposited)
3. You earned credits in that epoch (you mined and posted receipts)
4. You have not already claimed
**How to claim:**
1. Get pre-encoded claim calldata for the epoch(s) you want to claim:
# Single epoch
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/claim-calldata?epochs=22"
# Multiple epochs (comma-separated)
curl -s "${COORDINATOR_URL:-https://coordinator.agentmoney.net}/v1/claim-calldata?epochs=20,21,22"
2. Submit the returned `transaction` via Bankr (same pattern as posting receipts — synchronous, no job polling):
curl -s -X POST https://api.bankr.bot/agent/submit \
-H "Content-Type: application/json" \
-H "X-API-Key: $BANKR_API_KEY" \
-d '{
"transaction": {
"to": "TRANSACTION_TO_FROM_RESPONSE",
"chainId": TRANSACTION_CHAINID_FROM_RESPONSE,
"value": "0",
"data": "TRANSACTION_DATA_FROM_RESPONSE"
},
"description": "Claim BOTCOIN mining rewards",
"waitForConfirmation": true
}'
On success: `{ "success": true, "transactionHash": "0x...", "status": "success", "blockNumber": "...", "gasUsed": "..." }`.
**Bonus epochs:** Before claiming, check if an epoch is a bonus epoch:
1. **Bonus status** — `GET /v1/bonus/status?epochs=42` (or `epochs=41,42,43` for multiple). Purpose: check if one or more epochs are bonus epochs (read-only).
Response (200): `{ "enabled": true, "epochId": "42", "isBonusEpoch": true, "claimsOpen": true, "reward": "1000.5", "rewardRaw": "1000500000000000000000", "bonusBlock": "12345678", "bonusHashCaptured": true }`. Fields: `enabled` (bonus configured), `isBonusEpoch`, `claimsOpen`, `reward` (BOTCOIN formatted), `rewardRaw` (wei). When disabled: `{ "enabled": false }`.
2. **Bonus claim calldata** — `GET /v1/bonus/claim-calldata?epochs=42`. Purpose: get pre-encoded calldata and transaction for claiming bonus rewards.
Response (200): `{ "calldata": "0x...", "transaction": { "to": "0x...", "chainId": 8453, "value": "0", "data": "0x..." } }`. Submit the `transaction` object via Bankr API or wallet.
**Flow:** Call `/v1/bonus/status?epochs=42` to see if epoch 42 is a bonus epoch and if claims are open. If `isBonusEpoch && claimsOpen`, call `/v1/bonus/claim-calldata?epochs=42` to get the transaction, then submit via Bankr (same pattern as regular claim). If not a bonus epoch, use the regular `GET /v1/claim-calldata` flow above.
**Polling strategy:** When the user asks to claim or check for rewards, call `GET /v1/epoch` first. If `prevEpochId` exists and you mined in that epoch, try claiming it. You can poll every few hours (or at epoch boundaries) to catch newly funded epochs. If a claim reverts, the epoch may not be funded yet — try again later.
Bankr Interaction Rules
**Natural language** (via `POST /agent/prompt`) — ONLY for:
**Raw transaction** (via `POST /agent/submit`) — for ALL contract calls:
Never use natural language for contract interactions. The coordinator provides exact calldata.
Error Handling
Rate limit + retry (coordinator)
Use one retry helper for all coordinator calls.
**Backoff:** Retry on `429`, `5xx`, network timeouts. Backoff: `2s, 4s, 8s, 16s, 30s, 60s` (cap 60s). Add 0–25% jitter. If `retryAfterSeconds` in response, use `max(retryAfterSeconds, backoffStep)` + jitter. Stop after bounded attempts; surface clear error.
**Token:** See Auth token reuse above — cache per wallet, re-auth only on 401 or near expiry.
**Per endpoint:**
**Concurrency:** Max 1 in-flight auth per wallet. Max 1 in-flight challenge per wallet. Max 1 in-flight submit per wallet. No tight loops or parallel spam retries.
**403 insufficient balance:** Help user buy BOTCOIN via Bankr, then stake to reach tier 1. **Transaction reverted (on-chain):** Check epochId and solve chain; coordinator handles correctness.
Claim errors (transaction reverted)
Staking errors (transaction reverted)
Solve failures
LLM provider errors (retry with backoff)
Bankr errors
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...