From 936743ead760c507a4886141cf7d5b94d50e53a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ois=C3=ADn=20Kyne?= Date: Tue, 7 Jul 2026 00:12:19 +0100 Subject: [PATCH] feat(skills): give some refresh to our skills --- CLAUDE.md | 2 +- README.md | 46 ++--- internal/embed/embed_skills_test.go | 3 +- internal/embed/skills/addresses/SKILL.md | 3 +- .../addresses/references/obol-payments.md | 58 ++++++ internal/embed/skills/agent-factory/SKILL.md | 2 +- internal/embed/skills/monetize-guide/SKILL.md | 2 +- internal/embed/skills/sell/SKILL.md | 2 +- .../embed/skills/sub-agent-business/SKILL.md | 190 ++++++++++++++++++ internal/embed/skills/swap/SKILL.md | 137 +++++++++++++ 10 files changed, 416 insertions(+), 29 deletions(-) create mode 100644 internal/embed/skills/addresses/references/obol-payments.md create mode 100644 internal/embed/skills/sub-agent-business/SKILL.md create mode 100644 internal/embed/skills/swap/SKILL.md diff --git a/CLAUDE.md b/CLAUDE.md index 3eaf1db6..915562f1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -472,7 +472,7 @@ The Cloudflare tunnel exposes the cluster to the public internet. Only x402-gate | `internal/enclave` | `enclave.go`, `enclave_darwin.go`, `enclave_stub.go` | Secure Enclave keys | | `internal/embed` | `embed.go` | Embedded assets (skills, infrastructure, networks) | -**Embedded assets**: `internal/embed/infrastructure/` (K8s templates), `internal/embed/networks/` (ethereum, aztec), `internal/embed/skills/` (21 skills). +**Embedded assets**: `internal/embed/infrastructure/` (K8s templates), `internal/embed/networks/` (ethereum, aztec), `internal/embed/skills/` (23 skills). **Tests**: `cmd/obol/sell_test.go` (CLI flags), `internal/x402/*_test.go` (verifier, config, matcher, E2E), `internal/erc8004/*_test.go` (ABI, client), `internal/embed/embed_crd_test.go` (CRD+RBAC validation), `internal/openclaw/integration_test.go` (full-cluster inference), `internal/openclaw/overlay_test.go`, `internal/inference/gateway_test.go`, `internal/serviceoffercontroller/*_test.go` (controller, render). diff --git a/README.md b/README.md index 72a1dcc8..aac76095 100644 --- a/README.md +++ b/README.md @@ -212,43 +212,43 @@ Use `obol agent` for Obol-managed lifecycle and auth flows. Use `obol hermes` fo The stack ships with embedded Obol skills installed automatically for the default Hermes agent and OpenClaw instances. Skills give agents domain-specific capabilities — from querying blockchains to buying and selling services. -#### Infrastructure & Commerce +#### Commerce & Agents | Skill | Purpose | |-------|---------| +| `sub-agent-business` | The business playbook — design, evaluate, price, and sell specialised sub-agents people pay per turn | +| `agent-factory` | Spawn durable child agents with their own namespace, wallet, skills, and paid endpoint | +| `sell` | ServiceOffer CRUD — payment-gated routes, reconciliation status, ERC-8004 registration | +| `monetize-guide` | Guided end-to-end walkthrough for selling inference or an HTTP API | | `buy-x402` | Buy paid services: probe pricing, pre-sign payments, auto-refill, check balances | -| `monetize` | Manage the agent's own sell offers (ServiceOffer CRUD) | -| `ethereum-networks` | Read-only Ethereum queries via cast — blocks, balances, contract reads, ERC-20, ENS | -| `ethereum-local-wallet` | Sign and send Ethereum transactions via the per-agent remote-signer | -| `obol-stack` | Kubernetes cluster diagnostics — pods, logs, events, deployments | -| `distributed-validators` | Obol DVT cluster monitoring, operator audit, exit coordination | +| `discovery` | Find agents registered on the ERC-8004 Identity Registry across chains | +| `swap` | Treasury moves — swap USDC/ETH/OBOL on Base and mainnet via Uniswap V3 | +| `autoresearch` | Run autonomous LLM optimization experiments and publish the best checkpoints | +| `autoresearch-coordinator` | Coordinate distributed experiments across GPU workers, discovered via ERC-8004 and paid via x402 | +| `autoresearch-worker` | Sell your GPU as a paid experiment worker | -#### Ethereum Development +#### Ethereum | Skill | Purpose | |-------|---------| -| `addresses` | Verified contract addresses — DeFi, tokens, bridges, ERC-8004 registries across chains | -| `building-blocks` | OpenZeppelin patterns, DEX integration, oracle usage, access control | -| `concepts` | Mental model — state machines, incentive design, gas mechanics, EOAs vs contracts | -| `gas` | Gas optimization patterns, L2 fee structures, estimation | -| `indexing` | The Graph, Dune, event indexing for onchain data | -| `l2s` | L2 comparison — Base, Arbitrum, Optimism, zkSync with gas costs and use cases | -| `orchestration` | End-to-end dApp build (Scaffold-ETH 2) + AI agent commerce cycle | -| `security` | Smart contract vulnerability patterns, reentrancy, flash loans, MEV protection | +| `ethereum-networks` | Read-only Ethereum queries via cast — blocks, balances, contract reads, ERC-20, ENS | +| `ethereum-local-wallet` | Sign and send Ethereum transactions via the per-agent remote-signer | +| `addresses` | Verified contract addresses — payment rails, DeFi, tokens, bridges, ERC-8004 registries | +| `building-blocks` | DeFi legos and protocol composability — Uniswap, Aave, Aerodrome, Pendle | +| `concepts` | Mental model — state machines, incentive design, why nothing onchain is automatic | +| `gas` | Real transaction costs today, mainnet vs L2, fee settings | +| `indexing` | The Graph, Dune, Ponder, event-first design for onchain data at scale | +| `l2s` | L2 comparison — Base, Arbitrum, Optimism, zkSync with costs and use cases | | `standards` | ERC-8004, x402, EIP-3009, EIP-7702, ERC-4337 — spec details and integration patterns | -| `ship` | Architecture planning — onchain vs offchain, chain selection, agent service patterns | -| `testing` | Foundry testing — unit, fuzz, fork, invariant tests | -| `tools` | Development tooling — Foundry, Hardhat, Scaffold-ETH 2, verification | | `wallets` | Wallet management — EOAs, Safe multisig, EIP-7702, key safety for AI agents | +| `why` | Why Ethereum — the AI agent angle with ERC-8004 and x402 | -#### Frontend & QA +#### Operations | Skill | Purpose | |-------|---------| -| `frontend-playbook` | Deployment — IPFS, Vercel, ENS subdomains | -| `frontend-ux` | Web3 UX patterns — wallet connection, transaction flows, error handling | -| `qa` | Quality assurance — testing strategy, coverage, CI/CD patterns | -| `why` | Why Ethereum — the AI agent angle with ERC-8004 and x402 | +| `obol-stack` | Kubernetes cluster diagnostics — pods, logs, events, deployments | +| `distributed-validators` | Obol DVT cluster monitoring, operator audit, exit coordination | Manage skills at runtime: diff --git a/internal/embed/embed_skills_test.go b/internal/embed/embed_skills_test.go index cb644e9a..39d86ca1 100644 --- a/internal/embed/embed_skills_test.go +++ b/internal/embed/embed_skills_test.go @@ -19,7 +19,8 @@ func TestGetEmbeddedSkillNames(t *testing.T) { coreSkills := []string{ "addresses", "agent-factory", "building-blocks", "buy-x402", "concepts", "discovery", "distributed-validators", "ethereum-networks", "ethereum-local-wallet", - "gas", "indexing", "l2s", "sell", "obol-stack", "standards", "wallets", "why", + "gas", "indexing", "l2s", "sell", "obol-stack", "standards", "sub-agent-business", + "swap", "wallets", "why", } sort.Strings(names) diff --git a/internal/embed/skills/addresses/SKILL.md b/internal/embed/skills/addresses/SKILL.md index b6b65b59..bdf215ff 100644 --- a/internal/embed/skills/addresses/SKILL.md +++ b/internal/embed/skills/addresses/SKILL.md @@ -1,6 +1,6 @@ --- name: addresses -description: Verified contract addresses for major Ethereum protocols across mainnet and L2s. Use this instead of guessing. SKILL.md is an index — load the appropriate references/*.md file for the addresses you need. Categories include stablecoins, staking + Obol/Splits, DEXs, lending and DeFi, L2-native protocols, infrastructure (Safe, AA, Chainlink, EigenLayer, ENS, OpenSea), bridges (CCIP, Across), agents (ERC-8004), and major token addresses. Always verify on-chain via eth_getCode + eth_call before sending value. +description: Verified contract addresses for major Ethereum protocols across mainnet and L2s. Use this instead of guessing. SKILL.md is an index — load the appropriate references/*.md file for the addresses you need. Start with references/obol-payments.md for the Stack's own rails (USDC + OBOL + Permit2 + ERC-8004 on the supported chains). Other categories include stablecoins, staking + Obol/Splits, DEXs, lending and DeFi, L2-native protocols, infrastructure (Safe, AA, Chainlink, EigenLayer, ENS, OpenSea), bridges (CCIP, Across), and major token addresses. Always verify on-chain via eth_getCode + eth_call before sending value. --- # Contract Addresses @@ -19,6 +19,7 @@ Open the file that matches the category you need: | Reference | What's in it | |-----------|--------------| +| [`references/obol-payments.md`](references/obol-payments.md) | **Start here for anything payment-related** — USDC + OBOL on the chains the Stack supports, Permit2, ERC-8004 registries, facilitator | | [`references/stablecoins.md`](references/stablecoins.md) | USDC, USDT, DAI, WETH on mainnet + L2s | | [`references/staking.md`](references/staking.md) | Lido (stETH, wstETH, withdrawals), Rocket Pool, Obol Splits, Splits.org | | [`references/dex.md`](references/dex.md) | Uniswap V2/V3/V4, Universal Router, Permit2, 1inch, UNI token | diff --git a/internal/embed/skills/addresses/references/obol-payments.md b/internal/embed/skills/addresses/references/obol-payments.md new file mode 100644 index 00000000..ed4df82f --- /dev/null +++ b/internal/embed/skills/addresses/references/obol-payments.md @@ -0,0 +1,58 @@ +# Obol Stack payment rails + +The addresses the Stack's own commerce loop runs on. **Check here first** — +these are the chains and tokens `sell`, `buy-x402`, and `agent-factory` +actually support, and they are canonical in the Stack's source +(`internal/x402/tokens.go` / `chains.go`). + +**Last verified on-chain (`eth_getCode`): 2026-07-06.** + +## Payment tokens + +### USDC (6 decimals, EIP-3009 `transferWithAuthorization` — gasless x402 transfers) + +| Chain | Address | Notes | +|-------|---------|-------| +| Base | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | Primary "cheap real money" rail | +| Base Sepolia | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | Dev/testing only — label it as such | +| Ethereum mainnet | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` | | +| Polygon | `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` | | +| Arbitrum One | `0xaf88d065e77c8cC2239327C5EDb3A432268e5831` | | +| Avalanche | `0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E` | | + +(Testnets registered in the Stack: Polygon Amoy +`0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582`, Avalanche Fuji +`0x5425890298aed601595a70AB815c96711a31Bc65`, Arbitrum Sepolia +`0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d`.) + +### OBOL (18 decimals, Permit2 + EIP-2612) + +| Chain | Address | +|-------|---------| +| Ethereum mainnet | `0x0B010000b7624eb9B3DfBC279673C76E9D29D5F7` | +| Base Sepolia | `0x0a09371a8b011d5110656ceBCc70603e53FD2c78` | + +OBOL's headline property: the Obol-operated facilitator +(`https://x402.gcp.obol.tech`) batches the EIP-2612 `permit()` with the +transfer at settlement — **buyers pay zero gas** and skip the one-time +`approve(Permit2, max)` step. + +## Infrastructure + +| Contract | Address | Chains | +|----------|---------|--------| +| Permit2 | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | Same on every EVM chain (CREATE2) | +| ERC-8004 IdentityRegistry | `0x8004A169FB4a3325136EB29fA0ceB6D2e539a432` | Mainnet, Base, Arbitrum, Optimism (CREATE2) | +| ERC-8004 ReputationRegistry | `0x8004BAa17C55a88189AE136b182e5fdA19dE9b63` | Mainnet, Base (CREATE2) | +| ERC-8004 IdentityRegistry (testnets) | `0x8004A818BFB912233c491871b3d84c89A494BD9e` | Base Sepolia, Sepolia | + +## Which rail for what + +- **Selling**: quote OBOL on Ethereum mainnet (gasless buyers) and/or USDC + on Base (cheapest real-money settlement). Use Base Sepolia only for dev + smoke tests. +- **Chain names** as the Stack's tooling expects them: `ethereum` (alias + `mainnet`), `base`, `base-sepolia`, `polygon`, `arbitrum-one`, + `avalanche` — plus CAIP-2 forms (`eip155:8453` = Base). +- **Native vs bridged**: all USDC addresses above are native Circle + deployments, not bridged variants. diff --git a/internal/embed/skills/agent-factory/SKILL.md b/internal/embed/skills/agent-factory/SKILL.md index b23cec24..8fd3d268 100644 --- a/internal/embed/skills/agent-factory/SKILL.md +++ b/internal/embed/skills/agent-factory/SKILL.md @@ -1,6 +1,6 @@ --- name: agent-factory -description: "Spawn durable child Hermes agents from inside Obol Stack. Creates child namespaces, optional profile/env Secrets, Agent CRDs, and optional ServiceOffers for x402-paid child services." +description: "Spawn durable child Hermes agents from inside Obol Stack. Creates child namespaces, optional profile/env Secrets, Agent CRDs, and optional ServiceOffers for x402-paid child services. Use when the user says 'spawn an agent', 'create a sub-agent', 'child agent', or wants a separate long-lived service agent. For deciding WHAT agent to build, whether it's good enough to sell, and how to price it, load sub-agent-business first." metadata: { "openclaw": { "requires": { "bins": ["python3"] } } } --- diff --git a/internal/embed/skills/monetize-guide/SKILL.md b/internal/embed/skills/monetize-guide/SKILL.md index 14b11d56..f228e3f1 100644 --- a/internal/embed/skills/monetize-guide/SKILL.md +++ b/internal/embed/skills/monetize-guide/SKILL.md @@ -1,6 +1,6 @@ --- name: monetize-guide -description: "End-to-end guide for monetizing GPU resources or HTTP services through obol-stack. Covers pre-flight checks, model detection, pricing research, selling via x402, ERC-8004 registration, and verification. Use this skill when the user wants to monetize their machine." +description: "End-to-end guide for monetizing GPU resources or HTTP services through obol-stack. Covers pre-flight checks, model detection, pricing research, selling via x402, ERC-8004 registration, and verification. Use when the user says 'monetize my machine', 'sell my GPU', or 'expose a paid API' — i.e. selling raw inference or a plain HTTP service. For selling a specialised agent's replies (the higher-margin path), use sub-agent-business instead." metadata: { "openclaw": { "emoji": "🚀", "requires": { "bins": ["python3"] } } } --- diff --git a/internal/embed/skills/sell/SKILL.md b/internal/embed/skills/sell/SKILL.md index 07e85b6d..d55286f6 100644 --- a/internal/embed/skills/sell/SKILL.md +++ b/internal/embed/skills/sell/SKILL.md @@ -1,6 +1,6 @@ --- name: sell -description: "Sell access to services via x402 payment gating. Create ServiceOffer CRDs that automatically health-check upstreams, create payment-gated routes, and optionally pull models and register on ERC-8004. Supports inference, HTTP, and fine-tuning service types." +description: "Sell access to services via x402 payment gating. Create ServiceOffer CRDs that automatically health-check upstreams, create payment-gated routes, and optionally pull models and register on ERC-8004. Supports inference, HTTP, and fine-tuning service types. Use for ServiceOffer plumbing: listing offers, checking/waiting on reconciliation status, creating or deleting offers. For the guided end-to-end walkthrough use monetize-guide; for selling a child agent's turns use sub-agent-business + agent-factory." metadata: { "openclaw": { "emoji": "\ud83d\udcb0", "requires": { "bins": ["python3"] } } } --- diff --git a/internal/embed/skills/sub-agent-business/SKILL.md b/internal/embed/skills/sub-agent-business/SKILL.md new file mode 100644 index 00000000..caa96ac5 --- /dev/null +++ b/internal/embed/skills/sub-agent-business/SKILL.md @@ -0,0 +1,190 @@ +--- +name: sub-agent-business +description: "Build and run a paid sub-agent business: design specialised child agents whose replies are worth more than a raw model call, evaluate them honestly, price them, sell turns via x402, and iterate (or kill) based on revenue. Use when the user says 'build an agent people will pay for', 'productise my agent', 'agent business', 'what should I sell', 'is my agent good enough to charge for', or when deciding WHAT to sell and at WHAT price before reaching for agent-factory or sell." +metadata: { "openclaw": { "emoji": "📈", "requires": { "bins": ["python3"] } } } +--- + +# Sub-Agent Business + +Turn one idea into a specialised child agent that strangers pay per turn. +This skill is the business layer. The mechanics live in other skills: +`agent-factory` builds the child, `sell` publishes the offer, `discovery` +and `buy-x402` scout the market, `ethereum-networks` reads the revenue. + +## The one rule: margin justification + +A buyer pays your agent per reply. Raw LLM completions sell elsewhere for +0.0005–0.005 USDC per request. So a paid sub-agent is only a business if +its replies are **clearly better than the buyer's own model call** on the +same question. That gap must come from something the buyer cannot prompt +out of a stock model: + +| Alpha type | Example | +|------------|---------| +| Private or live data | An index you maintain from a local archive node; a feed you pay for | +| Curated, verified facts | Contract addresses checked on-chain; current protocol parameters; watchlists | +| An expensive workflow | Multi-step research that burns 50 model calls but sells as one turn | +| Access to paid tools | Your sub-agent buys from other x402 services and resells the composite | +| Hard-won judgment | A SOUL.md refined over hundreds of real questions in one niche | + +If the honest answer to *"why wouldn't the buyer just ask their own model?"* +is silence, do not list the agent. Find alpha first. + +## The loop + +``` +NICHE → SCOUT → PACK ALPHA → BUILD → EVALUATE → PRICE → SELL → MEASURE → ITERATE or KILL +``` + +Run every new agent idea through all nine steps. Skipping EVALUATE is the +most common way to ship an agent nobody buys twice. + +### 1. Niche + +One agent, one job. "Crypto assistant" is not a niche; +"liquidation-risk monitor for Aave positions on Base" is. Narrow niches +make the objective sharp, the skills list short, and the eval honest. + +### 2. Scout the market + +See who already sells nearby, and at what price: + +```bash +SKILLS="${OBOL_SKILLS_DIR:-/data/.openclaw/skills}" + +# Who is registered on-chain? +python3 "$SKILLS/discovery/scripts/discovery.py" search --chain base --limit 20 + +# What do comparable services charge? (402 response shows live pricing) +python3 "$SKILLS/buy-x402/scripts/buy.py" probe +``` + +A crowded niche at high prices is a good sign (demand exists — differentiate). +An empty niche is either an opportunity or a graveyard; assume graveyard +until you find one person who wants it. + +### 3. Pack the alpha + +The child agent's edge lives in its skills directory, not its weights: + +- Write niche reference files (verified addresses, current parameters, + playbooks) into a custom skill's `references/` folder. +- Keep the skill list **narrow** — pass only the skills the niche needs via + `--skills`. A generalist child dilutes the margin story. +- If the alpha is live data, make sure the source survives restarts + (an index the mother agent refreshes on a schedule beats a one-off dump). +- Date-stamp every fact file (`Last verified: YYYY-MM-DD`) and refresh on a + cadence. Stale alpha is negative alpha — a wrong answer a buyer paid for. + +### 4. Build + +Use `agent-factory` (load that skill for full flags): + +```bash +python3 "$SKILLS/agent-factory/scripts/factory.py" create aave-risk-monitor \ + --model qwen3.5:9b \ + --skills aave-watch,ethereum-networks,addresses \ + --objective "Monitor Aave v3 positions on Base for liquidation risk. Given an address, report health factor, at-risk collateral, and concrete de-risking steps with current numbers. Refuse questions outside Aave-on-Base risk. Always cite the block number your data came from." \ + --price 0.02 --pay-to 0xYourWallet --network base \ + --register-name "Aave Risk Monitor" +``` + +The `--objective` is the child's SOUL — spend real effort here: persona, +scope, refusal policy, output format, citation rules. One sharp paragraph +beats a page of vibes. + +### 5. Evaluate — the gate + +Before listing (and after every iteration): + +1. Write the **10 hardest questions** a paying buyer in this niche would ask. +2. Ask the child agent all 10. Save answers. +3. Answer the same 10 yourself with no niche skills — the "raw model" baseline. +4. Score each pair: does the child's answer contain something the baseline + could not know or do? + +**List only if the child clearly wins ≥ 7 of 10.** Otherwise go back to +step 3 and pack more alpha. Keep the question set in a file and re-run it +whenever you change the child — it is your regression test. + +### 6. Price + +Price the *value of the answer*, not the tokens: + +| Turn type | Range | +|-----------|-------| +| Fact lookup backed by your data | 0.001 – 0.01 USDC | +| Analysis / report turn | 0.01 – 0.10 USDC | +| Workflow that saves the buyer real money or many calls | 0.10 – 5.00 USDC | + +- Quote **OBOL on Ethereum mainnet** (buyers pay zero gas — the facilitator + sponsors it) and/or **USDC on Base** (cheap real money). Use `base-sepolia` + only for dev tests, and label it as such. +- Anchor against step 2's competitor probes. Being 2× the price is fine if + the eval gap is visible; being 10× cheaper than everyone signals junk. +- **Always confirm pricing with the user before creating or changing an + offer.** Never set prices autonomously. + +### 7. Sell + +`factory.py create` with `--price`/`--accept` already publishes the +ServiceOffer. Check it converged and the endpoint answers 402: + +```bash +python3 "$SKILLS/agent-factory/scripts/factory.py" status aave-risk-monitor +python3 "$SKILLS/sell/scripts/monetize.py" status aave-risk-monitor --namespace +``` + +Ask the **operator** (the human at the terminal) to handle the host-side +half — you cannot do these from inside the cluster: + +- Permanent public URL: `obol tunnel setup` (+ optionally `obol domain`) +- Storefront branding: `obol sell info set --display-name … --tagline … --logo-url …` +- ERC-8004 registration signing: `obol sell register` + +### 8. Measure + +Revenue is on-chain — read it, don't guess: + +```bash +# USDC earned (Base): balanceOf(payTo), 6 decimals +sh "$SKILLS/ethereum-networks/scripts/rpc.sh" --network base call \ + 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \ + "balanceOf(address)(uint256)" 0xYourWallet + +# OBOL earned (mainnet): same pattern against +# 0x0B010000b7624eb9B3DfBC279673C76E9D29D5F7 (18 decimals) +``` + +Record a weekly snapshot per offer (date, balance, delta, price). Give each +offer its own `payTo` if you want clean per-agent attribution. + +### 9. Iterate or kill + +- **Selling steadily** → refresh the alpha on a cadence, then test a price + raise (with user confirmation). Returning buyers price on trust. +- **Occasional sales** → sharpen the objective, add eval questions from real + buyer queries, improve the weakest 3 of your 10 eval answers. +- **No sales in 30 days** → kill the offer + (`factory.py delete ` removes the offer; the agent stays for reuse). + Killing fast is what lets you test many niches. The agent's skills and + references are reusable inputs to the next attempt. + +## Anti-patterns + +- Selling raw model output with a persona sticker — buyers churn after one turn. +- A dozen half-alive offers instead of one great one — curation IS the storefront. +- Skipping the eval because "it seems good" — the eval is cheaper than a refund in reputation. +- Letting reference data rot — a paid wrong answer costs more than no answer. +- Setting or changing prices without asking the user first. + +## Related skills + +| Skill | Use it for | +|-------|-----------| +| `agent-factory` | Creating/updating the child agent + offer | +| `sell` | ServiceOffer status, lifecycle, deletion | +| `discovery` | Finding registered competitor/complement agents | +| `buy-x402` | Probing competitor pricing; buying inputs your agent resells | +| `monetize-guide` | Selling raw inference or a plain HTTP API instead of an agent | +| `ethereum-networks` | Reading revenue balances | diff --git a/internal/embed/skills/swap/SKILL.md b/internal/embed/skills/swap/SKILL.md new file mode 100644 index 00000000..c55a6d37 --- /dev/null +++ b/internal/embed/skills/swap/SKILL.md @@ -0,0 +1,137 @@ +--- +name: swap +description: "Swap tokens on the chains the Obol Stack supports — USDC, WETH/ETH, and OBOL on Base and Ethereum mainnet via Uniswap V3. Use when earnings need converting (USDC → ETH for gas, consolidating USDC/OBOL revenue, rebalancing the agent treasury) or the user says 'swap', 'convert', 'sell my USDC', 'get ETH for gas'. Quote first, bound slippage, confirm with the user before sending." +metadata: { "openclaw": { "emoji": "🔁", "requires": { "bins": ["cast", "python3"] } } } +--- + +# Swap + +Convert tokens the agent actually earns and spends. The x402 rails pay you +in **USDC on Base** or **OBOL on Ethereum mainnet**; on-chain writes need +**ETH** for gas (on mainnet — Base writes cost fractions of a cent). This +skill covers the treasury moves between them using Uniswap V3, with quotes +from QuoterV2 and execution through the agent's remote-signer +(`ethereum-local-wallet` skill). + +**Iron rules — no exceptions:** + +1. **Quote before every swap.** Never send a swap without a fresh QuoterV2 + quote and an `amountOutMinimum` derived from it. +2. **Confirm with the user** before sending any swap, stating: amount in, + expected amount out, minimum out, fee tier, chain. Never swap autonomously. +3. **Never swap more than the immediate need** (e.g. gas top-ups: swap for + ~2–4 weeks of expected gas, not the whole balance). +4. Addresses below were verified on-chain (`eth_getCode`) on 2026-07-06. + Re-verify with `rpc.sh code ` if anything reverts unexpectedly. + +## Verified addresses + +| Contract | Base (8453) | Ethereum mainnet (1) | +|----------|-------------|----------------------| +| Uniswap V3 SwapRouter02 | `0x2626664c2603336E57B271c5C0b26F421741e481` | `0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45` | +| Uniswap V3 QuoterV2 | `0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a` | `0x61fFE014bA17989E743c5F6cB21bF9697530B21e` | +| USDC (6 decimals) | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` | +| WETH (18 decimals) | `0x4200000000000000000000000000000000000006` | `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` | +| OBOL (18 decimals) | — (Base-Sepolia only, no mainnet-Base deploy) | `0x0B010000b7624eb9B3DfBC279673C76E9D29D5F7` | + +Aerodrome (router `0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43`, Base) often +has deeper liquidity for long-tail Base pairs — but its ve(3,3) router ABI +differs; prefer Uniswap V3 for the pairs above and reach for Aerodrome only +when V3 quotes are bad. See `building-blocks` for Aerodrome details. + +## Recipe: USDC → ETH for gas (Base example) + +Environment (same defaults as `ethereum-local-wallet`): + +```bash +SKILLS="${OBOL_SKILLS_DIR:-/data/.openclaw/skills}" +RPC="$SKILLS/ethereum-networks/scripts/rpc.sh" +WALLET="$SKILLS/ethereum-local-wallet/scripts/signer.py" +NET=base +ROUTER=0x2626664c2603336E57B271c5C0b26F421741e481 +QUOTER=0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a +USDC=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 +WETH=0x4200000000000000000000000000000000000006 +ME=$(python3 "$WALLET" accounts | grep -o '0x[0-9a-fA-F]*' | head -1) # agent signing address +``` + +### Step 1 — Quote (read-only, free) + +QuoterV2 is called via `eth_call` even though it's not marked `view`: + +```bash +AMOUNT_IN=10000000 # 10 USDC (6 decimals) +sh "$RPC" --network $NET call $QUOTER \ + "quoteExactInputSingle((address,address,uint256,uint24,uint160))(uint256,uint160,uint32,uint256)" \ + "($USDC,$WETH,$AMOUNT_IN,500,0)" +# First return value = expected WETH out (18 decimals) +``` + +Try fee tiers `500`, `3000`, `10000` and keep the best output. A **revert +means no pool at that tier** — if all tiers revert there is no direct pool; +route through WETH in two hops or stop and tell the user. + +Sanity-check the quote against an independent price source if available. A +quote > 2% away from the expected market rate means thin liquidity — warn +the user and reduce size or abort. + +### Step 2 — Approve the router (once per token per chain) + +```bash +DATA=$(cast calldata "approve(address,uint256)" $ROUTER $AMOUNT_IN) +python3 "$WALLET" send-tx --from $ME --to $USDC --data $DATA --network $NET +``` + +Approve only the amount being swapped (not unlimited). + +### Step 3 — Swap with a slippage floor + +`amountOutMinimum` = quoted output × 0.995 (0.5% slippage; use 0.3% for +USDC/WETH majors, up to 1% for thin pairs — never 0): + +```bash +MIN_OUT= +# SwapRouter02 exactInputSingle: (tokenIn, tokenOut, fee, recipient, amountIn, amountOutMinimum, sqrtPriceLimitX96) +# NOTE: SwapRouter02 has NO deadline field (unlike the older SwapRouter). +DATA=$(cast calldata \ + "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))" \ + "($USDC,$WETH,500,$ME,$AMOUNT_IN,$MIN_OUT,0)") +python3 "$WALLET" send-tx --from $ME --to $ROUTER --data $DATA --network $NET +``` + +### Step 4 — Unwrap WETH → ETH (if the goal is gas) + +```bash +DATA=$(cast calldata "withdraw(uint256)" ) +python3 "$WALLET" send-tx --from $ME --to $WETH --data $DATA --network $NET +``` + +### Step 5 — Verify + +```bash +sh "$RPC" --network $NET balance $ME # ETH +sh "$RPC" --network $NET call $USDC "balanceOf(address)(uint256)" $ME # USDC left +``` + +## Variations + +- **OBOL ↔ ETH/USDC (mainnet):** same recipe with `NET=mainnet`, mainnet + router/quoter/token addresses. Quote all three fee tiers first — OBOL + liquidity is concentrated in few pools; **do not assume a direct + OBOL/USDC pool exists**. If direct quotes revert, two-hop via WETH: + quote `OBOL→WETH` and `WETH→USDC` separately, execute as two swaps, and + re-confirm with the user before the second hop. +- **Mainnet gas cost check:** before any mainnet swap run + `python3 "$WALLET" gas-info --network mainnet`. If the swap gas cost + exceeds ~1% of the swap value, tell the user and suggest batching later. +- **Exact output** (e.g. "get me exactly 0.01 ETH"): use + `quoteExactOutputSingle` / `exactOutputSingle` with the same struct shapes + (amountOut + amountInMaximum instead); approve `amountInMaximum`. + +## When NOT to use this skill + +- Paying for an x402 service — that's `buy-x402` (no swap needed; it signs + USDC/OBOL authorizations directly). +- Bridging between chains — this skill never bridges. USDC on Base and USDC + on mainnet are different balances; say so if the user conflates them. +- Anything the user hasn't confirmed. Every swap is user-confirmed, every time.