{"id":"042c81fb-6bd7-4643-b3f7-242d17e6d954","entityType":"agent","slug":"clawhub-almiashev-aidex","name":"Aidex","canonicalUrl":"https://www.xpersona.co/agent/clawhub-almiashev-aidex","canonicalPath":"/agent/clawhub-almiashev-aidex","generatedAt":"2026-10-11T10:51:28.261Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T06:58:03.399Z","emptyReason":null},"description":"AIDEX is a lightning-fast DEX aggregator for swapping tokens on-chain. The pipeline is optimised for minimal latency between an agent’s decision and the moment the signed transaction hits the network. The gap between intent and execution is where price moves against you, and AIDEX is built to minimise it.\n\nSearch tokens, check exchange rates, view balances, and execute swaps with low-latency on-chain execution — without giving up wallet custody or trusting a third party with your private keys","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s173b8438g4qb8w5ggfvk616kx863gp7:aidex","sourceUrl":"https://clawhub.ai/almiashev/aidex","homepage":"https://clawhub.ai/almiashev/skills/aidex","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/almiashev/aidex","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/almiashev/skills/aidex","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Aidex technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T06:58:03.399Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T06:58:03.399Z","emptyReason":null},"stars":null,"forks":null,"downloads":1129,"packageName":null,"latestVersion":"1.0.7","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T06:58:03.339Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T06:58:03.399Z","lastCrawledAt":"2026-10-11T06:58:03.339Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T06:58:03.339Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.7","createdAt":"2026-05-13T15:49:31.661Z","changelog":"Minor improvements.","fileCount":17,"zipByteSize":98516},{"version":"1.0.6","createdAt":"2026-05-13T11:36:13.037Z","changelog":"Refinements across setup and safety.","fileCount":16,"zipByteSize":97177},{"version":"1.0.5","createdAt":"2026-05-12T16:18:35.672Z","changelog":"Updated supported token list.","fileCount":16,"zipByteSize":96948},{"version":"1.0.4","createdAt":"2026-05-11T15:17:40.248Z","changelog":"Pinned ethers dependency version and minor documentation improvements.","fileCount":16,"zipByteSize":90500},{"version":"1.0.3","createdAt":"2026-05-09T19:45:49.588Z","changelog":"Minor improvements under the hood.","fileCount":16,"zipByteSize":90456},{"version":"1.0.2","createdAt":"2026-05-08T16:22:26.212Z","changelog":"Client-side transaction validation.","fileCount":15,"zipByteSize":90235},{"version":"1.0.1","createdAt":"2026-05-04T20:58:40.744Z","changelog":"Refine security model description","fileCount":13,"zipByteSize":20588},{"version":"1.0.0","createdAt":"2026-05-04T20:27:01.462Z","changelog":"Initial release","fileCount":13,"zipByteSize":20658}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s173b8438g4qb8w5ggfvk616kx863gp7:aidex","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s173b8438g4qb8w5ggfvk616kx863gp7:aidex` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/almiashev/aidex before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T10:51:28.257Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-almiashev-aidex/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T06:58:03.399Z","emptyReason":null},"readme":"Skill: Aidex\n\nOwner: almiashev\n\nSummary: AIDEX is a lightning-fast DEX aggregator for swapping tokens on-chain. The pipeline is optimised for minimal latency between an agent’s decision and the moment the signed transaction hits the network. The gap between intent and execution is where price moves against you, and AIDEX is built to minimise it.\n\nSearch tokens, check exchange rates, view balances, and execute swaps with low-latency on-chain execution — without giving up wallet custody or trusting a third party with your private keys\n\nTags: latest:1.0.7\n\nVersion history:\n\nv1.0.7 | 2026-05-13T15:49:31.661Z | user\n\nMinor improvements.\n\nv1.0.6 | 2026-05-13T11:36:13.037Z | user\n\nRefinements across setup and safety.\n\nv1.0.5 | 2026-05-12T16:18:35.672Z | user\n\nUpdated supported token list.\n\nv1.0.4 | 2026-05-11T15:17:40.248Z | user\n\nPinned ethers dependency version and minor documentation improvements.\n\nv1.0.3 | 2026-05-09T19:45:49.588Z | user\n\nMinor improvements under the hood.\n\nv1.0.2 | 2026-05-08T16:22:26.212Z | user\n\nClient-side transaction validation.\n\nv1.0.1 | 2026-05-04T20:58:40.744Z | user\n\nRefine security model description\n\nv1.0.0 | 2026-05-04T20:27:01.462Z | user\n\nInitial release\n\nArchive index:\n\nArchive v1.0.7: 17 files, 98516 bytes\n\nFiles: package.json (332b), references/scripts.md (9224b), references/security.md (5614b), scripts/account.js (276b), scripts/balance.js (955b), scripts/data/tokens.json (275405b), scripts/lib/api.js (5023b), scripts/lib/tokens.js (1507b), scripts/lib/utils.js (7724b), scripts/lib/version.js (160b), scripts/rate.js (887b), scripts/swap-status.js (951b), scripts/swap.js (13673b), scripts/tokens.js (333b), skill-card.md (2306b), SKILL.md (19968b), _meta.json (124b)\n\nFile v1.0.7:SKILL.md\n\n---\r\nname: aidex\r\ndescription: Swap tokens on Ethereum via the AIDEX aggregator. Search tokens, check exchange rates, view balances, and execute swaps. Client-side transaction signing keeps your private key on your machine.\r\nversion: 1.0.7\r\nhomepage: https://ai-dex.io/\r\nuser-invocable: true\r\nemoji: \"\\U0001F504\"\r\nmetadata: {\r\n  \"openclaw\": {\r\n    \"requires\": {\r\n      \"bins\": [\"node\"]\r\n    },\r\n    \"primaryEnv\": \"AIDEX_PRIVATE_KEY\"\r\n  }\r\n}\r\n---\r\n\r\n## Overview\r\n\r\nAIDEX is a high-performance DEX aggregator on Ethereum. This skill gives your OpenClaw agent the ability to swap tokens, check exchange rates, monitor balances, and verify transaction results.\r\n\r\nAIDEX provides tools, not decisions. You decide when and what to trade. AIDEX is your hands — fast, transparent, reliable. Every operation is a visible on-chain Ethereum transaction that you can verify on Etherscan. Nothing is hidden, nothing is obscured.\r\n\r\nAIDEX doesn't pretend to be smarter than you. It doesn't make decisions on your behalf. It does exactly what you ask — honestly, quickly, and verifiably. If you want to experiment with automated trading, AIDEX gives you the simplest, most transparent foundation to build on.\r\n\r\nYour funds stay in your wallet at all times. Unlike centralized exchange integrations where your money sits on someone else's platform, AIDEX works with decentralized liquidity pools. You remain in full control.\r\n\r\n## Source code\r\n\r\nOpen source on GitHub: [AIDEX-DeFi/skills](https://github.com/AIDEX-DeFi/skills). Issues and pull requests welcome.\r\n\r\n## Why AIDEX\r\n\r\n- **Simplicity** — Simple, clear scripts. Clear inputs, clear outputs. The agent calls them, you see the results. That's it.\r\n- **Transparency** — Every swap is a standard Ethereum transaction. You get a transaction hash. You can check it on Etherscan. What you asked for is what gets executed.\r\n- **Security** — Your private key never leaves your machine. The API only receives already-signed transactions. Even if our servers were compromised, no one could alter your transaction — it's cryptographically signed by you. See the [Security Model](#security-model) section below.\r\n- **Speed** — Lightning-fast execution layer with minimal latency. Transactions are built and sent in milliseconds.\r\n- **Best rates** — Wide liquidity pool coverage finds exchange routes that competitors miss, giving you better rates.\r\n\r\n## Dependencies\r\n\r\nThis skill requires Node.js packages listed in `package.json` in the skill's root folder:\r\n\r\n- **ethers** — Ethereum library for client-side transaction signing. This is what keeps your private key safe — transactions are signed locally, never sent to the API.\r\n- **@napi-rs/keyring** *(optional)* — Native access to the operating system's credential manager (Windows Credential Manager, macOS Keychain, Linux Secret Service). Allows storing the private key securely instead of an environment variable.\r\n\r\n**Run `npm install` in the skill's root folder after the initial install and after each skill update.** Skill updates may pin new dependency versions. The packages are installed locally into the skill's own `node_modules/` folder — this is NOT a modification to the user's system environment. It is a standard, reversible operation (the folder can be deleted at any time).\r\n\r\nIf your operational constraints prevent you from running `npm install` automatically, ask the user for permission and let them decide.\r\n\r\n**Do not report the skill as broken if dependencies are missing — install them.**\r\n\r\n## Security Model\r\n\r\n### Client-side transaction signing\r\n\r\nAll transaction signing happens locally on your machine using ethers.js. The AIDEX API **never receives, requests, or has access to your private key**.\r\n\r\nHere's what happens during a swap:\r\n\r\n1. Your agent calls the AIDEX API with swap parameters (which tokens, how much)\r\n2. The API returns a **complete unsigned transaction** (destination address, call data, gas parameters)\r\n3. The `swap.js` script signs this transaction using your private key via `ethers.Wallet.signTransaction()`\r\n4. Finally, the signed transaction is sent back to the API for fast broadcasting to the Ethereum network\r\n\r\n### What the API cannot do\r\n\r\nYour funds are protected because every transaction must be reviewed and signed directly by your wallet. AIDEX cannot modify transaction amounts, tokens, or recipients, and cannot initiate unauthorized transactions.\r\n\r\n### What AIDEX API does NOT do\r\n\r\n- Does not store private keys\r\n- Does not manage or custody your funds\r\n- Does not deduct fees from your wallet\r\n- Does not have any access to your assets beyond what you explicitly sign\r\n\r\n### Private key storage — a reasonable trade-off\r\n\r\nYour private key can be stored in the `AIDEX_PRIVATE_KEY` environment variable or in the operating system's credential manager (system keyring). Both approaches keep the key local to your machine. See the [Setup](#setup) section for configuration details.\r\n\r\nThis is a deliberate and reasonable trade-off between autonomy and security: if the agent cannot sign transactions, it cannot trade autonomously.\r\n\r\n## Setup\r\n\r\nThe AIDEX skill works out of the box for read-only operations: searching tokens, checking exchange rates, and viewing balances. No configuration needed.\r\n\r\nTo execute swaps, configure your private key using one of the options below.\r\n\r\n### What is a Private Key?\r\n\r\nA private key is 64 hexadecimal characters (`0-9`, `a-f`), optionally prefixed with `0x` — 64 or 66 characters total. It is the sole credential that authorizes transactions from your Ethereum wallet. Unlike a password, a private key cannot be reset or recovered — if it is lost or compromised, access to the wallet's funds is permanently lost or stolen.\r\n\r\nIf you don't have a wallet yet, the easiest way to get started is with [MetaMask](https://metamask.io/):\r\n\r\n1. Install the MetaMask browser extension and create a new wallet\r\n2. Open MetaMask, click the account selector at the top of the screen\r\n3. Tap the account menu (⋮) next to the account name, then select **Account details**\r\n4. Select **Private keys**, enter your MetaMask password, and copy the revealed key\r\n\r\nUse this key in one of the configuration options below.\r\n\r\n### Option A: Environment variable (via OpenClaw)\r\n\r\n**Simple — for testing only.** The private key is passed as a command-line argument and may end up in shell history, process list, and audit logs:\r\n\r\n```bash\r\nopenclaw config set skills.entries.aidex.env.AIDEX_PRIVATE_KEY \"0xYourPrivateKeyHere\"\r\n```\r\n\r\n**Secure — requires bash (on Windows use WSL).** The key is read interactively into a shell variable and piped via stdin, never appearing in argv:\r\n\r\n```bash\r\nread -rsp \"AIDEX private key: \" k; echo; printf '{\"skills\":{\"entries\":{\"aidex\":{\"env\":{\"AIDEX_PRIVATE_KEY\":\"%s\"}}}}}' \"$k\" | openclaw config patch --stdin; unset k\r\n```\r\n\r\nAfter changing the config, restart the gateway so the new value takes effect:\r\n\r\n```bash\r\nopenclaw gateway restart\r\n```\r\n\r\n### Option B: System keyring (desktop only)\r\n\r\n> **Not available in Docker, WSL, CI, or headless Linux.** The system keyring requires a desktop session. If you are running in a containerized or headless environment, use Option A above.\r\n\r\nStore your private key in the operating system's credential manager. The key is encrypted at rest and protected by your OS user account, keeping it out of configuration files and environment variable logs.\r\n\r\n**Windows** (Credential Manager):\r\n\r\n```cmd\r\ncmdkey /generic:AIDEX_PRIVATE_KEY.aidex /user:AIDEX_PRIVATE_KEY\r\n```\r\n\r\n**macOS** (Keychain):\r\n\r\n```bash\r\nsecurity add-generic-password -s aidex -a AIDEX_PRIVATE_KEY -U -w\r\n```\r\n\r\n**Linux** (Secret Service — GNOME Keyring, KWallet):\r\n\r\n```bash\r\nsecret-tool store --label=\"AIDEX Private Key\" service aidex username AIDEX_PRIVATE_KEY target default\r\n```\r\n\r\nIn all three commands above, you will be prompted to enter the private key interactively.\r\n\r\n**Headless and containerized environments (Docker, WSL, CI):**\r\n\r\nThe system keyring is not accessible from containers or headless environments — it requires a desktop session with D-Bus. In these environments, use Option A (environment variable). For production server deployments, proper firewall configuration is essential to restrict access to the machine running the agent.\r\n\r\nIf both an environment variable and a keyring entry are present, the environment variable takes priority.\r\n\r\n## Token identification\r\n\r\nIn all scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`), you can specify tokens by **address** or by **symbol**:\r\n\r\n- By address: `--token-in 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- By symbol: `--token-in USDC`\r\n\r\nIf a symbol is ambiguous (matches multiple tokens), the API will return an error listing all matches so you can specify the address instead.\r\n\r\n## Scripts\r\n\r\n> **Note:** You don't need to read this section to use AIDEX for trading. Your OpenClaw agent handles the scripts automatically. This section is for developers or anyone who wants to understand how the system works under the hood.\r\n\r\nAll scripts output JSON to stdout. Every response contains a `success` field (`true` or `false`). On failure, an `error` field explains what went wrong.\r\n\r\n### account.js — Get wallet address *(requires private key)*\r\n\r\nDerives your wallet address from the private key. Does not call the API.\r\n\r\n```bash\r\nnode {baseDir}/scripts/account.js\r\n```\r\n\r\nOutput: `{\"success\": true, \"address\": \"0x...\"}`\r\n\r\n### tokens.js — Search tokens\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n```bash\r\nnode {baseDir}/scripts/tokens.js --term USDC\r\n```\r\n\r\nWithout `--term`, returns the full token list.\r\n\r\nOutput: `{\"success\": true, \"tokens\": [{\"address\": \"0x...\", \"symbol\": \"USDC\", \"decimals\": 6, \"name\": \"USD Coin\", \"imageUrl\": \"...\"}]}`\r\n\r\n### rate.js — Check exchange rate\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything. Tokens can be specified by address or symbol.\r\n\r\n```bash\r\nnode {baseDir}/scripts/rate.js --token-in ETH --token-out USDC --amount-in 0.5\r\n```\r\n\r\nOutput: `{\"success\": true, \"rate\": \"3125.50\", \"amountOut\": \"1562.75\", \"estimatedGasPriceUsd\": 2.34}`\r\n\r\n### balance.js — Check token balances\r\n\r\nGet balances for up to 9 tokens at once. Use `ETH` or the zero address (`0x0000000000000000000000000000000000000000`) for native ETH balance. Tokens can be specified by address or symbol.\r\n\r\n> **Note:** `--address` is required, but you often don't need to ask the user for it. Run `account.js` first — if the private key is configured, it returns the wallet address. Only ask the user for their address if `account.js` returns an error (private key not configured).\r\n\r\n```bash\r\nnode {baseDir}/scripts/balance.js --address 0xYourWallet --tokens ETH,USDC\r\n```\r\n\r\nOutput: `{\"success\": true, \"balances\": [{\"address\": \"0x000...0\", \"symbol\": \"ETH\", \"balance\": \"1.5\", \"allowance\": null}, {\"address\": \"0xA0b...eB48\", \"symbol\": \"USDC\", \"balance\": \"3250.00\", \"allowance\": \"1000.0\"}]}`\r\n\r\nThe `allowance` field shows how much the AIDEX router is approved to spend on behalf of the wallet (relevant for ERC-20 tokens). For native ETH, `allowance` is `null`.\r\n\r\n### swap.js — Execute a swap *(requires private key)*\r\n\r\nBuilds a chain of transactions (approve if needed + swap) via API, signs them locally on your machine, and broadcasts them. Full cycle in one call. The API handles approve automatically — the script doesn't need to know about it. Tokens can be specified by address or symbol.\r\n\r\n```bash\r\nnode {baseDir}/scripts/swap.js --token-in ETH --token-out USDC --amount-in 0.5 --slippage 0.5 --deadline-minutes 20\r\n```\r\n\r\n- `--slippage` — Maximum acceptable slippage in percent (default: 0.5)\r\n- `--deadline-minutes` — Transaction deadline in minutes from now (default: 20)\r\n\r\nOutput: `{\"success\": true, \"transactionHashes\": [\"0x...\"], \"fromAddress\": \"0x...\", \"amountOut\": \"1562.75\", \"estimatedGasPriceUsd\": 2.34}`\r\n\r\nNote: `transactionHashes` is an array — it may contain 1-3 hashes (approve transactions + swap). Pass all of them to swap-status.js.\r\n\r\n### swap-status.js — Check swap operation status\r\n\r\nVerify the result of a swap operation (including approve steps). Accepts 1-3 transaction hashes.\r\n\r\n```bash\r\nnode {baseDir}/scripts/swap-status.js --hashes 0xApproveHash,0xSwapHash\r\n```\r\n\r\nOutput:\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"completed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\", \"amountIn\": \"0.5\", \"tokenIn\": \"ETH\", \"amountOut\": \"1562.75\", \"tokenOut\": \"USDC\"}\r\n  ]\r\n}\r\n```\r\n\r\nHigh-level status: `pending` (waiting for confirmation), `completed` (all steps confirmed), `failed` (a step reverted).\r\n\r\n## Workflow Patterns\r\n\r\n### Check exchange rate\r\n\r\n```\r\n1. rate.js --token-in ETH --token-out USDC --amount-in 1\r\n```\r\n\r\n### Execute a swap\r\n\r\n```\r\n1. account.js                                              → get wallet address\r\n2. rate.js --token-in ETH --token-out USDC --amount-in 0.5 → show rate and gas cost to user\r\n3. [Ask user for confirmation]\r\n4. balance.js --address <wallet> --tokens ETH,USDC          → show balances and allowance\r\n5. swap.js --token-in ETH --token-out USDC --amount-in 0.5  → execute (approve + swap if needed)\r\n6. swap-status.js --hashes <hash1>,<hash2>                  → verify result\r\n7. balance.js --address <wallet> --tokens ETH,USDC          → show balances after\r\n```\r\n\r\n### Price monitoring with auto-swap (via OpenClaw cron/heartbeat)\r\n\r\n```\r\n1. rate.js --token-in ETH --token-out USDC --amount-in 0.5  → check current rate\r\n2. If target rate reached:\r\n   a. swap.js --token-in ETH --token-out USDC --amount-in 0.5  → execute swap\r\n   b. swap-status.js --hashes <hashes>                          → verify result\r\n   c. balance.js ...                                            → show final balances\r\n3. If not reached: wait for next cron tick\r\n```\r\n\r\nWhen using cron-based monitoring and the API returns a temporary error (\"AIDEX is temporarily unavailable\" or network error), simply skip this iteration and retry on the next tick. Do not treat temporary errors as final failures.\r\n\r\n## Agent Rules\r\n\r\n1. **Always show rate and gas cost** before executing a swap. The user must see what they're getting.\r\n2. **Ask for explicit confirmation** before executing a swap — unless the user explicitly set up automatic execution (e.g., \"swap every time the price drops below 2800\"). Confirmation can be one-time or for a series, but the agent never invents retries on its own.\r\n3. **Display amounts in human-readable format** (e.g., \"0.5 ETH\", \"1,562.75 USDC\"), not raw BigInt values.\r\n4. **Always show transaction hashes** after a swap so the user can track them on Etherscan.\r\n5. **Handle error responses gracefully**:\r\n   - `Route not found` — Let the user know AIDEX could not find a route for this pair, and suggest trying a different pair or amount.\r\n   - `AIDEX is temporarily unavailable` — Let the user know AIDEX is not available right now and suggest trying again in a few minutes.\r\n   - The error says the skill is outdated (e.g., `Skill ... is outdated` or `Outdated skill version`) — Ask the user to run `openclaw skills update aidex` in their terminal.\r\n   - `Request rejected` — Most likely the request was formed incorrectly — re-check the arguments. If they look correct, ask the user to update the skill: `openclaw skills update aidex`.\r\n   - Network errors — Same as above, suggest retrying later.\r\n   - Invalid token — Suggest searching for the token by name or symbol.\r\n6. **After a swap, always call swap-status.js** to verify the actual result and show it to the user.\r\n7. **Private key not configured?** If no private key is available, present **all** configuration options: environment variable (via `openclaw config set`) **and** system keyring. Do not default to a single option — let the user choose.\r\n8. **NEVER loop or auto-retry on errors.** If any transaction reverts or the API returns an error, stop the current operation and report to the user. Do not automatically retry. If the user wants to try again, they will say so.\r\n9. **NEVER access the private key directly.** Do not read openclaw.json, .env files, or any other configuration files to extract the private key. Do not pass the private key as a command-line argument — command-line arguments are visible to all processes on the system. Passing the key this way is equivalent to leaking it to an attacker. The key is resolved from the AIDEX_PRIVATE_KEY environment variable or the system keyring. If neither source provides a valid key, inform the user and stop. No workarounds.\r\n10. **While a transaction is mining**, you can show the user a link to track it: `https://etherscan.io/tx/{transactionHash}`. This applies to all transactions (swap, approve).\r\n11. **Detect the user's environment.** When helping with private key setup, adapt your suggestions to the user's environment. If the user is running in a containerized or headless Linux environment (Docker, WSL, CI), lead with the environment variable approach (Option A) — do not mention the system keyring unless the user explicitly asks about alternatives. If asked, explain that the system keyring is available for desktop operating systems (Windows, macOS, Linux with a graphical session) but is not accessible from containers or headless environments. For desktop users, present all keyring options but highlight the one matching their OS first.\r\n12. **Never ask the user about private key configuration proactively.** Do not ask \"is your private key configured?\" or offer to help with setup when the user first interacts with the skill. The user may not even know what a private key is. Simply run the requested operation — if the key is needed and not configured, the script will return a clear error, and only then should you explain what happened and how to set it up. For read-only operations (rate, tokens, balances), the key is not needed at all — do not mention it.\r\n13. **Do not assume the private key is missing — check by running the script.** When the user asks for their balance, wallet address, or any operation that may require a private key, do not refuse preemptively. Run `account.js` — if the key is configured, you'll get the wallet address. If not, the script will return a clear error explaining what to set up. This is a read-only operation with no cost and no risk. Never tell the user \"I can't do this\" without actually trying first.\r\n14. **When asking for a wallet address, warn the user not to confuse it with a private key.** Both start with `0x`, but an address is 42 characters and is safe to share, while a private key is 66 characters and must be kept secret. If the user provides a 66-character string where an address is expected, **do not use it** — warn them immediately that this looks like a private key and should never be shared. Example: \"Your wallet address (42 characters, starts with 0x — this is **not** your private key, which is longer and must be kept secret).\"\r\n15. **Never modify the skill's source code.** The scripts in `{baseDir}/scripts/` and `package.json` are canonical — do not edit, patch, or \"fix\" them under any circumstances, even temporarily. If a script returns an unexpected error and you suspect a bug in the skill, you are almost certainly wrong: re-check your own inputs and call sequence carefully, read the script specifications in this SKILL.md word-for-word, and use the exact command names and argument names documented there — never invent your own syntax.\r\n\r\n## Key Constants\r\n\r\n- Native ETH address: `0x0000000000000000000000000000000000000000`\r\n- WETH address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`\r\n- Network: Ethereum mainnet (chainId: 1)\r\n- Common tokens: ETH (18 decimals), USDC (6), USDT (6), DAI (18), WBTC (8)\n\nFile v1.0.7:_meta.json\n\n{\n  \"ownerId\": \"kn75vpgckjav1ae1dw275517y9863f78\",\n  \"slug\": \"aidex\",\n  \"version\": \"1.0.7\",\n  \"publishedAt\": 1778687371661\n}\n\nFile v1.0.7:references/scripts.md\n\n# AIDEX Scripts Reference\r\n\r\nDetailed reference for all AIDEX skill scripts. Load this when you need to understand exact arguments, output formats, or error handling for a specific script.\r\n\r\nAll scripts are located in `{baseDir}/scripts/` and invoked via `node`. Every script outputs a single JSON line to stdout and exits. The JSON always contains a `success` field (`true` or `false`). On failure, an `error` field provides a human-readable explanation.\r\n\r\n## Token identification\r\n\r\nAll scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`) support two formats:\r\n\r\n- **By address**: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- **By symbol**: `USDC`\r\n\r\nIf a symbol matches zero tokens, the error will be: `\"Token not found: 'XYZ'. Use /api/v1/agent/tokens to search for available tokens.\"`\r\n\r\nIf a symbol matches multiple tokens (ambiguous), the error will list all matches with their addresses so you can specify the exact one.\r\n\r\nUse `ETH` or `0x0000000000000000000000000000000000000000` for native Ether.\r\n\r\n---\r\n\r\n## Common API errors\r\n\r\nThese can come from any script that calls the AIDEX API. Per-script tables below list only script-specific errors.\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Skill version ... is outdated...\"` | Skill is outdated — run `openclaw skills update aidex` |\r\n| `\"Request rejected...\"` | Server rejected the request — re-check arguments |\r\n\r\n---\r\n\r\n## account.js\r\n\r\nDerives the wallet address from the configured private key. Does not call the API.\r\n\r\n### Arguments\r\n\r\nNone.\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output\r\n\r\n```json\r\n{\"success\": true, \"address\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18\"}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n\r\n---\r\n\r\n## tokens.js\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--term <query>` | No | Search query (substring match, case-insensitive). If omitted, returns all tokens. |\r\n\r\n### Output\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"tokens\": [\r\n    {\r\n      \"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\r\n      \"symbol\": \"USDC\",\r\n      \"decimals\": 6,\r\n      \"name\": \"USD Coin\",\r\n      \"imageUrl\": \"https://...\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nAn empty `tokens` array means no matches were found.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"API request failed: ...\"` | Network or server error |\r\n\r\n---\r\n\r\n## rate.js\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--token-in <token>` | Yes | Token to sell (address or symbol) |\r\n| `--token-out <token>` | Yes | Token to buy (address or symbol) |\r\n| `--amount-in <number>` | Yes | Amount to sell, human-readable (e.g., `0.5`) |\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"rate\": \"3125.50\",\r\n  \"amountOut\": \"1562.75\",\r\n  \"estimatedGasPriceUsd\": 2.34\r\n}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --token-in.\"` | Missing argument |\r\n| `\"Token not found.\"` | Unknown token symbol |\r\n| `\"Route not found.\"` | No exchange route for this pair/amount |\r\n| `\"AIDEX is temporarily unavailable. Please try again later.\"` | Internal service down — retry later |\r\n\r\n---\r\n\r\n## balance.js\r\n\r\nGet token balances and allowances for a wallet address. Maximum 9 tokens per request. The `allowance` field shows how much the AIDEX router is approved to spend on behalf of the wallet (relevant for ERC-20 tokens). For native ETH, `allowance` is `null`.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--address <wallet>` | Yes | Wallet address (0x...) |\r\n| `--tokens <list>` | Yes | Comma-separated tokens (address or symbol). Use `ETH` for native Ether. Max 9. |\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"balances\": [\r\n    {\"address\": \"0x0000000000000000000000000000000000000000\", \"symbol\": \"ETH\", \"balance\": \"1.5\", \"allowance\": null},\r\n    {\"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", \"symbol\": \"USDC\", \"balance\": \"3250.00\", \"allowance\": \"1000.0\"}\r\n  ]\r\n}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --address.\"` | Missing argument |\r\n| `\"Missing required argument: --tokens.\"` | Missing argument |\r\n| `\"Too many tokens. Maximum is 9 per request.\"` | Exceeded limit |\r\n| `\"Token not found.\"` | Unknown token symbol |\r\n\r\n---\r\n\r\n## swap.js\r\n\r\nExecutes a full swap cycle. The API builds a chain of transactions (approve + swap if needed), the script signs them locally and sends them. Approve is handled automatically — the script doesn't need to know about it.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Default | Description |\r\n|----------|----------|---------|-------------|\r\n| `--token-in <token>` | Yes | — | Token to sell (address or symbol) |\r\n| `--token-out <token>` | Yes | — | Token to buy (address or symbol) |\r\n| `--amount-in <number>` | Yes | — | Amount to sell, human-readable |\r\n| `--slippage <percent>` | No | `0.5` | Maximum acceptable slippage (e.g., `0.5` = 0.5%) |\r\n| `--deadline-minutes <min>` | No | `20` | Transaction deadline in minutes from now |\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"transactionHashes\": [\"0xApproveHash...\", \"0xSwapHash...\"],\r\n  \"fromAddress\": \"0x742d35Cc...\",\r\n  \"amountOut\": \"1562.75\",\r\n  \"estimatedGasPriceUsd\": 2.34\r\n}\r\n```\r\n\r\n`transactionHashes` is an array (1-3 hashes). Pass all of them to swap-status.js to check the result.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --token-in.\"` | Missing argument |\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n| `\"Route not found.\"` | No exchange route — suggest different pair or amount |\r\n| `\"AIDEX is temporarily unavailable. Please try again later.\"` | Internal service down — retry later |\r\n| `\"Insufficient balance\"` | Not enough tokens to execute the swap |\r\n| `\"Failed to sign transaction: ...\"` | ethers.js signing error |\r\n\r\n### Important behavior\r\n\r\n- If the API returns a non-success result, the script does **not** attempt to sign or send anything. It returns the error and exits.\r\n- The private key is used only for `ethers.Wallet.signTransaction()` and never leaves the process.\r\n- If the node rejects a transaction, the script stops and exits with `success: false`. `failedAtStep` is the zero-based index (into the transaction chain returned by createSwap) of the transaction the node rejected — use it to report to the user which step could not be sent. `transactionHashes` contains the hashes of transactions that were accepted by the node before the failure.\r\n\r\n---\r\n\r\n## swap-status.js\r\n\r\nCheck the status of a swap operation (including approve steps). Accepts 1-3 transaction hashes.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--hashes <list>` | Yes | Comma-separated transaction hashes (1-3). Pass the hashes returned by swap.js. |\r\n\r\n### Output\r\n\r\n**Completed (all steps confirmed):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"completed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\", \"amountIn\": \"0.5\", \"tokenIn\": \"ETH\", \"amountOut\": \"1562.75\", \"tokenOut\": \"USDC\"}\r\n  ]\r\n}\r\n```\r\n\r\n**Pending (waiting for confirmation):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"pending\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"pending\", \"transactionHash\": \"0x...\"}\r\n  ]\r\n}\r\n```\r\n\r\n**Failed (a step reverted):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"failed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"reverted\", \"transactionHash\": \"0x...\"}\r\n  ]\r\n}\r\n```\r\n\r\nHigh-level status: `pending` (waiting), `completed` (all confirmed), `failed` (a step reverted).\r\n\r\nStep-level status: `pending`, `confirmed`, `reverted`.\r\n\r\n`amountIn`, `tokenIn`, `amountOut`, `tokenOut` are only present for the swap step, not for approve steps.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --hashes.\"` | Missing argument |\r\n| `\"Expected 1 to 3 transaction hashes, comma-separated.\"` | Wrong number of hashes |\r\n| `\"Invalid hash: ...\"` | Malformed transaction hash |\r\n| `\"API request failed: ...\"` | Network or server error |\n\nFile v1.0.7:references/security.md\n\n# AIDEX Security Model\r\n\r\n## Architecture\r\n\r\nThe AIDEX skill uses a client-side signing architecture. This document explains how it works and why it's secure.\r\n\r\n## How a swap works step by step\r\n\r\n1. **Agent requests swap parameters** — The `swap.js` script sends a POST request to the AIDEX API with high-level swap parameters: which token to sell, which token to buy, and how much. The API does NOT receive the private key.\r\n\r\n2. **API builds the transaction** — The AIDEX API finds the best exchange route, computes the exact transaction data (contract address, call data, gas parameters, nonce), and returns it as a complete unsigned transaction object.\r\n\r\n3. **Local signing** — The `swap.js` script uses `ethers.Wallet.signTransaction()` to sign the transaction locally. The private key **never** leaves your machine. Transaction signing happens entirely on your side.\r\n\r\n4. **Broadcasting** — The signed raw transaction (a hex string) is sent to the AIDEX API, which broadcasts it to the Ethereum network via `eth_sendRawTransaction`. This is equivalent to what any public RPC endpoint does.\r\n\r\n## What makes this secure\r\n\r\n### The private key never leaves the machine\r\n\r\nThe key is resolved locally from one of two sources: the `AIDEX_PRIVATE_KEY` environment variable or the operating system's credential manager (via `@napi-rs/keyring`). In both cases, the key is used exclusively by the local ethers.js `Wallet` instance to produce a cryptographic signature. No API call, at any point, includes the private key.\r\n\r\n### Signed transactions are tamper-proof\r\n\r\nAn Ethereum transaction, once signed, is cryptographically bound to its parameters. If anyone modifies any field — the recipient address, the amount, the call data, the gas price — the signature becomes invalid and the transaction is rejected by the network.\r\n\r\nThis means:\r\n- The AIDEX API cannot change what you signed\r\n- A man-in-the-middle cannot alter the transaction\r\n- Even a fully compromised AIDEX server can only broadcast exactly what you signed, or refuse to broadcast it\r\n\r\n### The API is a public RPC relay\r\n\r\nThe `POST /api/v1/agent/swap/send` endpoint is functionally equivalent to calling `eth_sendRawTransaction` on any public Ethereum RPC. It receives a signed transaction and submits it to the network. It has no special privileges and cannot modify the transaction in any way.\r\n\r\n### All read operations are unauthenticated\r\n\r\nToken searches, rate checks, balance queries, and transaction receipts are all read-only operations that use publicly available blockchain data. They do not require a private key and do not expose any sensitive information.\r\n\r\n## Risk assessment\r\n\r\n### What can go wrong\r\n\r\n| Risk | Likelihood | Impact | Mitigation |\r\n|------|-----------|--------|------------|\r\n| AIDEX API compromised | Low | None — attacker can only see/broadcast signed txs they cannot alter | Client-side signing architecture |\r\n| OpenClaw host compromised (env) | Low-Medium | High — attacker gets the private key from process environment | Use a dedicated wallet with limited funds |\r\n| OpenClaw host compromised (keyring) | Low-Medium | High — attacker may access the keyring if logged in as the same OS user | Use a dedicated wallet with limited funds; OS-level access controls |\r\n| Network eavesdropping | Low | None — signed txs are public anyway once broadcast | Standard HTTPS encryption |\r\n| Malicious transaction data from API | Very Low | Medium — user signs a bad transaction | Slippage protection, deadline, user review of rates before swap |\r\n\r\n### Recommended practices\r\n\r\n1. **Use a dedicated trading wallet** — Create a new wallet specifically for automated trading.\r\n2. **Start small** — Begin with small amounts to verify everything works as expected.\r\n3. **Review rates before swaps** — The agent should always show you the exchange rate and gas cost before executing.\r\n4. **Set reasonable slippage** — The default 0.5% slippage protects against price movements. Adjust based on token volatility.\r\n5. **Monitor transaction results** — After each swap, check the receipt to confirm actual amounts.\r\n\r\n## Comparison with alternatives\r\n\r\n### vs. Custodial (CEX) integrations\r\nIn custodial integrations, you deposit funds to the platform. The platform holds your money and you trust them not to lose it, get hacked, or freeze your account. AIDEX never touches your funds — they stay in your wallet.\r\n\r\n### vs. Server-side signing\r\nSome integrations ask you to provide your private key to a server that signs transactions on your behalf. This is a significantly higher risk profile. With AIDEX, signing happens on your machine, and the key is never transmitted over the network.\r\n\r\n## Note on `primaryEnv` in SKILL.md metadata\r\n\r\nThe SKILL.md declares `\"primaryEnv\": \"AIDEX_PRIVATE_KEY\"`. This is a workaround for a limitation in OpenClaw's current architecture: OpenClaw does not provide a mechanism for optional sensitive environment variables. Without `primaryEnv` (or `requires.env`, which would make the variable mandatory and block the entire skill), the `AIDEX_PRIVATE_KEY` variable is rejected by OpenClaw's env sanitizer (pattern `_PRIVATE_KEY`).\r\n\r\nUsing `primaryEnv` maps the variable to OpenClaw's `apiKey` config field. Despite this naming, the AIDEX API is fully public and does not require authentication. The private key is used exclusively for client-side transaction signing and is never sent to the API. The `primaryEnv` field exists solely to allow the private key through the sanitizer while keeping it optional (read-only operations work without it).\n\nFile v1.0.7:skill-card.md\n\n## Description:\n\nSwap tokens on Ethereum via the AIDEX aggregator; agents can search tokens, check exchange rates, view balances, and execute swaps while transaction signing remains local.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[almiashev](https://clawhub.ai/user/almiashev)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers use Aidex to let an OpenClaw agent search Ethereum tokens, quote swaps, inspect wallet balances, execute signed swaps, and check transaction status. Swap execution requires a locally configured wallet private key.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: A high-value private key could be exposed if the agent host or its environment is compromised.\n\nMitigation: Use a dedicated wallet with limited funds and avoid configuring a wallet that controls high-value assets.\n\nRisk: API-controlled swap terms could result in a bad trade or unexpectedly high gas fees.\n\nMitigation: Verify the final swap terms, exchange rate, slippage, and fees independently before execution.\n\nRisk: Token approvals may grant the router spending authority beyond the immediate swap.\n\nMitigation: Review allowances before and after swaps, and revoke unneeded approvals when appropriate.\n\n## Reference(s):\n\n- [ClawHub Aidex Skill Page](https://clawhub.ai/almiashev/skills/aidex)\n- [AIDEX Homepage](https://ai-dex.io/)\n- [AIDEX Scripts Reference](artifact/references/scripts.md)\n- [AIDEX Security Model](artifact/references/security.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, JSON, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with JSON results from Node.js command-line scripts]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only operations return token, rate, balance, or status data; swap operations can produce signed Ethereum transaction hashes.]\n\n## Skill Version(s):\n\n1.0.7 (source: SKILL.md frontmatter, package.json, and server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.0.7:package.json\n\n{\r\n  \"name\": \"openclaw-aidex\",\r\n  \"version\": \"1.0.7\",\r\n  \"description\": \"OpenClaw skill for AIDEX aggregator on Ethereum\",\r\n  \"private\": true,\r\n  \"type\": \"module\",\r\n  \"engines\": {\r\n    \"node\": \">=18.0.0\"\r\n  },\r\n  \"dependencies\": {\r\n    \"ethers\": \"6.16.0\"\r\n  },\r\n  \"optionalDependencies\": {\r\n    \"@napi-rs/keyring\": \"1.2.0\"\r\n  }\r\n}\n\nArchive v1.0.6: 16 files, 97177 bytes\n\nFiles: package.json (332b), references/scripts.md (9224b), references/security.md (5614b), scripts/account.js (276b), scripts/balance.js (955b), scripts/data/tokens.json (275405b), scripts/lib/api.js (5023b), scripts/lib/tokens.js (1507b), scripts/lib/utils.js (7708b), scripts/lib/version.js (160b), scripts/rate.js (887b), scripts/swap-status.js (951b), scripts/swap.js (13673b), scripts/tokens.js (333b), SKILL.md (19845b), _meta.json (124b)\n\nFile v1.0.6:SKILL.md\n\n---\r\nname: aidex\r\ndescription: Swap tokens on Ethereum via the AIDEX aggregator. Search tokens, check exchange rates, view balances, and execute swaps. Client-side transaction signing keeps your private key on your machine.\r\nversion: 1.0.6\r\nhomepage: https://ai-dex.io/\r\nuser-invocable: true\r\nemoji: \"\\U0001F504\"\r\nmetadata: {\r\n  \"openclaw\": {\r\n    \"requires\": {\r\n      \"bins\": [\"node\"]\r\n    },\r\n    \"primaryEnv\": \"AIDEX_PRIVATE_KEY\"\r\n  }\r\n}\r\n---\r\n\r\n## Overview\r\n\r\nAIDEX is a high-performance DEX aggregator on Ethereum. This skill gives your OpenClaw agent the ability to swap tokens, check exchange rates, monitor balances, and verify transaction results.\r\n\r\nAIDEX provides tools, not decisions. You decide when and what to trade. AIDEX is your hands — fast, transparent, reliable. Every operation is a visible on-chain Ethereum transaction that you can verify on Etherscan. Nothing is hidden, nothing is obscured.\r\n\r\nAIDEX doesn't pretend to be smarter than you. It doesn't make decisions on your behalf. It does exactly what you ask — honestly, quickly, and verifiably. If you want to experiment with automated trading, AIDEX gives you the simplest, most transparent foundation to build on.\r\n\r\nYour funds stay in your wallet at all times. Unlike centralized exchange integrations where your money sits on someone else's platform, AIDEX works with decentralized liquidity pools. You remain in full control.\r\n\r\n## Source code\r\n\r\nOpen source on GitHub: [AIDEX-DeFi/skills](https://github.com/AIDEX-DeFi/skills). Issues and pull requests welcome.\r\n\r\n## Why AIDEX\r\n\r\n- **Simplicity** — Simple, clear scripts. Clear inputs, clear outputs. The agent calls them, you see the results. That's it.\r\n- **Transparency** — Every swap is a standard Ethereum transaction. You get a transaction hash. You can check it on Etherscan. What you asked for is what gets executed.\r\n- **Security** — Your private key never leaves your machine. The API only receives already-signed transactions. Even if our servers were compromised, no one could alter your transaction — it's cryptographically signed by you. See the [Security Model](#security-model) section below.\r\n- **Speed** — Lightning-fast execution layer with minimal latency. Transactions are built and sent in milliseconds.\r\n- **Best rates** — Wide liquidity pool coverage finds exchange routes that competitors miss, giving you better rates.\r\n\r\n## Dependencies\r\n\r\nThis skill requires Node.js packages listed in `package.json` in the skill's root folder:\r\n\r\n- **ethers** — Ethereum library for client-side transaction signing. This is what keeps your private key safe — transactions are signed locally, never sent to the API.\r\n- **@napi-rs/keyring** *(optional)* — Native access to the operating system's credential manager (Windows Credential Manager, macOS Keychain, Linux Secret Service). Allows storing the private key securely instead of an environment variable.\r\n\r\n**Run `npm install` in the skill's root folder after the initial install and after each skill update.** Skill updates may pin new dependency versions. The packages are installed locally into the skill's own `node_modules/` folder — this is NOT a modification to the user's system environment. It is a standard, reversible operation (the folder can be deleted at any time).\r\n\r\nIf your operational constraints prevent you from running `npm install` automatically, ask the user for permission and let them decide.\r\n\r\n**Do not report the skill as broken if dependencies are missing — install them.**\r\n\r\n## Security Model\r\n\r\n### Client-side transaction signing\r\n\r\nAll transaction signing happens locally on your machine using ethers.js. The AIDEX API **never receives, requests, or has access to your private key**.\r\n\r\nHere's what happens during a swap:\r\n\r\n1. Your agent calls the AIDEX API with swap parameters (which tokens, how much)\r\n2. The API returns a **complete unsigned transaction** (destination address, call data, gas parameters)\r\n3. The `swap.js` script signs this transaction using your private key via `ethers.Wallet.signTransaction()`\r\n4. Finally, the signed transaction is sent back to the API for fast broadcasting to the Ethereum network\r\n\r\n### What the API cannot do\r\n\r\nYour funds are protected because every transaction must be reviewed and signed directly by your wallet. AIDEX cannot modify transaction amounts, tokens, or recipients, and cannot initiate unauthorized transactions.\r\n\r\n### What AIDEX API does NOT do\r\n\r\n- Does not store private keys\r\n- Does not manage or custody your funds\r\n- Does not deduct fees from your wallet\r\n- Does not have any access to your assets beyond what you explicitly sign\r\n\r\n### Private key storage — a reasonable trade-off\r\n\r\nYour private key can be stored in the `AIDEX_PRIVATE_KEY` environment variable or in the operating system's credential manager (system keyring). Both approaches keep the key local to your machine. See the [Setup](#setup) section for configuration details.\r\n\r\nThis is a deliberate and reasonable trade-off between autonomy and security: if the agent cannot sign transactions, it cannot trade autonomously.\r\n\r\n## Setup\r\n\r\nThe AIDEX skill works out of the box for read-only operations: searching tokens, checking exchange rates, and viewing balances. No configuration needed.\r\n\r\nTo execute swaps, configure your private key using one of the options below.\r\n\r\n### What is a Private Key?\r\n\r\nA private key is 64 hexadecimal characters (`0-9`, `a-f`), optionally prefixed with `0x` — 64 or 66 characters total. It is the sole credential that authorizes transactions from your Ethereum wallet. Unlike a password, a private key cannot be reset or recovered — if it is lost or compromised, access to the wallet's funds is permanently lost or stolen.\r\n\r\nIf you don't have a wallet yet, the easiest way to get started is with [MetaMask](https://metamask.io/):\r\n\r\n1. Install the MetaMask browser extension and create a new wallet\r\n2. Open MetaMask, click the account selector at the top of the screen\r\n3. Tap the account menu (⋮) next to the account name, then select **Account details**\r\n4. Select **Private keys**, enter your MetaMask password, and copy the revealed key\r\n\r\nUse this key in one of the configuration options below.\r\n\r\n### Option A: Environment variable (via OpenClaw)\r\n\r\n**Simple — for testing only.** The private key is passed as a command-line argument and may end up in shell history, process list, and audit logs:\r\n\r\n```bash\r\nopenclaw config set skills.entries.aidex.env.AIDEX_PRIVATE_KEY \"0xYourPrivateKeyHere\"\r\n```\r\n\r\n**Secure — requires bash (on Windows use WSL).** The key is read interactively into a shell variable and piped via stdin, never appearing in argv:\r\n\r\n```bash\r\nread -rsp \"AIDEX private key: \" k; echo; printf '{\"skills\":{\"entries\":{\"aidex\":{\"env\":{\"AIDEX_PRIVATE_KEY\":\"%s\"}}}}}' \"$k\" | openclaw config patch --stdin; unset k\r\n```\r\n\r\n### Option B: System keyring (desktop only)\r\n\r\n> **Not available in Docker, WSL, CI, or headless Linux.** The system keyring requires a desktop session. If you are running in a containerized or headless environment, use Option A above.\r\n\r\nStore your private key in the operating system's credential manager. The key is encrypted at rest and protected by your OS user account, keeping it out of configuration files and environment variable logs.\r\n\r\n**Windows** (Credential Manager):\r\n\r\n```cmd\r\ncmdkey /generic:AIDEX_PRIVATE_KEY.aidex /user:AIDEX_PRIVATE_KEY\r\n```\r\n\r\n**macOS** (Keychain):\r\n\r\n```bash\r\nsecurity add-generic-password -s aidex -a AIDEX_PRIVATE_KEY -U -w\r\n```\r\n\r\n**Linux** (Secret Service — GNOME Keyring, KWallet):\r\n\r\n```bash\r\nsecret-tool store --label=\"AIDEX Private Key\" service aidex username AIDEX_PRIVATE_KEY target default\r\n```\r\n\r\nIn all three commands above, you will be prompted to enter the private key interactively.\r\n\r\n**Headless and containerized environments (Docker, WSL, CI):**\r\n\r\nThe system keyring is not accessible from containers or headless environments — it requires a desktop session with D-Bus. In these environments, use Option A (environment variable). For production server deployments, proper firewall configuration is essential to restrict access to the machine running the agent.\r\n\r\nIf both an environment variable and a keyring entry are present, the environment variable takes priority.\r\n\r\n## Token identification\r\n\r\nIn all scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`), you can specify tokens by **address** or by **symbol**:\r\n\r\n- By address: `--token-in 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- By symbol: `--token-in USDC`\r\n\r\nIf a symbol is ambiguous (matches multiple tokens), the API will return an error listing all matches so you can specify the address instead.\r\n\r\n## Scripts\r\n\r\n> **Note:** You don't need to read this section to use AIDEX for trading. Your OpenClaw agent handles the scripts automatically. This section is for developers or anyone who wants to understand how the system works under the hood.\r\n\r\nAll scripts output JSON to stdout. Every response contains a `success` field (`true` or `false`). On failure, an `error` field explains what went wrong.\r\n\r\n### account.js — Get wallet address *(requires private key)*\r\n\r\nDerives your wallet address from the private key. Does not call the API.\r\n\r\n```bash\r\nnode {baseDir}/scripts/account.js\r\n```\r\n\r\nOutput: `{\"success\": true, \"address\": \"0x...\"}`\r\n\r\n### tokens.js — Search tokens\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n```bash\r\nnode {baseDir}/scripts/tokens.js --term USDC\r\n```\r\n\r\nWithout `--term`, returns the full token list.\r\n\r\nOutput: `{\"success\": true, \"tokens\": [{\"address\": \"0x...\", \"symbol\": \"USDC\", \"decimals\": 6, \"name\": \"USD Coin\", \"imageUrl\": \"...\"}]}`\r\n\r\n### rate.js — Check exchange rate\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything. Tokens can be specified by address or symbol.\r\n\r\n```bash\r\nnode {baseDir}/scripts/rate.js --token-in ETH --token-out USDC --amount-in 0.5\r\n```\r\n\r\nOutput: `{\"success\": true, \"rate\": \"3125.50\", \"amountOut\": \"1562.75\", \"estimatedGasPriceUsd\": 2.34}`\r\n\r\n### balance.js — Check token balances\r\n\r\nGet balances for up to 9 tokens at once. Use `ETH` or the zero address (`0x0000000000000000000000000000000000000000`) for native ETH balance. Tokens can be specified by address or symbol.\r\n\r\n> **Note:** `--address` is required, but you often don't need to ask the user for it. Run `account.js` first — if the private key is configured, it returns the wallet address. Only ask the user for their address if `account.js` returns an error (private key not configured).\r\n\r\n```bash\r\nnode {baseDir}/scripts/balance.js --address 0xYourWallet --tokens ETH,USDC\r\n```\r\n\r\nOutput: `{\"success\": true, \"balances\": [{\"address\": \"0x000...0\", \"symbol\": \"ETH\", \"balance\": \"1.5\", \"allowance\": null}, {\"address\": \"0xA0b...eB48\", \"symbol\": \"USDC\", \"balance\": \"3250.00\", \"allowance\": \"1000.0\"}]}`\r\n\r\nThe `allowance` field shows how much the AIDEX router is approved to spend on behalf of the wallet (relevant for ERC-20 tokens). For native ETH, `allowance` is `null`.\r\n\r\n### swap.js — Execute a swap *(requires private key)*\r\n\r\nBuilds a chain of transactions (approve if needed + swap) via API, signs them locally on your machine, and broadcasts them. Full cycle in one call. The API handles approve automatically — the script doesn't need to know about it. Tokens can be specified by address or symbol.\r\n\r\n```bash\r\nnode {baseDir}/scripts/swap.js --token-in ETH --token-out USDC --amount-in 0.5 --slippage 0.5 --deadline-minutes 20\r\n```\r\n\r\n- `--slippage` — Maximum acceptable slippage in percent (default: 0.5)\r\n- `--deadline-minutes` — Transaction deadline in minutes from now (default: 20)\r\n\r\nOutput: `{\"success\": true, \"transactionHashes\": [\"0x...\"], \"fromAddress\": \"0x...\", \"amountOut\": \"1562.75\", \"estimatedGasPriceUsd\": 2.34}`\r\n\r\nNote: `transactionHashes` is an array — it may contain 1-3 hashes (approve transactions + swap). Pass all of them to swap-status.js.\r\n\r\n### swap-status.js — Check swap operation status\r\n\r\nVerify the result of a swap operation (including approve steps). Accepts 1-3 transaction hashes.\r\n\r\n```bash\r\nnode {baseDir}/scripts/swap-status.js --hashes 0xApproveHash,0xSwapHash\r\n```\r\n\r\nOutput:\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"completed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\", \"amountIn\": \"0.5\", \"tokenIn\": \"ETH\", \"amountOut\": \"1562.75\", \"tokenOut\": \"USDC\"}\r\n  ]\r\n}\r\n```\r\n\r\nHigh-level status: `pending` (waiting for confirmation), `completed` (all steps confirmed), `failed` (a step reverted).\r\n\r\n## Workflow Patterns\r\n\r\n### Check exchange rate\r\n\r\n```\r\n1. rate.js --token-in ETH --token-out USDC --amount-in 1\r\n```\r\n\r\n### Execute a swap\r\n\r\n```\r\n1. account.js                                              → get wallet address\r\n2. rate.js --token-in ETH --token-out USDC --amount-in 0.5 → show rate and gas cost to user\r\n3. [Ask user for confirmation]\r\n4. balance.js --address <wallet> --tokens ETH,USDC          → show balances and allowance\r\n5. swap.js --token-in ETH --token-out USDC --amount-in 0.5  → execute (approve + swap if needed)\r\n6. swap-status.js --hashes <hash1>,<hash2>                  → verify result\r\n7. balance.js --address <wallet> --tokens ETH,USDC          → show balances after\r\n```\r\n\r\n### Price monitoring with auto-swap (via OpenClaw cron/heartbeat)\r\n\r\n```\r\n1. rate.js --token-in ETH --token-out USDC --amount-in 0.5  → check current rate\r\n2. If target rate reached:\r\n   a. swap.js --token-in ETH --token-out USDC --amount-in 0.5  → execute swap\r\n   b. swap-status.js --hashes <hashes>                          → verify result\r\n   c. balance.js ...                                            → show final balances\r\n3. If not reached: wait for next cron tick\r\n```\r\n\r\nWhen using cron-based monitoring and the API returns a temporary error (\"AIDEX is temporarily unavailable\" or network error), simply skip this iteration and retry on the next tick. Do not treat temporary errors as final failures.\r\n\r\n## Agent Rules\r\n\r\n1. **Always show rate and gas cost** before executing a swap. The user must see what they're getting.\r\n2. **Ask for explicit confirmation** before executing a swap — unless the user explicitly set up automatic execution (e.g., \"swap every time the price drops below 2800\"). Confirmation can be one-time or for a series, but the agent never invents retries on its own.\r\n3. **Display amounts in human-readable format** (e.g., \"0.5 ETH\", \"1,562.75 USDC\"), not raw BigInt values.\r\n4. **Always show transaction hashes** after a swap so the user can track them on Etherscan.\r\n5. **Handle error responses gracefully**:\r\n   - `Route not found` — Let the user know AIDEX could not find a route for this pair, and suggest trying a different pair or amount.\r\n   - `AIDEX is temporarily unavailable` — Let the user know AIDEX is not available right now and suggest trying again in a few minutes.\r\n   - The error says the skill is outdated (e.g., `Skill ... is outdated` or `Outdated skill version`) — Ask the user to run `openclaw skills update aidex` in their terminal.\r\n   - `Request rejected` — Most likely the request was formed incorrectly — re-check the arguments. If they look correct, ask the user to update the skill: `openclaw skills update aidex`.\r\n   - Network errors — Same as above, suggest retrying later.\r\n   - Invalid token — Suggest searching for the token by name or symbol.\r\n6. **After a swap, always call swap-status.js** to verify the actual result and show it to the user.\r\n7. **Private key not configured?** If no private key is available, present **all** configuration options: environment variable (via `openclaw config set`) **and** system keyring. Do not default to a single option — let the user choose.\r\n8. **NEVER loop or auto-retry on errors.** If any transaction reverts or the API returns an error, stop the current operation and report to the user. Do not automatically retry. If the user wants to try again, they will say so.\r\n9. **NEVER access the private key directly.** Do not read openclaw.json, .env files, or any other configuration files to extract the private key. Do not pass the private key as a command-line argument — command-line arguments are visible to all processes on the system. Passing the key this way is equivalent to leaking it to an attacker. The key is resolved from the AIDEX_PRIVATE_KEY environment variable or the system keyring. If neither source provides a valid key, inform the user and stop. No workarounds.\r\n10. **While a transaction is mining**, you can show the user a link to track it: `https://etherscan.io/tx/{transactionHash}`. This applies to all transactions (swap, approve).\r\n11. **Detect the user's environment.** When helping with private key setup, adapt your suggestions to the user's environment. If the user is running in a containerized or headless Linux environment (Docker, WSL, CI), lead with the environment variable approach (Option A) — do not mention the system keyring unless the user explicitly asks about alternatives. If asked, explain that the system keyring is available for desktop operating systems (Windows, macOS, Linux with a graphical session) but is not accessible from containers or headless environments. For desktop users, present all keyring options but highlight the one matching their OS first.\r\n12. **Never ask the user about private key configuration proactively.** Do not ask \"is your private key configured?\" or offer to help with setup when the user first interacts with the skill. The user may not even know what a private key is. Simply run the requested operation — if the key is needed and not configured, the script will return a clear error, and only then should you explain what happened and how to set it up. For read-only operations (rate, tokens, balances), the key is not needed at all — do not mention it.\r\n13. **Do not assume the private key is missing — check by running the script.** When the user asks for their balance, wallet address, or any operation that may require a private key, do not refuse preemptively. Run `account.js` — if the key is configured, you'll get the wallet address. If not, the script will return a clear error explaining what to set up. This is a read-only operation with no cost and no risk. Never tell the user \"I can't do this\" without actually trying first.\r\n14. **When asking for a wallet address, warn the user not to confuse it with a private key.** Both start with `0x`, but an address is 42 characters and is safe to share, while a private key is 66 characters and must be kept secret. If the user provides a 66-character string where an address is expected, **do not use it** — warn them immediately that this looks like a private key and should never be shared. Example: \"Your wallet address (42 characters, starts with 0x — this is **not** your private key, which is longer and must be kept secret).\"\r\n15. **Never modify the skill's source code.** The scripts in `{baseDir}/scripts/` and `package.json` are canonical — do not edit, patch, or \"fix\" them under any circumstances, even temporarily. If a script returns an unexpected error and you suspect a bug in the skill, you are almost certainly wrong: re-check your own inputs and call sequence carefully, read the script specifications in this SKILL.md word-for-word, and use the exact command names and argument names documented there — never invent your own syntax.\r\n\r\n## Key Constants\r\n\r\n- Native ETH address: `0x0000000000000000000000000000000000000000`\r\n- WETH address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`\r\n- Network: Ethereum mainnet (chainId: 1)\r\n- Common tokens: ETH (18 decimals), USDC (6), USDT (6), DAI (18), WBTC (8)\n\nFile v1.0.6:_meta.json\n\n{\n  \"ownerId\": \"kn75vpgckjav1ae1dw275517y9863f78\",\n  \"slug\": \"aidex\",\n  \"version\": \"1.0.6\",\n  \"publishedAt\": 1778672173037\n}\n\nFile v1.0.6:references/scripts.md\n\n# AIDEX Scripts Reference\r\n\r\nDetailed reference for all AIDEX skill scripts. Load this when you need to understand exact arguments, output formats, or error handling for a specific script.\r\n\r\nAll scripts are located in `{baseDir}/scripts/` and invoked via `node`. Every script outputs a single JSON line to stdout and exits. The JSON always contains a `success` field (`true` or `false`). On failure, an `error` field provides a human-readable explanation.\r\n\r\n## Token identification\r\n\r\nAll scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`) support two formats:\r\n\r\n- **By address**: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- **By symbol**: `USDC`\r\n\r\nIf a symbol matches zero tokens, the error will be: `\"Token not found: 'XYZ'. Use /api/v1/agent/tokens to search for available tokens.\"`\r\n\r\nIf a symbol matches multiple tokens (ambiguous), the error will list all matches with their addresses so you can specify the exact one.\r\n\r\nUse `ETH` or `0x0000000000000000000000000000000000000000` for native Ether.\r\n\r\n---\r\n\r\n## Common API errors\r\n\r\nThese can come from any script that calls the AIDEX API. Per-script tables below list only script-specific errors.\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Skill version ... is outdated...\"` | Skill is outdated — run `openclaw skills update aidex` |\r\n| `\"Request rejected...\"` | Server rejected the request — re-check arguments |\r\n\r\n---\r\n\r\n## account.js\r\n\r\nDerives the wallet address from the configured private key. Does not call the API.\r\n\r\n### Arguments\r\n\r\nNone.\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output\r\n\r\n```json\r\n{\"success\": true, \"address\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18\"}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n\r\n---\r\n\r\n## tokens.js\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--term <query>` | No | Search query (substring match, case-insensitive). If omitted, returns all tokens. |\r\n\r\n### Output\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"tokens\": [\r\n    {\r\n      \"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\r\n      \"symbol\": \"USDC\",\r\n      \"decimals\": 6,\r\n      \"name\": \"USD Coin\",\r\n      \"imageUrl\": \"https://...\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nAn empty `tokens` array means no matches were found.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"API request failed: ...\"` | Network or server error |\r\n\r\n---\r\n\r\n## rate.js\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--token-in <token>` | Yes | Token to sell (address or symbol) |\r\n| `--token-out <token>` | Yes | Token to buy (address or symbol) |\r\n| `--amount-in <number>` | Yes | Amount to sell, human-readable (e.g., `0.5`) |\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"rate\": \"3125.50\",\r\n  \"amountOut\": \"1562.75\",\r\n  \"estimatedGasPriceUsd\": 2.34\r\n}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --token-in.\"` | Missing argument |\r\n| `\"Token not found.\"` | Unknown token symbol |\r\n| `\"Route not found.\"` | No exchange route for this pair/amount |\r\n| `\"AIDEX is temporarily unavailable. Please try again later.\"` | Internal service down — retry later |\r\n\r\n---\r\n\r\n## balance.js\r\n\r\nGet token balances and allowances for a wallet address. Maximum 9 tokens per request. The `allowance` field shows how much the AIDEX router is approved to spend on behalf of the wallet (relevant for ERC-20 tokens). For native ETH, `allowance` is `null`.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--address <wallet>` | Yes | Wallet address (0x...) |\r\n| `--tokens <list>` | Yes | Comma-separated tokens (address or symbol). Use `ETH` for native Ether. Max 9. |\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"balances\": [\r\n    {\"address\": \"0x0000000000000000000000000000000000000000\", \"symbol\": \"ETH\", \"balance\": \"1.5\", \"allowance\": null},\r\n    {\"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", \"symbol\": \"USDC\", \"balance\": \"3250.00\", \"allowance\": \"1000.0\"}\r\n  ]\r\n}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --address.\"` | Missing argument |\r\n| `\"Missing required argument: --tokens.\"` | Missing argument |\r\n| `\"Too many tokens. Maximum is 9 per request.\"` | Exceeded limit |\r\n| `\"Token not found.\"` | Unknown token symbol |\r\n\r\n---\r\n\r\n## swap.js\r\n\r\nExecutes a full swap cycle. The API builds a chain of transactions (approve + swap if needed), the script signs them locally and sends them. Approve is handled automatically — the script doesn't need to know about it.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Default | Description |\r\n|----------|----------|---------|-------------|\r\n| `--token-in <token>` | Yes | — | Token to sell (address or symbol) |\r\n| `--token-out <token>` | Yes | — | Token to buy (address or symbol) |\r\n| `--amount-in <number>` | Yes | — | Amount to sell, human-readable |\r\n| `--slippage <percent>` | No | `0.5` | Maximum acceptable slippage (e.g., `0.5` = 0.5%) |\r\n| `--deadline-minutes <min>` | No | `20` | Transaction deadline in minutes from now |\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"transactionHashes\": [\"0xApproveHash...\", \"0xSwapHash...\"],\r\n  \"fromAddress\": \"0x742d35Cc...\",\r\n  \"amountOut\": \"1562.75\",\r\n  \"estimatedGasPriceUsd\": 2.34\r\n}\r\n```\r\n\r\n`transactionHashes` is an array (1-3 hashes). Pass all of them to swap-status.js to check the result.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --token-in.\"` | Missing argument |\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n| `\"Route not found.\"` | No exchange route — suggest different pair or amount |\r\n| `\"AIDEX is temporarily unavailable. Please try again later.\"` | Internal service down — retry later |\r\n| `\"Insufficient balance\"` | Not enough tokens to execute the swap |\r\n| `\"Failed to sign transaction: ...\"` | ethers.js signing error |\r\n\r\n### Important behavior\r\n\r\n- If the API returns a non-success result, the script does **not** attempt to sign or send anything. It returns the error and exits.\r\n- The private key is used only for `ethers.Wallet.signTransaction()` and never leaves the process.\r\n- If the node rejects a transaction, the script stops and exits with `success: false`. `failedAtStep` is the zero-based index (into the transaction chain returned by createSwap) of the transaction the node rejected — use it to report to the user which step could not be sent. `transactionHashes` contains the hashes of transactions that were accepted by the node before the failure.\r\n\r\n---\r\n\r\n## swap-status.js\r\n\r\nCheck the status of a swap operation (including approve steps). Accepts 1-3 transaction hashes.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--hashes <list>` | Yes | Comma-separated transaction hashes (1-3). Pass the hashes returned by swap.js. |\r\n\r\n### Output\r\n\r\n**Completed (all steps confirmed):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"completed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\", \"amountIn\": \"0.5\", \"tokenIn\": \"ETH\", \"amountOut\": \"1562.75\", \"tokenOut\": \"USDC\"}\r\n  ]\r\n}\r\n```\r\n\r\n**Pending (waiting for confirmation):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"pending\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"pending\", \"transactionHash\": \"0x...\"}\r\n  ]\r\n}\r\n```\r\n\r\n**Failed (a step reverted):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"failed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"reverted\", \"transactionHash\": \"0x...\"}\r\n  ]\r\n}\r\n```\r\n\r\nHigh-level status: `pending` (waiting), `completed` (all confirmed), `failed` (a step reverted).\r\n\r\nStep-level status: `pending`, `confirmed`, `reverted`.\r\n\r\n`amountIn`, `tokenIn`, `amountOut`, `tokenOut` are only present for the swap step, not for approve steps.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --hashes.\"` | Missing argument |\r\n| `\"Expected 1 to 3 transaction hashes, comma-separated.\"` | Wrong number of hashes |\r\n| `\"Invalid hash: ...\"` | Malformed transaction hash |\r\n| `\"API request failed: ...\"` | Network or server error |\n\nFile v1.0.6:references/security.md\n\n# AIDEX Security Model\r\n\r\n## Architecture\r\n\r\nThe AIDEX skill uses a client-side signing architecture. This document explains how it works and why it's secure.\r\n\r\n## How a swap works step by step\r\n\r\n1. **Agent requests swap parameters** — The `swap.js` script sends a POST request to the AIDEX API with high-level swap parameters: which token to sell, which token to buy, and how much. The API does NOT receive the private key.\r\n\r\n2. **API builds the transaction** — The AIDEX API finds the best exchange route, computes the exact transaction data (contract address, call data, gas parameters, nonce), and returns it as a complete unsigned transaction object.\r\n\r\n3. **Local signing** — The `swap.js` script uses `ethers.Wallet.signTransaction()` to sign the transaction locally. The private key **never** leaves your machine. Transaction signing happens entirely on your side.\r\n\r\n4. **Broadcasting** — The signed raw transaction (a hex string) is sent to the AIDEX API, which broadcasts it to the Ethereum network via `eth_sendRawTransaction`. This is equivalent to what any public RPC endpoint does.\r\n\r\n## What makes this secure\r\n\r\n### The private key never leaves the machine\r\n\r\nThe key is resolved locally from one of two sources: the `AIDEX_PRIVATE_KEY` environment variable or the operating system's credential manager (via `@napi-rs/keyring`). In both cases, the key is used exclusively by the local ethers.js `Wallet` instance to produce a cryptographic signature. No API call, at any point, includes the private key.\r\n\r\n### Signed transactions are tamper-proof\r\n\r\nAn Ethereum transaction, once signed, is cryptographically bound to its parameters. If anyone modifies any field — the recipient address, the amount, the call data, the gas price — the signature becomes invalid and the transaction is rejected by the network.\r\n\r\nThis means:\r\n- The AIDEX API cannot change what you signed\r\n- A man-in-the-middle cannot alter the transaction\r\n- Even a fully compromised AIDEX server can only broadcast exactly what you signed, or refuse to broadcast it\r\n\r\n### The API is a public RPC relay\r\n\r\nThe `POST /api/v1/agent/swap/send` endpoint is functionally equivalent to calling `eth_sendRawTransaction` on any public Ethereum RPC. It receives a signed transaction and submits it to the network. It has no special privileges and cannot modify the transaction in any way.\r\n\r\n### All read operations are unauthenticated\r\n\r\nToken searches, rate checks, balance queries, and transaction receipts are all read-only operations that use publicly available blockchain data. They do not require a private key and do not expose any sensitive information.\r\n\r\n## Risk assessment\r\n\r\n### What can go wrong\r\n\r\n| Risk | Likelihood | Impact | Mitigation |\r\n|------|-----------|--------|------------|\r\n| AIDEX API compromised | Low | None — attacker can only see/broadcast signed txs they cannot alter | Client-side signing architecture |\r\n| OpenClaw host compromised (env) | Low-Medium | High — attacker gets the private key from process environment | Use a dedicated wallet with limited funds |\r\n| OpenClaw host compromised (keyring) | Low-Medium | High — attacker may access the keyring if logged in as the same OS user | Use a dedicated wallet with limited funds; OS-level access controls |\r\n| Network eavesdropping | Low | None — signed txs are public anyway once broadcast | Standard HTTPS encryption |\r\n| Malicious transaction data from API | Very Low | Medium — user signs a bad transaction | Slippage protection, deadline, user review of rates before swap |\r\n\r\n### Recommended practices\r\n\r\n1. **Use a dedicated trading wallet** — Create a new wallet specifically for automated trading.\r\n2. **Start small** — Begin with small amounts to verify everything works as expected.\r\n3. **Review rates before swaps** — The agent should always show you the exchange rate and gas cost before executing.\r\n4. **Set reasonable slippage** — The default 0.5% slippage protects against price movements. Adjust based on token volatility.\r\n5. **Monitor transaction results** — After each swap, check the receipt to confirm actual amounts.\r\n\r\n## Comparison with alternatives\r\n\r\n### vs. Custodial (CEX) integrations\r\nIn custodial integrations, you deposit funds to the platform. The platform holds your money and you trust them not to lose it, get hacked, or freeze your account. AIDEX never touches your funds — they stay in your wallet.\r\n\r\n### vs. Server-side signing\r\nSome integrations ask you to provide your private key to a server that signs transactions on your behalf. This is a significantly higher risk profile. With AIDEX, signing happens on your machine, and the key is never transmitted over the network.\r\n\r\n## Note on `primaryEnv` in SKILL.md metadata\r\n\r\nThe SKILL.md declares `\"primaryEnv\": \"AIDEX_PRIVATE_KEY\"`. This is a workaround for a limitation in OpenClaw's current architecture: OpenClaw does not provide a mechanism for optional sensitive environment variables. Without `primaryEnv` (or `requires.env`, which would make the variable mandatory and block the entire skill), the `AIDEX_PRIVATE_KEY` variable is rejected by OpenClaw's env sanitizer (pattern `_PRIVATE_KEY`).\r\n\r\nUsing `primaryEnv` maps the variable to OpenClaw's `apiKey` config field. Despite this naming, the AIDEX API is fully public and does not require authentication. The private key is used exclusively for client-side transaction signing and is never sent to the API. The `primaryEnv` field exists solely to allow the private key through the sanitizer while keeping it optional (read-only operations work without it).\n\nFile v1.0.6:package.json\n\n{\r\n  \"name\": \"openclaw-aidex\",\r\n  \"version\": \"1.0.6\",\r\n  \"description\": \"OpenClaw skill for AIDEX aggregator on Ethereum\",\r\n  \"private\": true,\r\n  \"type\": \"module\",\r\n  \"engines\": {\r\n    \"node\": \">=18.0.0\"\r\n  },\r\n  \"dependencies\": {\r\n    \"ethers\": \"6.16.0\"\r\n  },\r\n  \"optionalDependencies\": {\r\n    \"@napi-rs/keyring\": \"1.2.0\"\r\n  }\r\n}\n\nArchive v1.0.5: 16 files, 96948 bytes\n\nFiles: package.json (332b), references/scripts.md (9224b), references/security.md (5614b), scripts/account.js (276b), scripts/balance.js (955b), scripts/data/tokens.json (275405b), scripts/lib/api.js (5023b), scripts/lib/tokens.js (1507b), scripts/lib/utils.js (7708b), scripts/lib/version.js (160b), scripts/rate.js (887b), scripts/swap-status.js (951b), scripts/swap.js (13673b), scripts/tokens.js (333b), SKILL.md (19318b), _meta.json (124b)\n\nFile v1.0.5:SKILL.md\n\n---\r\nname: aidex\r\ndescription: Swap tokens on Ethereum via the AIDEX aggregator. Search tokens, check exchange rates, view balances, and execute swaps. Client-side transaction signing keeps your private key on your machine.\r\nversion: 1.0.5\r\nhomepage: https://ai-dex.io/\r\nuser-invocable: true\r\nemoji: \"\\U0001F504\"\r\nmetadata: {\r\n  \"openclaw\": {\r\n    \"requires\": {\r\n      \"bins\": [\"node\"]\r\n    },\r\n    \"primaryEnv\": \"AIDEX_PRIVATE_KEY\"\r\n  }\r\n}\r\n---\r\n\r\n## Overview\r\n\r\nAIDEX is a high-performance DEX aggregator on Ethereum. This skill gives your OpenClaw agent the ability to swap tokens, check exchange rates, monitor balances, and verify transaction results.\r\n\r\nAIDEX provides tools, not decisions. You decide when and what to trade. AIDEX is your hands — fast, transparent, reliable. Every operation is a visible on-chain Ethereum transaction that you can verify on Etherscan. Nothing is hidden, nothing is obscured.\r\n\r\nAIDEX doesn't pretend to be smarter than you. It doesn't make decisions on your behalf. It does exactly what you ask — honestly, quickly, and verifiably. If you want to experiment with automated trading, AIDEX gives you the simplest, most transparent foundation to build on.\r\n\r\nYour funds stay in your wallet at all times. Unlike centralized exchange integrations where your money sits on someone else's platform, AIDEX works with decentralized liquidity pools. You remain in full control.\r\n\r\n## Source code\r\n\r\nOpen source on GitHub: [AIDEX-DeFi/skills](https://github.com/AIDEX-DeFi/skills). Issues and pull requests welcome.\r\n\r\n## Why AIDEX\r\n\r\n- **Simplicity** — Simple, clear scripts. Clear inputs, clear outputs. The agent calls them, you see the results. That's it.\r\n- **Transparency** — Every swap is a standard Ethereum transaction. You get a transaction hash. You can check it on Etherscan. What you asked for is what gets executed.\r\n- **Security** — Your private key never leaves your machine. The API only receives already-signed transactions. Even if our servers were compromised, no one could alter your transaction — it's cryptographically signed by you. See the [Security Model](#security-model) section below.\r\n- **Speed** — Lightning-fast execution layer with minimal latency. Transactions are built and sent in milliseconds.\r\n- **Best rates** — Wide liquidity pool coverage finds exchange routes that competitors miss, giving you better rates.\r\n\r\n## Dependencies\r\n\r\nThis skill requires Node.js packages listed in `package.json` in the skill's root folder:\r\n\r\n- **ethers** — Ethereum library for client-side transaction signing. This is what keeps your private key safe — transactions are signed locally, never sent to the API.\r\n- **@napi-rs/keyring** *(optional)* — Native access to the operating system's credential manager (Windows Credential Manager, macOS Keychain, Linux Secret Service). Allows storing the private key securely instead of an environment variable.\r\n\r\n**Run `npm install` in the skill's root folder after the initial install and after each skill update.** Skill updates may pin new dependency versions. The packages are installed locally into the skill's own `node_modules/` folder — this is NOT a modification to the user's system environment. It is a standard, reversible operation (the folder can be deleted at any time).\r\n\r\nIf your operational constraints prevent you from running `npm install` automatically, ask the user for permission and let them decide.\r\n\r\n**Do not report the skill as broken if dependencies are missing — install them.**\r\n\r\n## Security Model\r\n\r\n### Client-side transaction signing\r\n\r\nAll transaction signing happens locally on your machine using ethers.js. The AIDEX API **never receives, requests, or has access to your private key**.\r\n\r\nHere's what happens during a swap:\r\n\r\n1. Your agent calls the AIDEX API with swap parameters (which tokens, how much)\r\n2. The API returns a **complete unsigned transaction** (destination address, call data, gas parameters)\r\n3. The `swap.js` script signs this transaction using your private key via `ethers.Wallet.signTransaction()`\r\n4. Finally, the signed transaction is sent back to the API for fast broadcasting to the Ethereum network\r\n\r\n### What the API cannot do\r\n\r\nYour funds are protected because every transaction must be reviewed and signed directly by your wallet. AIDEX cannot modify transaction amounts, tokens, or recipients, and cannot initiate unauthorized transactions.\r\n\r\n### What AIDEX API does NOT do\r\n\r\n- Does not store private keys\r\n- Does not manage or custody your funds\r\n- Does not deduct fees from your wallet\r\n- Does not have any access to your assets beyond what you explicitly sign\r\n\r\n### Private key storage — a reasonable trade-off\r\n\r\nYour private key can be stored in the `AIDEX_PRIVATE_KEY` environment variable or in the operating system's credential manager (system keyring). Both approaches keep the key local to your machine. See the [Setup](#setup) section for configuration details.\r\n\r\nThis is a deliberate and reasonable trade-off between autonomy and security: if the agent cannot sign transactions, it cannot trade autonomously.\r\n\r\n## Setup\r\n\r\nThe AIDEX skill works out of the box for read-only operations: searching tokens, checking exchange rates, and viewing balances. No configuration needed.\r\n\r\nTo execute swaps, configure your private key using one of the options below.\r\n\r\n### What is a Private Key?\r\n\r\nA private key is 64 hexadecimal characters (`0-9`, `a-f`), optionally prefixed with `0x` — 64 or 66 characters total. It is the sole credential that authorizes transactions from your Ethereum wallet. Unlike a password, a private key cannot be reset or recovered — if it is lost or compromised, access to the wallet's funds is permanently lost or stolen.\r\n\r\nIf you don't have a wallet yet, the easiest way to get started is with [MetaMask](https://metamask.io/):\r\n\r\n1. Install the MetaMask browser extension and create a new wallet\r\n2. Open MetaMask, click the account selector at the top of the screen\r\n3. Tap the account menu (⋮) next to the account name, then select **Account details**\r\n4. Select **Private keys**, enter your MetaMask password, and copy the revealed key\r\n\r\nUse this key in one of the configuration options below.\r\n\r\n### Option A: Environment variable (via OpenClaw)\r\n\r\n**Simple — for testing only.** The private key is passed as a command-line argument and may end up in shell history, process list, and audit logs:\r\n\r\n```bash\r\nopenclaw config set skills.entries.aidex.env.AIDEX_PRIVATE_KEY \"0xYourPrivateKeyHere\"\r\n```\r\n\r\n**Secure — requires bash (on Windows use WSL).** The key is read interactively into a shell variable and piped via stdin, never appearing in argv:\r\n\r\n```bash\r\nread -rsp \"AIDEX private key: \" k; echo; printf '{\"skills\":{\"entries\":{\"aidex\":{\"env\":{\"AIDEX_PRIVATE_KEY\":\"%s\"}}}}}' \"$k\" | openclaw config patch --stdin; unset k\r\n```\r\n\r\n### Option B: System keyring (desktop only)\r\n\r\n> **Not available in Docker, WSL, CI, or headless Linux.** The system keyring requires a desktop session. If you are running in a containerized or headless environment, use Option A above.\r\n\r\nStore your private key in the operating system's credential manager. The key is encrypted at rest and protected by your OS user account, keeping it out of configuration files and environment variable logs.\r\n\r\n**Windows** (Credential Manager):\r\n\r\n```cmd\r\ncmdkey /generic:AIDEX_PRIVATE_KEY.aidex /user:AIDEX_PRIVATE_KEY\r\n```\r\n\r\n**macOS** (Keychain):\r\n\r\n```bash\r\nsecurity add-generic-password -s aidex -a AIDEX_PRIVATE_KEY -U\r\n```\r\n\r\n**Linux** (Secret Service — GNOME Keyring, KWallet):\r\n\r\n```bash\r\nsecret-tool store --label=\"AIDEX Private Key\" service aidex username AIDEX_PRIVATE_KEY target default\r\n```\r\n\r\nIn all three commands above, you will be prompted to enter the private key interactively.\r\n\r\n**Headless and containerized environments (Docker, WSL, CI):**\r\n\r\nThe system keyring is not accessible from containers or headless environments — it requires a desktop session with D-Bus. In these environments, use Option A (environment variable). For production server deployments, proper firewall configuration is essential to restrict access to the machine running the agent.\r\n\r\nIf both an environment variable and a keyring entry are present, the environment variable takes priority.\r\n\r\n## Token identification\r\n\r\nIn all scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`), you can specify tokens by **address** or by **symbol**:\r\n\r\n- By address: `--token-in 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- By symbol: `--token-in USDC`\r\n\r\nIf a symbol is ambiguous (matches multiple tokens), the API will return an error listing all matches so you can specify the address instead.\r\n\r\n## Scripts\r\n\r\n> **Note:** You don't need to read this section to use AIDEX for trading. Your OpenClaw agent handles the scripts automatically. This section is for developers or anyone who wants to understand how the system works under the hood.\r\n\r\nAll scripts output JSON to stdout. Every response contains a `success` field (`true` or `false`). On failure, an `error` field explains what went wrong.\r\n\r\n### account.js — Get wallet address *(requires private key)*\r\n\r\nDerives your wallet address from the private key. Does not call the API.\r\n\r\n```bash\r\nnode {baseDir}/scripts/account.js\r\n```\r\n\r\nOutput: `{\"success\": true, \"address\": \"0x...\"}`\r\n\r\n### tokens.js — Search tokens\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n```bash\r\nnode {baseDir}/scripts/tokens.js --term USDC\r\n```\r\n\r\nWithout `--term`, returns the full token list.\r\n\r\nOutput: `{\"success\": true, \"tokens\": [{\"address\": \"0x...\", \"symbol\": \"USDC\", \"decimals\": 6, \"name\": \"USD Coin\", \"imageUrl\": \"...\"}]}`\r\n\r\n### rate.js — Check exchange rate\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything. Tokens can be specified by address or symbol.\r\n\r\n```bash\r\nnode {baseDir}/scripts/rate.js --token-in ETH --token-out USDC --amount-in 0.5\r\n```\r\n\r\nOutput: `{\"success\": true, \"rate\": \"3125.50\", \"amountOut\": \"1562.75\", \"estimatedGasPriceUsd\": 2.34}`\r\n\r\n### balance.js — Check token balances\r\n\r\nGet balances for up to 9 tokens at once. Use `ETH` or the zero address (`0x0000000000000000000000000000000000000000`) for native ETH balance. Tokens can be specified by address or symbol.\r\n\r\n> **Note:** `--address` is required, but you often don't need to ask the user for it. Run `account.js` first — if the private key is configured, it returns the wallet address. Only ask the user for their address if `account.js` returns an error (private key not configured).\r\n\r\n```bash\r\nnode {baseDir}/scripts/balance.js --address 0xYourWallet --tokens ETH,USDC\r\n```\r\n\r\nOutput: `{\"success\": true, \"balances\": [{\"address\": \"0x000...0\", \"symbol\": \"ETH\", \"balance\": \"1.5\", \"allowance\": null}, {\"address\": \"0xA0b...eB48\", \"symbol\": \"USDC\", \"balance\": \"3250.00\", \"allowance\": \"1000.0\"}]}`\r\n\r\nThe `allowance` field shows how much the AIDEX router is approved to spend on behalf of the wallet (relevant for ERC-20 tokens). For native ETH, `allowance` is `null`.\r\n\r\n### swap.js — Execute a swap *(requires private key)*\r\n\r\nBuilds a chain of transactions (approve if needed + swap) via API, signs them locally on your machine, and broadcasts them. Full cycle in one call. The API handles approve automatically — the script doesn't need to know about it. Tokens can be specified by address or symbol.\r\n\r\n```bash\r\nnode {baseDir}/scripts/swap.js --token-in ETH --token-out USDC --amount-in 0.5 --slippage 0.5 --deadline-minutes 20\r\n```\r\n\r\n- `--slippage` — Maximum acceptable slippage in percent (default: 0.5)\r\n- `--deadline-minutes` — Transaction deadline in minutes from now (default: 20)\r\n\r\nOutput: `{\"success\": true, \"transactionHashes\": [\"0x...\"], \"fromAddress\": \"0x...\", \"amountOut\": \"1562.75\", \"estimatedGasPriceUsd\": 2.34}`\r\n\r\nNote: `transactionHashes` is an array — it may contain 1-3 hashes (approve transactions + swap). Pass all of them to swap-status.js.\r\n\r\n### swap-status.js — Check swap operation status\r\n\r\nVerify the result of a swap operation (including approve steps). Accepts 1-3 transaction hashes.\r\n\r\n```bash\r\nnode {baseDir}/scripts/swap-status.js --hashes 0xApproveHash,0xSwapHash\r\n```\r\n\r\nOutput:\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"completed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\", \"amountIn\": \"0.5\", \"tokenIn\": \"ETH\", \"amountOut\": \"1562.75\", \"tokenOut\": \"USDC\"}\r\n  ]\r\n}\r\n```\r\n\r\nHigh-level status: `pending` (waiting for confirmation), `completed` (all steps confirmed), `failed` (a step reverted).\r\n\r\n## Workflow Patterns\r\n\r\n### Check exchange rate\r\n\r\n```\r\n1. rate.js --token-in ETH --token-out USDC --amount-in 1\r\n```\r\n\r\n### Execute a swap\r\n\r\n```\r\n1. account.js                                              → get wallet address\r\n2. rate.js --token-in ETH --token-out USDC --amount-in 0.5 → show rate and gas cost to user\r\n3. [Ask user for confirmation]\r\n4. balance.js --address <wallet> --tokens ETH,USDC          → show balances and allowance\r\n5. swap.js --token-in ETH --token-out USDC --amount-in 0.5  → execute (approve + swap if needed)\r\n6. swap-status.js --hashes <hash1>,<hash2>                  → verify result\r\n7. balance.js --address <wallet> --tokens ETH,USDC          → show balances after\r\n```\r\n\r\n### Price monitoring with auto-swap (via OpenClaw cron/heartbeat)\r\n\r\n```\r\n1. rate.js --token-in ETH --token-out USDC --amount-in 0.5  → check current rate\r\n2. If target rate reached:\r\n   a. swap.js --token-in ETH --token-out USDC --amount-in 0.5  → execute swap\r\n   b. swap-status.js --hashes <hashes>                          → verify result\r\n   c. balance.js ...                                            → show final balances\r\n3. If not reached: wait for next cron tick\r\n```\r\n\r\nWhen using cron-based monitoring and the API returns a temporary error (\"AIDEX is temporarily unavailable\" or network error), simply skip this iteration and retry on the next tick. Do not treat temporary errors as final failures.\r\n\r\n## Agent Rules\r\n\r\n1. **Always show rate and gas cost** before executing a swap. The user must see what they're getting.\r\n2. **Ask for explicit confirmation** before executing a swap — unless the user explicitly set up automatic execution (e.g., \"swap every time the price drops below 2800\"). Confirmation can be one-time or for a series, but the agent never invents retries on its own.\r\n3. **Display amounts in human-readable format** (e.g., \"0.5 ETH\", \"1,562.75 USDC\"), not raw BigInt values.\r\n4. **Always show transaction hashes** after a swap so the user can track them on Etherscan.\r\n5. **Handle error responses gracefully**:\r\n   - `Route not found` — Let the user know AIDEX could not find a route for this pair, and suggest trying a different pair or amount.\r\n   - `AIDEX is temporarily unavailable` — Let the user know AIDEX is not available right now and suggest trying again in a few minutes.\r\n   - The error says the skill is outdated (e.g., `Skill ... is outdated` or `Outdated skill version`) — Ask the user to run `openclaw skills update aidex` in their terminal.\r\n   - `Request rejected` — Most likely the request was formed incorrectly — re-check the arguments. If they look correct, ask the user to update the skill: `openclaw skills update aidex`.\r\n   - Network errors — Same as above, suggest retrying later.\r\n   - Invalid token — Suggest searching for the token by name or symbol.\r\n6. **After a swap, always call swap-status.js** to verify the actual result and show it to the user.\r\n7. **Private key not configured?** If no private key is available, present **all** configuration options: environment variable (via `openclaw config set`) **and** system keyring. Do not default to a single option — let the user choose.\r\n8. **NEVER loop or auto-retry on errors.** If any transaction reverts or the API returns an error, stop the current operation and report to the user. Do not automatically retry. If the user wants to try again, they will say so.\r\n9. **NEVER access the private key directly.** Do not read openclaw.json, .env files, or any other configuration files to extract the private key. Do not pass the private key as a command-line argument — command-line arguments are visible to all processes on the system. Passing the key this way is equivalent to leaking it to an attacker. The key is resolved from the AIDEX_PRIVATE_KEY environment variable or the system keyring. If neither source provides a valid key, inform the user and stop. No workarounds.\r\n10. **While a transaction is mining**, you can show the user a link to track it: `https://etherscan.io/tx/{transactionHash}`. This applies to all transactions (swap, approve).\r\n11. **Detect the user's environment.** When helping with private key setup, adapt your suggestions to the user's environment. If the user is running in a containerized or headless Linux environment (Docker, WSL, CI), lead with the environment variable approach (Option A) — do not mention the system keyring unless the user explicitly asks about alternatives. If asked, explain that the system keyring is available for desktop operating systems (Windows, macOS, Linux with a graphical session) but is not accessible from containers or headless environments. For desktop users, present all keyring options but highlight the one matching their OS first.\r\n12. **Never ask the user about private key configuration proactively.** Do not ask \"is your private key configured?\" or offer to help with setup when the user first interacts with the skill. The user may not even know what a private key is. Simply run the requested operation — if the key is needed and not configured, the script will return a clear error, and only then should you explain what happened and how to set it up. For read-only operations (rate, tokens, balances), the key is not needed at all — do not mention it.\r\n13. **Do not assume the private key is missing — check by running the script.** When the user asks for their balance, wallet address, or any operation that may require a private key, do not refuse preemptively. Run `account.js` — if the key is configured, you'll get the wallet address. If not, the script will return a clear error explaining what to set up. This is a read-only operation with no cost and no risk. Never tell the user \"I can't do this\" without actually trying first.\r\n14. **When asking for a wallet address, warn the user not to confuse it with a private key.** Both start with `0x`, but an address is 42 characters and is safe to share, while a private key is 66 characters and must be kept secret. If the user provides a 66-character string where an address is expected, **do not use it** — warn them immediately that this looks like a private key and should never be shared. Example: \"Your wallet address (42 characters, starts with 0x — this is **not** your private key, which is longer and must be kept secret).\"\r\n\r\n## Key Constants\r\n\r\n- Native ETH address: `0x0000000000000000000000000000000000000000`\r\n- WETH address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`\r\n- Network: Ethereum mainnet (chainId: 1)\r\n- Common tokens: ETH (18 decimals), USDC (6), USDT (6), DAI (18), WBTC (8)\n\nFile v1.0.5:_meta.json\n\n{\n  \"ownerId\": \"kn75vpgckjav1ae1dw275517y9863f78\",\n  \"slug\": \"aidex\",\n  \"version\": \"1.0.5\",\n  \"publishedAt\": 1778602715672\n}\n\nFile v1.0.5:references/scripts.md\n\n# AIDEX Scripts Reference\r\n\r\nDetailed reference for all AIDEX skill scripts. Load this when you need to understand exact arguments, output formats, or error handling for a specific script.\r\n\r\nAll scripts are located in `{baseDir}/scripts/` and invoked via `node`. Every script outputs a single JSON line to stdout and exits. The JSON always contains a `success` field (`true` or `false`). On failure, an `error` field provides a human-readable explanation.\r\n\r\n## Token identification\r\n\r\nAll scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`) support two formats:\r\n\r\n- **By address**: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- **By symbol**: `USDC`\r\n\r\nIf a symbol matches zero tokens, the error will be: `\"Token not found: 'XYZ'. Use /api/v1/agent/tokens to search for available tokens.\"`\r\n\r\nIf a symbol matches multiple tokens (ambiguous), the error will list all matches with their addresses so you can specify the exact one.\r\n\r\nUse `ETH` or `0x0000000000000000000000000000000000000000` for native Ether.\r\n\r\n---\r\n\r\n## Common API errors\r\n\r\nThese can come from any script that calls the AIDEX API. Per-script tables below list only script-specific errors.\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Skill version ... is outdated...\"` | Skill is outdated — run `openclaw skills update aidex` |\r\n| `\"Request rejected...\"` | Server rejected the request — re-check arguments |\r\n\r\n---\r\n\r\n## account.js\r\n\r\nDerives the wallet address from the configured private key. Does not call the API.\r\n\r\n### Arguments\r\n\r\nNone.\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output\r\n\r\n```json\r\n{\"success\": true, \"address\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18\"}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n\r\n---\r\n\r\n## tokens.js\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--term <query>` | No | Search query (substring match, case-insensitive). If omitted, returns all tokens. |\r\n\r\n### Output\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"tokens\": [\r\n    {\r\n      \"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\r\n      \"symbol\": \"USDC\",\r\n      \"decimals\": 6,\r\n      \"name\": \"USD Coin\",\r\n      \"imageUrl\": \"https://...\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nAn empty `tokens` array means no matches were found.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"API request failed: ...\"` | Network or server error |\r\n\r\n---\r\n\r\n## rate.js\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--token-in <token>` | Yes | Token to sell (address or symbol) |\r\n| `--token-out <token>` | Yes | Token to buy (address or symbol) |\r\n| `--amount-in <number>` | Yes | Amount to sell, human-readable (e.g., `0.5`) |\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"rate\": \"3125.50\",\r\n  \"amountOut\": \"1562.75\",\r\n  \"estimatedGasPriceUsd\": 2.34\r\n}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --token-in.\"` | Missing argument |\r\n| `\"Token not found.\"` | Unknown token symbol |\r\n| `\"Route not found.\"` | No exchange route for this pair/amount |\r\n| `\"AIDEX is temporarily unavailable. Please try again later.\"` | Internal service down — retry later |\r\n\r\n---\r\n\r\n## balance.js\r\n\r\nGet token balances and allowances for a wallet address. Maximum 9 tokens per request. The `allowance` field shows how much the AIDEX router is approved to spend on behalf of the wallet (relevant for ERC-20 tokens). For native ETH, `allowance` is `null`.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--address <wallet>` | Yes | Wallet address (0x...) |\r\n| `--tokens <list>` | Yes | Comma-separated tokens (address or symbol). Use `ETH` for native Ether. Max 9. |\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"balances\": [\r\n    {\"address\": \"0x0000000000000000000000000000000000000000\", \"symbol\": \"ETH\", \"balance\": \"1.5\", \"allowance\": null},\r\n    {\"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", \"symbol\": \"USDC\", \"balance\": \"3250.00\", \"allowance\": \"1000.0\"}\r\n  ]\r\n}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --address.\"` | Missing argument |\r\n| `\"Missing required argument: --tokens.\"` | Missing argument |\r\n| `\"Too many tokens. Maximum is 9 per request.\"` | Exceeded limit |\r\n| `\"Token not found.\"` | Unknown token symbol |\r\n\r\n---\r\n\r\n## swap.js\r\n\r\nExecutes a full swap cycle. The API builds a chain of transactions (approve + swap if needed), the script signs them locally and sends them. Approve is handled automatically — the script doesn't need to know about it.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Default | Description |\r\n|----------|----------|---------|-------------|\r\n| `--token-in <token>` | Yes | — | Token to sell (address or symbol) |\r\n| `--token-out <token>` | Yes | — | Token to buy (address or symbol) |\r\n| `--amount-in <number>` | Yes | — | Amount to sell, human-readable |\r\n| `--slippage <percent>` | No | `0.5` | Maximum acceptable slippage (e.g., `0.5` = 0.5%) |\r\n| `--deadline-minutes <min>` | No | `20` | Transaction deadline in minutes from now |\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"transactionHashes\": [\"0xApproveHash...\", \"0xSwapHash...\"],\r\n  \"fromAddress\": \"0x742d35Cc...\",\r\n  \"amountOut\": \"1562.75\",\r\n  \"estimatedGasPriceUsd\": 2.34\r\n}\r\n```\r\n\r\n`transactionHashes` is an array (1-3 hashes). Pass all of them to swap-status.js to check the result.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --token-in.\"` | Missing argument |\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n| `\"Route not found.\"` | No exchange route — suggest different pair or amount |\r\n| `\"AIDEX is temporarily unavailable. Please try again later.\"` | Internal service down — retry later |\r\n| `\"Insufficient balance\"` | Not enough tokens to execute the swap |\r\n| `\"Failed to sign transaction: ...\"` | ethers.js signing error |\r\n\r\n### Important behavior\r\n\r\n- If the API returns a non-success result, the script does **not** attempt to sign or send anything. It returns the error and exits.\r\n- The private key is used only for `ethers.Wallet.signTransaction()` and never leaves the process.\r\n- If the node rejects a transaction, the script stops and exits with `success: false`. `failedAtStep` is the zero-based index (into the transaction chain returned by createSwap) of the transaction the node rejected — use it to report to the user which step could not be sent. `transactionHashes` contains the hashes of transactions that were accepted by the node before the failure.\r\n\r\n---\r\n\r\n## swap-status.js\r\n\r\nCheck the status of a swap operation (including approve steps). Accepts 1-3 transaction hashes.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--hashes <list>` | Yes | Comma-separated transaction hashes (1-3). Pass the hashes returned by swap.js. |\r\n\r\n### Output\r\n\r\n**Completed (all steps confirmed):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"completed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\", \"amountIn\": \"0.5\", \"tokenIn\": \"ETH\", \"amountOut\": \"1562.75\", \"tokenOut\": \"USDC\"}\r\n  ]\r\n}\r\n```\r\n\r\n**Pending (waiting for confirmation):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"pending\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"pending\", \"transactionHash\": \"0x...\"}\r\n  ]\r\n}\r\n```\r\n\r\n**Failed (a step reverted):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"failed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"reverted\", \"transactionHash\": \"0x...\"}\r\n  ]\r\n}\r\n```\r\n\r\nHigh-level status: `pending` (waiting), `completed` (all confirmed), `failed` (a step reverted).\r\n\r\nStep-level status: `pending`, `confirmed`, `reverted`.\r\n\r\n`amountIn`, `tokenIn`, `amountOut`, `tokenOut` are only present for the swap step, not for approve steps.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --hashes.\"` | Missing argument |\r\n| `\"Expected 1 to 3 transaction hashes, comma-separated.\"` | Wrong number of hashes |\r\n| `\"Invalid hash: ...\"` | Malformed transaction hash |\r\n| `\"API request failed: ...\"` | Network or server error |\n\nFile v1.0.5:references/security.md\n\n# AIDEX Security Model\r\n\r\n## Architecture\r\n\r\nThe AIDEX skill uses a client-side signing architecture. This document explains how it works and why it's secure.\r\n\r\n## How a swap works step by step\r\n\r\n1. **Agent requests swap parameters** — The `swap.js` script sends a POST request to the AIDEX API with high-level swap parameters: which token to sell, which token to buy, and how much. The API does NOT receive the private key.\r\n\r\n2. **API builds the transaction** — The AIDEX API finds the best exchange route, computes the exact transaction data (contract address, call data, gas parameters, nonce), and returns it as a complete unsigned transaction object.\r\n\r\n3. **Local signing** — The `swap.js` script uses `ethers.Wallet.signTransaction()` to sign the transaction locally. The private key **never** leaves your machine. Transaction signing happens entirely on your side.\r\n\r\n4. **Broadcasting** — The signed raw transaction (a hex string) is sent to the AIDEX API, which broadcasts it to the Ethereum network via `eth_sendRawTransaction`. This is equivalent to what any public RPC endpoint does.\r\n\r\n## What makes this secure\r\n\r\n### The private key never leaves the machine\r\n\r\nThe key is resolved locally from one of two sources: the `AIDEX_PRIVATE_KEY` environment variable or the operating system's credential manager (via `@napi-rs/keyring`). In both cases, the key is used exclusively by the local ethers.js `Wallet` instance to produce a cryptographic signature. No API call, at any point, includes the private key.\r\n\r\n### Signed transactions are tamper-proof\r\n\r\nAn Ethereum transaction, once signed, is cryptographically bound to its parameters. If anyone modifies any field — the recipient address, the amount, the call data, the gas price — the signature becomes invalid and the transaction is rejected by the network.\r\n\r\nThis means:\r\n- The AIDEX API cannot change what you signed\r\n- A man-in-the-middle cannot alter the transaction\r\n- Even a fully compromised AIDEX server can only broadcast exactly what you signed, or refuse to broadcast it\r\n\r\n### The API is a public RPC relay\r\n\r\nThe `POST /api/v1/agent/swap/send` endpoint is functionally equivalent to calling `eth_sendRawTransaction` on any public Ethereum RPC. It receives a signed transaction and submits it to the network. It has no special privileges and cannot modify the transaction in any way.\r\n\r\n### All read operations are unauthenticated\r\n\r\nToken searches, rate checks, balance queries, and transaction receipts are all read-only operations that use publicly available blockchain data. They do not require a private key and do not expose any sensitive information.\r\n\r\n## Risk assessment\r\n\r\n### What can go wrong\r\n\r\n| Risk | Likelihood | Impact | Mitigation |\r\n|------|-----------|--------|------------|\r\n| AIDEX API compromised | Low | None — attacker can only see/broadcast signed txs they cannot alter | Client-side signing architecture |\r\n| OpenClaw host compromised (env) | Low-Medium | High — attacker gets the private key from process environment | Use a dedicated wallet with limited funds |\r\n| OpenClaw host compromised (keyring) | Low-Medium | High — attacker may access the keyring if logged in as the same OS user | Use a dedicated wallet with limited funds; OS-level access controls |\r\n| Network eavesdropping | Low | None — signed txs are public anyway once broadcast | Standard HTTPS encryption |\r\n| Malicious transaction data from API | Very Low | Medium — user signs a bad transaction | Slippage protection, deadline, user review of rates before swap |\r\n\r\n### Recommended practices\r\n\r\n1. **Use a dedicated trading wallet** — Create a new wallet specifically for automated trading.\r\n2. **Start small** — Begin with small amounts to verify everything works as expected.\r\n3. **Review rates before swaps** — The agent should always show you the exchange rate and gas cost before executing.\r\n4. **Set reasonable slippage** — The default 0.5% slippage protects against price movements. Adjust based on token volatility.\r\n5. **Monitor transaction results** — After each swap, check the receipt to confirm actual amounts.\r\n\r\n## Comparison with alternatives\r\n\r\n### vs. Custodial (CEX) integrations\r\nIn custodial integrations, you deposit funds to the platform. The platform holds your money and you trust them not to lose it, get hacked, or freeze your account. AIDEX never touches your funds — they stay in your wallet.\r\n\r\n### vs. Server-side signing\r\nSome integrations ask you to provide your private key to a server that signs transactions on your behalf. This is a significantly higher risk profile. With AIDEX, signing happens on your machine, and the key is never transmitted over the network.\r\n\r\n## Note on `primaryEnv` in SKILL.md metadata\r\n\r\nThe SKILL.md declares `\"primaryEnv\": \"AIDEX_PRIVATE_KEY\"`. This is a workaround for a limitation in OpenClaw's current architecture: OpenClaw does not provide a mechanism for optional sensitive environment variables. Without `primaryEnv` (or `requires.env`, which would make the variable mandatory and block the entire skill), the `AIDEX_PRIVATE_KEY` variable is rejected by OpenClaw's env sanitizer (pattern `_PRIVATE_KEY`).\r\n\r\nUsing `primaryEnv` maps the variable to OpenClaw's `apiKey` config field. Despite this naming, the AIDEX API is fully public and does not require authentication. The private key is used exclusively for client-side transaction signing and is never sent to the API. The `primaryEnv` field exists solely to allow the private key through the sanitizer while keeping it optional (read-only operations work without it).\n\nFile v1.0.5:package.json\n\n{\r\n  \"name\": \"openclaw-aidex\",\r\n  \"version\": \"1.0.5\",\r\n  \"description\": \"OpenClaw skill for AIDEX aggregator on Ethereum\",\r\n  \"private\": true,\r\n  \"type\": \"module\",\r\n  \"engines\": {\r\n    \"node\": \">=18.0.0\"\r\n  },\r\n  \"dependencies\": {\r\n    \"ethers\": \"6.16.0\"\r\n  },\r\n  \"optionalDependencies\": {\r\n    \"@napi-rs/keyring\": \"1.2.0\"\r\n  }\r\n}\n\nArchive v1.0.4: 16 files, 90500 bytes\n\nFiles: package.json (332b), references/scripts.md (9224b), references/security.md (5614b), scripts/account.js (276b), scripts/balance.js (955b), scripts/data/tokens.json (249409b), scripts/lib/api.js (5023b), scripts/lib/tokens.js (1507b), scripts/lib/utils.js (7708b), scripts/lib/version.js (160b), scripts/rate.js (887b), scripts/swap-status.js (951b), scripts/swap.js (13673b), scripts/tokens.js (333b), SKILL.md (19318b), _meta.json (124b)\n\nFile v1.0.4:SKILL.md\n\n---\r\nname: aidex\r\ndescription: Swap tokens on Ethereum via the AIDEX aggregator. Search tokens, check exchange rates, view balances, and execute swaps. Client-side transaction signing keeps your private key on your machine.\r\nversion: 1.0.4\r\nhomepage: https://ai-dex.io/\r\nuser-invocable: true\r\nemoji: \"\\U0001F504\"\r\nmetadata: {\r\n  \"openclaw\": {\r\n    \"requires\": {\r\n      \"bins\": [\"node\"]\r\n    },\r\n    \"primaryEnv\": \"AIDEX_PRIVATE_KEY\"\r\n  }\r\n}\r\n---\r\n\r\n## Overview\r\n\r\nAIDEX is a high-performance DEX aggregator on Ethereum. This skill gives your OpenClaw agent the ability to swap tokens, check exchange rates, monitor balances, and verify transaction results.\r\n\r\nAIDEX provides tools, not decisions. You decide when and what to trade. AIDEX is your hands — fast, transparent, reliable. Every operation is a visible on-chain Ethereum transaction that you can verify on Etherscan. Nothing is hidden, nothing is obscured.\r\n\r\nAIDEX doesn't pretend to be smarter than you. It doesn't make decisions on your behalf. It does exactly what you ask — honestly, quickly, and verifiably. If you want to experiment with automated trading, AIDEX gives you the simplest, most transparent foundation to build on.\r\n\r\nYour funds stay in your wallet at all times. Unlike centralized exchange integrations where your money sits on someone else's platform, AIDEX works with decentralized liquidity pools. You remain in full control.\r\n\r\n## Source code\r\n\r\nOpen source on GitHub: [AIDEX-DeFi/skills](https://github.com/AIDEX-DeFi/skills). Issues and pull requests welcome.\r\n\r\n## Why AIDEX\r\n\r\n- **Simplicity** — Simple, clear scripts. Clear inputs, clear outputs. The agent calls them, you see the results. That's it.\r\n- **Transparency** — Every swap is a standard Ethereum transaction. You get a transaction hash. You can check it on Etherscan. What you asked for is what gets executed.\r\n- **Security** — Your private key never leaves your machine. The API only receives already-signed transactions. Even if our servers were compromised, no one could alter your transaction — it's cryptographically signed by you. See the [Security Model](#security-model) section below.\r\n- **Speed** — Lightning-fast execution layer with minimal latency. Transactions are built and sent in milliseconds.\r\n- **Best rates** — Wide liquidity pool coverage finds exchange routes that competitors miss, giving you better rates.\r\n\r\n## Dependencies\r\n\r\nThis skill requires Node.js packages listed in `package.json` in the skill's root folder:\r\n\r\n- **ethers** — Ethereum library for client-side transaction signing. This is what keeps your private key safe — transactions are signed locally, never sent to the API.\r\n- **@napi-rs/keyring** *(optional)* — Native access to the operating system's credential manager (Windows Credential Manager, macOS Keychain, Linux Secret Service). Allows storing the private key securely instead of an environment variable.\r\n\r\n**Run `npm install` in the skill's root folder after the initial install and after each skill update.** Skill updates may pin new dependency versions. The packages are installed locally into the skill's own `node_modules/` folder — this is NOT a modification to the user's system environment. It is a standard, reversible operation (the folder can be deleted at any time).\r\n\r\nIf your operational constraints prevent you from running `npm install` automatically, ask the user for permission and let them decide.\r\n\r\n**Do not report the skill as broken if dependencies are missing — install them.**\r\n\r\n## Security Model\r\n\r\n### Client-side transaction signing\r\n\r\nAll transaction signing happens locally on your machine using ethers.js. The AIDEX API **never receives, requests, or has access to your private key**.\r\n\r\nHere's what happens during a swap:\r\n\r\n1. Your agent calls the AIDEX API with swap parameters (which tokens, how much)\r\n2. The API returns a **complete unsigned transaction** (destination address, call data, gas parameters)\r\n3. The `swap.js` script signs this transaction using your private key via `ethers.Wallet.signTransaction()`\r\n4. Finally, the signed transaction is sent back to the API for fast broadcasting to the Ethereum network\r\n\r\n### What the API cannot do\r\n\r\nYour funds are protected because every transaction must be reviewed and signed directly by your wallet. AIDEX cannot modify transaction amounts, tokens, or recipients, and cannot initiate unauthorized transactions.\r\n\r\n### What AIDEX API does NOT do\r\n\r\n- Does not store private keys\r\n- Does not manage or custody your funds\r\n- Does not deduct fees from your wallet\r\n- Does not have any access to your assets beyond what you explicitly sign\r\n\r\n### Private key storage — a reasonable trade-off\r\n\r\nYour private key can be stored in the `AIDEX_PRIVATE_KEY` environment variable or in the operating system's credential manager (system keyring). Both approaches keep the key local to your machine. See the [Setup](#setup) section for configuration details.\r\n\r\nThis is a deliberate and reasonable trade-off between autonomy and security: if the agent cannot sign transactions, it cannot trade autonomously.\r\n\r\n## Setup\r\n\r\nThe AIDEX skill works out of the box for read-only operations: searching tokens, checking exchange rates, and viewing balances. No configuration needed.\r\n\r\nTo execute swaps, configure your private key using one of the options below.\r\n\r\n### What is a Private Key?\r\n\r\nA private key is 64 hexadecimal characters (`0-9`, `a-f`), optionally prefixed with `0x` — 64 or 66 characters total. It is the sole credential that authorizes transactions from your Ethereum wallet. Unlike a password, a private key cannot be reset or recovered — if it is lost or compromised, access to the wallet's funds is permanently lost or stolen.\r\n\r\nIf you don't have a wallet yet, the easiest way to get started is with [MetaMask](https://metamask.io/):\r\n\r\n1. Install the MetaMask browser extension and create a new wallet\r\n2. Open MetaMask, click the account selector at the top of the screen\r\n3. Tap the account menu (⋮) next to the account name, then select **Account details**\r\n4. Select **Private keys**, enter your MetaMask password, and copy the revealed key\r\n\r\nUse this key in one of the configuration options below.\r\n\r\n### Option A: Environment variable (via OpenClaw)\r\n\r\n**Simple — for testing only.** The private key is passed as a command-line argument and may end up in shell history, process list, and audit logs:\r\n\r\n```bash\r\nopenclaw config set skills.entries.aidex.env.AIDEX_PRIVATE_KEY \"0xYourPrivateKeyHere\"\r\n```\r\n\r\n**Secure — requires bash (on Windows use WSL).** The key is read interactively into a shell variable and piped via stdin, never appearing in argv:\r\n\r\n```bash\r\nread -rsp \"AIDEX private key: \" k; echo; printf '{\"skills\":{\"entries\":{\"aidex\":{\"env\":{\"AIDEX_PRIVATE_KEY\":\"%s\"}}}}}' \"$k\" | openclaw config patch --stdin; unset k\r\n```\r\n\r\n### Option B: System keyring (desktop only)\r\n\r\n> **Not available in Docker, WSL, CI, or headless Linux.** The system keyring requires a desktop session. If you are running in a containerized or headless environment, use Option A above.\r\n\r\nStore your private key in the operating system's credential manager. The key is encrypted at rest and protected by your OS user account, keeping it out of configuration files and environment variable logs.\r\n\r\n**Windows** (Credential Manager):\r\n\r\n```cmd\r\ncmdkey /generic:AIDEX_PRIVATE_KEY.aidex /user:AIDEX_PRIVATE_KEY\r\n```\r\n\r\n**macOS** (Keychain):\r\n\r\n```bash\r\nsecurity add-generic-password -s aidex -a AIDEX_PRIVATE_KEY -U\r\n```\r\n\r\n**Linux** (Secret Service — GNOME Keyring, KWallet):\r\n\r\n```bash\r\nsecret-tool store --label=\"AIDEX Private Key\" service aidex username AIDEX_PRIVATE_KEY target default\r\n```\r\n\r\nIn all three commands above, you will be prompted to enter the private key interactively.\r\n\r\n**Headless and containerized environments (Docker, WSL, CI):**\r\n\r\nThe system keyring is not accessible from containers or headless environments — it requires a desktop session with D-Bus. In these environments, use Option A (environment variable). For production server deployments, proper firewall configuration is essential to restrict access to the machine running the agent.\r\n\r\nIf both an environment variable and a keyring entry are present, the environment variable takes priority.\r\n\r\n## Token identification\r\n\r\nIn all scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`), you can specify tokens by **address** or by **symbol**:\r\n\r\n- By address: `--token-in 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- By symbol: `--token-in USDC`\r\n\r\nIf a symbol is ambiguous (matches multiple tokens), the API will return an error listing all matches so you can specify the address instead.\r\n\r\n## Scripts\r\n\r\n> **Note:** You don't need to read this section to use AIDEX for trading. Your OpenClaw agent handles the scripts automatically. This section is for developers or anyone who wants to understand how the system works under the hood.\r\n\r\nAll scripts output JSON to stdout. Every response contains a `success` field (`true` or `false`). On failure, an `error` field explains what went wrong.\r\n\r\n### account.js — Get wallet address *(requires private key)*\r\n\r\nDerives your wallet address from the private key. Does not call the API.\r\n\r\n```bash\r\nnode {baseDir}/scripts/account.js\r\n```\r\n\r\nOutput: `{\"success\": true, \"address\": \"0x...\"}`\r\n\r\n### tokens.js — Search tokens\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n```bash\r\nnode {baseDir}/scripts/tokens.js --term USDC\r\n```\r\n\r\nWithout `--term`, returns the full token list.\r\n\r\nOutput: `{\"success\": true, \"tokens\": [{\"address\": \"0x...\", \"symbol\": \"USDC\", \"decimals\": 6, \"name\": \"USD Coin\", \"imageUrl\": \"...\"}]}`\r\n\r\n### rate.js — Check exchange rate\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything. Tokens can be specified by address or symbol.\r\n\r\n```bash\r\nnode {baseDir}/scripts/rate.js --token-in ETH --token-out USDC --amount-in 0.5\r\n```\r\n\r\nOutput: `{\"success\": true, \"rate\": \"3125.50\", \"amountOut\": \"1562.75\", \"estimatedGasPriceUsd\": 2.34}`\r\n\r\n### balance.js — Check token balances\r\n\r\nGet balances for up to 9 tokens at once. Use `ETH` or the zero address (`0x0000000000000000000000000000000000000000`) for native ETH balance. Tokens can be specified by address or symbol.\r\n\r\n> **Note:** `--address` is required, but you often don't need to ask the user for it. Run `account.js` first — if the private key is configured, it returns the wallet address. Only ask the user for their address if `account.js` returns an error (private key not configured).\r\n\r\n```bash\r\nnode {baseDir}/scripts/balance.js --address 0xYourWallet --tokens ETH,USDC\r\n```\r\n\r\nOutput: `{\"success\": true, \"balances\": [{\"address\": \"0x000...0\", \"symbol\": \"ETH\", \"balance\": \"1.5\", \"allowance\": null}, {\"address\": \"0xA0b...eB48\", \"symbol\": \"USDC\", \"balance\": \"3250.00\", \"allowance\": \"1000.0\"}]}`\r\n\r\nThe `allowance` field shows how much the AIDEX router is approved to spend on behalf of the wallet (relevant for ERC-20 tokens). For native ETH, `allowance` is `null`.\r\n\r\n### swap.js — Execute a swap *(requires private key)*\r\n\r\nBuilds a chain of transactions (approve if needed + swap) via API, signs them locally on your machine, and broadcasts them. Full cycle in one call. The API handles approve automatically — the script doesn't need to know about it. Tokens can be specified by address or symbol.\r\n\r\n```bash\r\nnode {baseDir}/scripts/swap.js --token-in ETH --token-out USDC --amount-in 0.5 --slippage 0.5 --deadline-minutes 20\r\n```\r\n\r\n- `--slippage` — Maximum acceptable slippage in percent (default: 0.5)\r\n- `--deadline-minutes` — Transaction deadline in minutes from now (default: 20)\r\n\r\nOutput: `{\"success\": true, \"transactionHashes\": [\"0x...\"], \"fromAddress\": \"0x...\", \"amountOut\": \"1562.75\", \"estimatedGasPriceUsd\": 2.34}`\r\n\r\nNote: `transactionHashes` is an array — it may contain 1-3 hashes (approve transactions + swap). Pass all of them to swap-status.js.\r\n\r\n### swap-status.js — Check swap operation status\r\n\r\nVerify the result of a swap operation (including approve steps). Accepts 1-3 transaction hashes.\r\n\r\n```bash\r\nnode {baseDir}/scripts/swap-status.js --hashes 0xApproveHash,0xSwapHash\r\n```\r\n\r\nOutput:\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"completed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\", \"amountIn\": \"0.5\", \"tokenIn\": \"ETH\", \"amountOut\": \"1562.75\", \"tokenOut\": \"USDC\"}\r\n  ]\r\n}\r\n```\r\n\r\nHigh-level status: `pending` (waiting for confirmation), `completed` (all steps confirmed), `failed` (a step reverted).\r\n\r\n## Workflow Patterns\r\n\r\n### Check exchange rate\r\n\r\n```\r\n1. rate.js --token-in ETH --token-out USDC --amount-in 1\r\n```\r\n\r\n### Execute a swap\r\n\r\n```\r\n1. account.js                                              → get wallet address\r\n2. rate.js --token-in ETH --token-out USDC --amount-in 0.5 → show rate and gas cost to user\r\n3. [Ask user for confirmation]\r\n4. balance.js --address <wallet> --tokens ETH,USDC          → show balances and allowance\r\n5. swap.js --token-in ETH --token-out USDC --amount-in 0.5  → execute (approve + swap if needed)\r\n6. swap-status.js --hashes <hash1>,<hash2>                  → verify result\r\n7. balance.js --address <wallet> --tokens ETH,USDC          → show balances after\r\n```\r\n\r\n### Price monitoring with auto-swap (via OpenClaw cron/heartbeat)\r\n\r\n```\r\n1. rate.js --token-in ETH --token-out USDC --amount-in 0.5  → check current rate\r\n2. If target rate reached:\r\n   a. swap.js --token-in ETH --token-out USDC --amount-in 0.5  → execute swap\r\n   b. swap-status.js --hashes <hashes>                          → verify result\r\n   c. balance.js ...                                            → show final balances\r\n3. If not reached: wait for next cron tick\r\n```\r\n\r\nWhen using cron-based monitoring and the API returns a temporary error (\"AIDEX is temporarily unavailable\" or network error), simply skip this iteration and retry on the next tick. Do not treat temporary errors as final failures.\r\n\r\n## Agent Rules\r\n\r\n1. **Always show rate and gas cost** before executing a swap. The user must see what they're getting.\r\n2. **Ask for explicit confirmation** before executing a swap — unless the user explicitly set up automatic execution (e.g., \"swap every time the price drops below 2800\"). Confirmation can be one-time or for a series, but the agent never invents retries on its own.\r\n3. **Display amounts in human-readable format** (e.g., \"0.5 ETH\", \"1,562.75 USDC\"), not raw BigInt values.\r\n4. **Always show transaction hashes** after a swap so the user can track them on Etherscan.\r\n5. **Handle error responses gracefully**:\r\n   - `Route not found` — Let the user know AIDEX could not find a route for this pair, and suggest trying a different pair or amount.\r\n   - `AIDEX is temporarily unavailable` — Let the user know AIDEX is not available right now and suggest trying again in a few minutes.\r\n   - The error says the skill is outdated (e.g., `Skill ... is outdated` or `Outdated skill version`) — Ask the user to run `openclaw skills update aidex` in their terminal.\r\n   - `Request rejected` — Most likely the request was formed incorrectly — re-check the arguments. If they look correct, ask the user to update the skill: `openclaw skills update aidex`.\r\n   - Network errors — Same as above, suggest retrying later.\r\n   - Invalid token — Suggest searching for the token by name or symbol.\r\n6. **After a swap, always call swap-status.js** to verify the actual result and show it to the user.\r\n7. **Private key not configured?** If no private key is available, present **all** configuration options: environment variable (via `openclaw config set`) **and** system keyring. Do not default to a single option — let the user choose.\r\n8. **NEVER loop or auto-retry on errors.** If any transaction reverts or the API returns an error, stop the current operation and report to the user. Do not automatically retry. If the user wants to try again, they will say so.\r\n9. **NEVER access the private key directly.** Do not read openclaw.json, .env files, or any other configuration files to extract the private key. Do not pass the private key as a command-line argument — command-line arguments are visible to all processes on the system. Passing the key this way is equivalent to leaking it to an attacker. The key is resolved from the AIDEX_PRIVATE_KEY environment variable or the system keyring. If neither source provides a valid key, inform the user and stop. No workarounds.\r\n10. **While a transaction is mining**, you can show the user a link to track it: `https://etherscan.io/tx/{transactionHash}`. This applies to all transactions (swap, approve).\r\n11. **Detect the user's environment.** When helping with private key setup, adapt your suggestions to the user's environment. If the user is running in a containerized or headless Linux environment (Docker, WSL, CI), lead with the environment variable approach (Option A) — do not mention the system keyring unless the user explicitly asks about alternatives. If asked, explain that the system keyring is available for desktop operating systems (Windows, macOS, Linux with a graphical session) but is not accessible from containers or headless environments. For desktop users, present all keyring options but highlight the one matching their OS first.\r\n12. **Never ask the user about private key configuration proactively.** Do not ask \"is your private key configured?\" or offer to help with setup when the user first interacts with the skill. The user may not even know what a private key is. Simply run the requested operation — if the key is needed and not configured, the script will return a clear error, and only then should you explain what happened and how to set it up. For read-only operations (rate, tokens, balances), the key is not needed at all — do not mention it.\r\n13. **Do not assume the private key is missing — check by running the script.** When the user asks for their balance, wallet address, or any operation that may require a private key, do not refuse preemptively. Run `account.js` — if the key is configured, you'll get the wallet address. If not, the script will return a clear error explaining what to set up. This is a read-only operation with no cost and no risk. Never tell the user \"I can't do this\" without actually trying first.\r\n14. **When asking for a wallet address, warn the user not to confuse it with a private key.** Both start with `0x`, but an address is 42 characters and is safe to share, while a private key is 66 characters and must be kept secret. If the user provides a 66-character string where an address is expected, **do not use it** — warn them immediately that this looks like a private key and should never be shared. Example: \"Your wallet address (42 characters, starts with 0x — this is **not** your private key, which is longer and must be kept secret).\"\r\n\r\n## Key Constants\r\n\r\n- Native ETH address: `0x0000000000000000000000000000000000000000`\r\n- WETH address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`\r\n- Network: Ethereum mainnet (chainId: 1)\r\n- Common tokens: ETH (18 decimals), USDC (6), USDT (6), DAI (18), WBTC (8)\n\nFile v1.0.4:_meta.json\n\n{\n  \"ownerId\": \"kn75vpgckjav1ae1dw275517y9863f78\",\n  \"slug\": \"aidex\",\n  \"version\": \"1.0.4\",\n  \"publishedAt\": 1778512660248\n}\n\nFile v1.0.4:references/scripts.md\n\n# AIDEX Scripts Reference\r\n\r\nDetailed reference for all AIDEX skill scripts. Load this when you need to understand exact arguments, output formats, or error handling for a specific script.\r\n\r\nAll scripts are located in `{baseDir}/scripts/` and invoked via `node`. Every script outputs a single JSON line to stdout and exits. The JSON always contains a `success` field (`true` or `false`). On failure, an `error` field provides a human-readable explanation.\r\n\r\n## Token identification\r\n\r\nAll scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`) support two formats:\r\n\r\n- **By address**: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- **By symbol**: `USDC`\r\n\r\nIf a symbol matches zero tokens, the error will be: `\"Token not found: 'XYZ'. Use /api/v1/agent/tokens to search for available tokens.\"`\r\n\r\nIf a symbol matches multiple tokens (ambiguous), the error will list all matches with their addresses so you can specify the exact one.\r\n\r\nUse `ETH` or `0x0000000000000000000000000000000000000000` for native Ether.\r\n\r\n---\r\n\r\n## Common API errors\r\n\r\nThese can come from any script that calls the AIDEX API. Per-script tables below list only script-specific errors.\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Skill version ... is outdated...\"` | Skill is outdated — run `openclaw skills update aidex` |\r\n| `\"Request rejected...\"` | Server rejected the request — re-check arguments |\r\n\r\n---\r\n\r\n## account.js\r\n\r\nDerives the wallet address from the configured private key. Does not call the API.\r\n\r\n### Arguments\r\n\r\nNone.\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output\r\n\r\n```json\r\n{\"success\": true, \"address\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18\"}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n\r\n---\r\n\r\n## tokens.js\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--term <query>` | No | Search query (substring match, case-insensitive). If omitted, returns all tokens. |\r\n\r\n### Output\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"tokens\": [\r\n    {\r\n      \"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\r\n      \"symbol\": \"USDC\",\r\n      \"decimals\": 6,\r\n      \"name\": \"USD Coin\",\r\n      \"imageUrl\": \"https://...\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nAn empty `tokens` array means no matches were found.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"API request failed: ...\"` | Network or server error |\r\n\r\n---\r\n\r\n## rate.js\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--token-in <token>` | Yes | Token to sell (address or symbol) |\r\n| `--token-out <token>` | Yes | Token to buy (address or symbol) |\r\n| `--amount-in <number>` | Yes | Amount to sell, human-readable (e.g., `0.5`) |\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"rate\": \"3125.50\",\r\n  \"amountOut\": \"1562.75\",\r\n  \"estimatedGasPriceUsd\": 2.34\r\n}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --token-in.\"` | Missing argument |\r\n| `\"Token not found.\"` | Unknown token symbol |\r\n| `\"Route not found.\"` | No exchange route for this pair/amount |\r\n| `\"AIDEX is temporarily unavailable. Please try again later.\"` | Internal service down — retry later |\r\n\r\n---\r\n\r\n## balance.js\r\n\r\nGet token balances and allowances for a wallet address. Maximum 9 tokens per request. The `allowance` field shows how much the AIDEX router is approved to spend on behalf of the wallet (relevant for ERC-20 tokens). For native ETH, `allowance` is `null`.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--address <wallet>` | Yes | Wallet address (0x...) |\r\n| `--tokens <list>` | Yes | Comma-separated tokens (address or symbol). Use `ETH` for native Ether. Max 9. |\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"balances\": [\r\n    {\"address\": \"0x0000000000000000000000000000000000000000\", \"symbol\": \"ETH\", \"balance\": \"1.5\", \"allowance\": null},\r\n    {\"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", \"symbol\": \"USDC\", \"balance\": \"3250.00\", \"allowance\": \"1000.0\"}\r\n  ]\r\n}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --address.\"` | Missing argument |\r\n| `\"Missing required argument: --tokens.\"` | Missing argument |\r\n| `\"Too many tokens. Maximum is 9 per request.\"` | Exceeded limit |\r\n| `\"Token not found.\"` | Unknown token symbol |\r\n\r\n---\r\n\r\n## swap.js\r\n\r\nExecutes a full swap cycle. The API builds a chain of transactions (approve + swap if needed), the script signs them locally and sends them. Approve is handled automatically — the script doesn't need to know about it.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Default | Description |\r\n|----------|----------|---------|-------------|\r\n| `--token-in <token>` | Yes | — | Token to sell (address or symbol) |\r\n| `--token-out <token>` | Yes | — | Token to buy (address or symbol) |\r\n| `--amount-in <number>` | Yes | — | Amount to sell, human-readable |\r\n| `--slippage <percent>` | No | `0.5` | Maximum acceptable slippage (e.g., `0.5` = 0.5%) |\r\n| `--deadline-minutes <min>` | No | `20` | Transaction deadline in minutes from now |\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output (success)\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"transactionHashes\": [\"0xApproveHash...\", \"0xSwapHash...\"],\r\n  \"fromAddress\": \"0x742d35Cc...\",\r\n  \"amountOut\": \"1562.75\",\r\n  \"estimatedGasPriceUsd\": 2.34\r\n}\r\n```\r\n\r\n`transactionHashes` is an array (1-3 hashes). Pass all of them to swap-status.js to check the result.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --token-in.\"` | Missing argument |\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n| `\"Route not found.\"` | No exchange route — suggest different pair or amount |\r\n| `\"AIDEX is temporarily unavailable. Please try again later.\"` | Internal service down — retry later |\r\n| `\"Insufficient balance\"` | Not enough tokens to execute the swap |\r\n| `\"Failed to sign transaction: ...\"` | ethers.js signing error |\r\n\r\n### Important behavior\r\n\r\n- If the API returns a non-success result, the script does **not** attempt to sign or send anything. It returns the error and exits.\r\n- The private key is used only for `ethers.Wallet.signTransaction()` and never leaves the process.\r\n- If the node rejects a transaction, the script stops and exits with `success: false`. `failedAtStep` is the zero-based index (into the transaction chain returned by createSwap) of the transaction the node rejected — use it to report to the user which step could not be sent. `transactionHashes` contains the hashes of transactions that were accepted by the node before the failure.\r\n\r\n---\r\n\r\n## swap-status.js\r\n\r\nCheck the status of a swap operation (including approve steps). Accepts 1-3 transaction hashes.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--hashes <list>` | Yes | Comma-separated transaction hashes (1-3). Pass the hashes returned by swap.js. |\r\n\r\n### Output\r\n\r\n**Completed (all steps confirmed):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"completed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\", \"amountIn\": \"0.5\", \"tokenIn\": \"ETH\", \"amountOut\": \"1562.75\", \"tokenOut\": \"USDC\"}\r\n  ]\r\n}\r\n```\r\n\r\n**Pending (waiting for confirmation):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"pending\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"pending\", \"transactionHash\": \"0x...\"}\r\n  ]\r\n}\r\n```\r\n\r\n**Failed (a step reverted):**\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"status\": \"failed\",\r\n  \"steps\": [\r\n    {\"type\": \"approve\", \"status\": \"confirmed\", \"transactionHash\": \"0x...\"},\r\n    {\"type\": \"swap\", \"status\": \"reverted\", \"transactionHash\": \"0x...\"}\r\n  ]\r\n}\r\n```\r\n\r\nHigh-level status: `pending` (waiting), `completed` (all confirmed), `failed` (a step reverted).\r\n\r\nStep-level status: `pending`, `confirmed`, `reverted`.\r\n\r\n`amountIn`, `tokenIn`, `amountOut`, `tokenOut` are only present for the swap step, not for approve steps.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Missing required argument: --hashes.\"` | Missing argument |\r\n| `\"Expected 1 to 3 transaction hashes, comma-separated.\"` | Wrong number of hashes |\r\n| `\"Invalid hash: ...\"` | Malformed transaction hash |\r\n| `\"API request failed: ...\"` | Network or server error |\n\nFile v1.0.4:references/security.md\n\n# AIDEX Security Model\r\n\r\n## Architecture\r\n\r\nThe AIDEX skill uses a client-side signing architecture. This document explains how it works and why it's secure.\r\n\r\n## How a swap works step by step\r\n\r\n1. **Agent requests swap parameters** — The `swap.js` script sends a POST request to the AIDEX API with high-level swap parameters: which token to sell, which token to buy, and how much. The API does NOT receive the private key.\r\n\r\n2. **API builds the transaction** — The AIDEX API finds the best exchange route, computes the exact transaction data (contract address, call data, gas parameters, nonce), and returns it as a complete unsigned transaction object.\r\n\r\n3. **Local signing** — The `swap.js` script uses `ethers.Wallet.signTransaction()` to sign the transaction locally. The private key **never** leaves your machine. Transaction signing happens entirely on your side.\r\n\r\n4. **Broadcasting** — The signed raw transaction (a hex string) is sent to the AIDEX API, which broadcasts it to the Ethereum network via `eth_sendRawTransaction`. This is equivalent to what any public RPC endpoint does.\r\n\r\n## What makes this secure\r\n\r\n### The private key never leaves the machine\r\n\r\nThe key is resolved locally from one of two sources: the `AIDEX_PRIVATE_KEY` environment variable or the operating system's credential manager (via `@napi-rs/keyring`). In both cases, the key is used exclusively by the local ethers.js `Wallet` instance to produce a cryptographic signature. No API call, at any point, includes the private key.\r\n\r\n### Signed transactions are tamper-proof\r\n\r\nAn Ethereum transaction, once signed, is cryptographically bound to its parameters. If anyone modifies any field — the recipient address, the amount, the call data, the gas price — the signature becomes invalid and the transaction is rejected by the network.\r\n\r\nThis means:\r\n- The AIDEX API cannot change what you signed\r\n- A man-in-the-middle cannot alter the transaction\r\n- Even a fully compromised AIDEX server can only broadcast exactly what you signed, or refuse to broadcast it\r\n\r\n### The API is a public RPC relay\r\n\r\nThe `POST /api/v1/agent/swap/send` endpoint is functionally equivalent to calling `eth_sendRawTransaction` on any public Ethereum RPC. It receives a signed transaction and submits it to the network. It has no special privileges and cannot modify the transaction in any way.\r\n\r\n### All read operations are unauthenticated\r\n\r\nToken searches, rate checks, balance queries, and transaction receipts are all read-only operations that use publicly available blockchain data. They do not require a private key and do not expose any sensitive information.\r\n\r\n## Risk assessment\r\n\r\n### What can go wrong\r\n\r\n| Risk | Likelihood | Impact | Mitigation |\r\n|------|-----------|--------|------------|\r\n| AIDEX API compromised | Low | None — attacker can only see/broadcast signed txs they cannot alter | Client-side signing architecture |\r\n| OpenClaw host compromised (env) | Low-Medium | High — attacker gets the private key from process environment | Use a dedicated wallet with limited funds |\r\n| OpenClaw host compromised (keyring) | Low-Medium | High — attacker may access the keyring if logged in as the same OS user | Use a dedicated wallet with limited funds; OS-level access controls |\r\n| Network eavesdropping | Low | None — signed txs are public anyway once broadcast | Standard HTTPS encryption |\r\n| Malicious transaction data from API | Very Low | Medium — user signs a bad transaction | Slippage protection, deadline, user review of rates before swap |\r\n\r\n### Recommended practices\r\n\r\n1. **Use a dedicated trading wallet** — Create a new wallet specifically for automated trading.\r\n2. **Start small** — Begin with small amounts to verify everything works as expected.\r\n3. **Review rates before swaps** — The agent should always show you the exchange rate and gas cost before executing.\r\n4. **Set reasonable slippage** — The default 0.5% slippage protects against price movements. Adjust based on token volatility.\r\n5. **Monitor transaction results** — After each swap, check the receipt to confirm actual amounts.\r\n\r\n## Comparison with alternatives\r\n\r\n### vs. Custodial (CEX) integrations\r\nIn custodial integrations, you deposit funds to the platform. The platform holds your money and you trust them not to lose it, get hacked, or freeze your account. AIDEX never touches your funds — they stay in your wallet.\r\n\r\n### vs. Server-side signing\r\nSome integrations ask you to provide your private key to a server that signs transactions on your behalf. This is a significantly higher risk profile. With AIDEX, signing happens on your machine, and the key is never transmitted over the network.\r\n\r\n## Note on `primaryEnv` in SKILL.m\n\nArchive v1.0.3: 16 files, 90456 bytes\n\nFiles: package.json (333b), references/scripts.md (9190b), references/security.md (5614b), scripts/account.js (276b), scripts/balance.js (955b), scripts/data/tokens.json (249409b), scripts/lib/api.js (5023b), scripts/lib/tokens.js (1507b), scripts/lib/utils.js (7644b), scripts/lib/version.js (160b), scripts/rate.js (887b), scripts/swap-status.js (951b), scripts/swap.js (13673b), scripts/tokens.js (333b), SKILL.md (19329b), _meta.json (124b)\n\nArchive v1.0.2: 15 files, 90235 bytes\n\nFiles: package.json (333b), references/scripts.md (9190b), references/security.md (5614b), scripts/account.js (276b), scripts/balance.js (955b), scripts/data/tokens.json (249409b), scripts/lib/api.js (5121b), scripts/lib/tokens.js (1507b), scripts/lib/utils.js (7644b), scripts/rate.js (887b), scripts/swap-status.js (951b), scripts/swap.js (13673b), scripts/tokens.js (333b), SKILL.md (19329b), _meta.json (124b)\n\nArchive v1.0.1: 13 files, 20588 bytes\n\nFiles: package.json (333b), references/scripts.md (8804b), references/security.md (5614b), scripts/account.js (276b), scripts/balance.js (953b), scripts/lib/api.js (3838b), scripts/lib/utils.js (7618b), scripts/rate.js (656b), scripts/swap-status.js (949b), scripts/swap.js (2396b), scripts/tokens.js (333b), SKILL.md (18472b), _meta.json (124b)\n\nArchive v1.0.0: 13 files, 20658 bytes\n\nFiles: package.json (333b), references/scripts.md (8804b), references/security.md (5614b), scripts/account.js (276b), scripts/balance.js (953b), scripts/lib/api.js (3838b), scripts/lib/utils.js (7618b), scripts/rate.js (656b), scripts/swap-status.js (949b), scripts/swap.js (2396b), scripts/tokens.js (333b), SKILL.md (18706b), _meta.json (124b)","readmeExcerpt":"Skill: Aidex Owner: almiashev Summary: AIDEX is a lightning-fast DEX aggregator for swapping tokens on-chain. The pipeline is optimised for minimal latency between an agent’s decision and the moment the signed transaction hits the network. The gap between intent and execution is where price moves against you, and AIDEX is built to minimise it. Search tokens, check exchange rates, view balances, and execute swaps with","codeSnippets":[],"executableExamples":[],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\r\nname: aidex\r\ndescription: Swap tokens on Ethereum via the AIDEX aggregator. Search tokens, check exchange rates, view balances, and execute swaps. Client-side transaction signing keeps your private key on your machine.\r\nversion: 1.0.7\r\nhomepage: https://ai-dex.io/\r\nuser-invocable: true\r\nemoji: \"\\U0001F504\"\r\nmetadata: {\r\n  \"openclaw\": {\r\n    \"requires\": {\r\n      \"bins\": [\"node\"]\r\n    },\r\n    \"primaryEnv\": \"AIDEX_PRIVATE_KEY\"\r\n  }\r\n}\r\n---\r\n\r\n## Overview\r\n\r\nAIDEX is a high-performance DEX aggregator on Ethereum. This skill gives your OpenClaw agent the ability to swap tokens, check exchange rates, monitor balances, and verify transaction results.\r\n\r\nAIDEX provides tools, not decisions. You decide when and what to trade. AIDEX is your hands — fast, transparent, reliable. Every operation is a visible on-chain Ethereum transaction that you can verify on Etherscan. Nothing is hidden, nothing is obscured.\r\n\r\nAIDEX doesn't pretend to be smarter than you. It doesn't make decisions on your behalf. It does exactly what you ask — honestly, quickly, and verifiably. If you want to experiment with automated trading, AIDEX gives you the simplest, most transparent foundation to build on.\r\n\r\nYour funds stay in your wallet at all times. Unlike centralized exchange integrations where your money sits on someone else's platform, AIDEX works with decentralized liquidity pools. You remain in full control.\r\n\r\n## Source code\r\n\r\nOpen source on GitHub: [AIDEX-DeFi/skills](https://github.com/AIDEX-DeFi/skills). Issues and pull requests welcome.\r\n\r\n## Why AIDEX\r\n\r\n- **Simplicity** — Simple, clear scripts. Clear inputs, clear outputs. The agent calls them, you see the results. That's it.\r\n- **Transparency** — Every swap is a standard Ethereum transaction. You get a transaction hash. You can check it on Etherscan. What you asked for is what gets executed.\r\n- **Security** — Your private key never leaves your machine. The API only receives already-signed transactions. Even if our servers were compromised, no one could alter your transaction — it's cryptographically signed by you. See the [Security Model](#security-model) section below.\r\n- **Speed** — Lightning-fast execution layer with minimal latency. Transactions are built and sent in milliseconds.\r\n- **Best rates** — Wide liquidity pool coverage finds exchange routes that competitors miss, giving you better rates.\r\n\r\n## Dependencies\r\n\r\nThis skill requires Node.js packages listed in `package.json` in the skill's root folder:\r\n\r\n- **ethers** — Ethereum library for client-side transaction signing. This is what keeps your private key safe — transactions are signed locally, never sent to the API.\r\n- **@napi-rs/keyring** *(optional)* — Native access to the operating system's credential manager (Windows Credential Manager, macOS Keychain, Linux Secret Service). Allows storing the private key securely instead of an environment variable.\r\n\r\n**Run `npm install` in the skill's root folder after the initial install and after each skil"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn75vpgckjav1ae1dw275517y9863f78\",\n  \"slug\": \"aidex\",\n  \"version\": \"1.0.7\",\n  \"publishedAt\": 1778687371661\n}"},{"path":"references/scripts.md","content":"# AIDEX Scripts Reference\r\n\r\nDetailed reference for all AIDEX skill scripts. Load this when you need to understand exact arguments, output formats, or error handling for a specific script.\r\n\r\nAll scripts are located in `{baseDir}/scripts/` and invoked via `node`. Every script outputs a single JSON line to stdout and exits. The JSON always contains a `success` field (`true` or `false`). On failure, an `error` field provides a human-readable explanation.\r\n\r\n## Token identification\r\n\r\nAll scripts that accept token parameters (`--token-in`, `--token-out`, `--tokens`) support two formats:\r\n\r\n- **By address**: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`\r\n- **By symbol**: `USDC`\r\n\r\nIf a symbol matches zero tokens, the error will be: `\"Token not found: 'XYZ'. Use /api/v1/agent/tokens to search for available tokens.\"`\r\n\r\nIf a symbol matches multiple tokens (ambiguous), the error will list all matches with their addresses so you can specify the exact one.\r\n\r\nUse `ETH` or `0x0000000000000000000000000000000000000000` for native Ether.\r\n\r\n---\r\n\r\n## Common API errors\r\n\r\nThese can come from any script that calls the AIDEX API. Per-script tables below list only script-specific errors.\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Skill version ... is outdated...\"` | Skill is outdated — run `openclaw skills update aidex` |\r\n| `\"Request rejected...\"` | Server rejected the request — re-check arguments |\r\n\r\n---\r\n\r\n## account.js\r\n\r\nDerives the wallet address from the configured private key. Does not call the API.\r\n\r\n### Arguments\r\n\r\nNone.\r\n\r\n### Private key\r\n\r\nRequired. See [Setup](../SKILL.md#setup) for configuration options.\r\n\r\n### Output\r\n\r\n```json\r\n{\"success\": true, \"address\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18\"}\r\n```\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"Private key is not configured...\"` | Neither `AIDEX_PRIVATE_KEY` environment variable nor system keyring entry is set — or the OpenClaw gateway was not restarted after configuration |\r\n| `\"Invalid private key: ...\"` | ethers.js rejected the key |\r\n\r\n---\r\n\r\n## tokens.js\r\n\r\nSearch for tokens by symbol, name, or address.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--term <query>` | No | Search query (substring match, case-insensitive). If omitted, returns all tokens. |\r\n\r\n### Output\r\n\r\n```json\r\n{\r\n  \"success\": true,\r\n  \"tokens\": [\r\n    {\r\n      \"address\": \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\r\n      \"symbol\": \"USDC\",\r\n      \"decimals\": 6,\r\n      \"name\": \"USD Coin\",\r\n      \"imageUrl\": \"https://...\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nAn empty `tokens` array means no matches were found.\r\n\r\n### Errors\r\n\r\n| Error | Cause |\r\n|-------|-------|\r\n| `\"API request failed: ...\"` | Network or server error |\r\n\r\n---\r\n\r\n## rate.js\r\n\r\nGet the current exchange rate for a token pair. Read-only, does not execute anything.\r\n\r\n### Arguments\r\n\r\n| Argument | Required | Description |\r\n|----------|----------|-------------|\r\n| `--token-in <token>` | Yes | Toke"},{"path":"references/security.md","content":"# AIDEX Security Model\r\n\r\n## Architecture\r\n\r\nThe AIDEX skill uses a client-side signing architecture. This document explains how it works and why it's secure.\r\n\r\n## How a swap works step by step\r\n\r\n1. **Agent requests swap parameters** — The `swap.js` script sends a POST request to the AIDEX API with high-level swap parameters: which token to sell, which token to buy, and how much. The API does NOT receive the private key.\r\n\r\n2. **API builds the transaction** — The AIDEX API finds the best exchange route, computes the exact transaction data (contract address, call data, gas parameters, nonce), and returns it as a complete unsigned transaction object.\r\n\r\n3. **Local signing** — The `swap.js` script uses `ethers.Wallet.signTransaction()` to sign the transaction locally. The private key **never** leaves your machine. Transaction signing happens entirely on your side.\r\n\r\n4. **Broadcasting** — The signed raw transaction (a hex string) is sent to the AIDEX API, which broadcasts it to the Ethereum network via `eth_sendRawTransaction`. This is equivalent to what any public RPC endpoint does.\r\n\r\n## What makes this secure\r\n\r\n### The private key never leaves the machine\r\n\r\nThe key is resolved locally from one of two sources: the `AIDEX_PRIVATE_KEY` environment variable or the operating system's credential manager (via `@napi-rs/keyring`). In both cases, the key is used exclusively by the local ethers.js `Wallet` instance to produce a cryptographic signature. No API call, at any point, includes the private key.\r\n\r\n### Signed transactions are tamper-proof\r\n\r\nAn Ethereum transaction, once signed, is cryptographically bound to its parameters. If anyone modifies any field — the recipient address, the amount, the call data, the gas price — the signature becomes invalid and the transaction is rejected by the network.\r\n\r\nThis means:\r\n- The AIDEX API cannot change what you signed\r\n- A man-in-the-middle cannot alter the transaction\r\n- Even a fully compromised AIDEX server can only broadcast exactly what you signed, or refuse to broadcast it\r\n\r\n### The API is a public RPC relay\r\n\r\nThe `POST /api/v1/agent/swap/send` endpoint is functionally equivalent to calling `eth_sendRawTransaction` on any public Ethereum RPC. It receives a signed transaction and submits it to the network. It has no special privileges and cannot modify the transaction in any way.\r\n\r\n### All read operations are unauthenticated\r\n\r\nToken searches, rate checks, balance queries, and transaction receipts are all read-only operations that use publicly available blockchain data. They do not require a private key and do not expose any sensitive information.\r\n\r\n## Risk assessment\r\n\r\n### What can go wrong\r\n\r\n| Risk | Likelihood | Impact | Mitigation |\r\n|------|-----------|--------|------------|\r\n| AIDEX API compromised | Low | None — attacker can only see/broadcast signed txs they cannot alter | Client-side signing architecture |\r\n| OpenClaw host compromised (env) | Low-Medium | High — attacker gets the privat"},{"path":"skill-card.md","content":"## Description:\n\nSwap tokens on Ethereum via the AIDEX aggregator; agents can search tokens, check exchange rates, view balances, and execute swaps while transaction signing remains local.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[almiashev](https://clawhub.ai/user/almiashev)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers use Aidex to let an OpenClaw agent search Ethereum tokens, quote swaps, inspect wallet balances, execute signed swaps, and check transaction status. Swap execution requires a locally configured wallet private key.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: A high-value private key could be exposed if the agent host or its environment is compromised.\n\nMitigation: Use a dedicated wallet with limited funds and avoid configuring a wallet that controls high-value assets.\n\nRisk: API-controlled swap terms could result in a bad trade or unexpectedly high gas fees.\n\nMitigation: Verify the final swap terms, exchange rate, slippage, and fees independently before execution.\n\nRisk: Token approvals may grant the router spending authority beyond the immediate swap.\n\nMitigation: Review allowances before and after swaps, and revoke unneeded approvals when appropriate.\n\n## Reference(s):\n\n- [ClawHub Aidex Skill Page](https://clawhub.ai/almiashev/skills/aidex)\n- [AIDEX Homepage](https://ai-dex.io/)\n- [AIDEX Scripts Reference](artifact/references/scripts.md)\n- [AIDEX Security Model](artifact/references/security.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, JSON, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with JSON results from Node.js command-line scripts]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only operations return token, rate, balance, or status data; swap operations can produce signed Ethereum transaction hashes.]\n\n## Skill Version(s):\n\n1.0.7 (source: SKILL.md frontmatter, package.json, and server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1939,"uniquenessScore":43,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T06:58:03.399Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T06:58:03.399Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:51:28.261Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}