From 742d06e8a2b861ed5b492f477b513fab0bac8f3e Mon Sep 17 00:00:00 2001 From: Daryl Collins Date: Tue, 21 Apr 2026 14:19:38 +0100 Subject: [PATCH 1/6] fix(ci): spill release additions/deletions through jq --slurpfile The release workflow was failing at the GraphQL-payload stage with `/usr/bin/jq: Argument list too long` whenever a release touched more than a handful of sizeable files. The base64-encoded contents of every changed file were being passed to jq as a single `--argjson` value, which blows past Linux's ~128 KB per-argument ARG_MAX ceiling once a few CHANGELOG / SKILL.md updates accumulate. Spill the additions and deletions JSON to temp files and load them via `--slurpfile`, unwrapping with `$additions[0]` / `$deletions[0]`. The GraphQL body shape is unchanged; only the jq transport is different. Temp files are added to the existing EXIT trap. --- .github/scripts/lerna-signed-release.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/scripts/lerna-signed-release.sh b/.github/scripts/lerna-signed-release.sh index 72bccf1..a80fd2c 100644 --- a/.github/scripts/lerna-signed-release.sh +++ b/.github/scripts/lerna-signed-release.sh @@ -269,7 +269,15 @@ else # pass nested JSON with large base64 payloads is unreliable; --input avoids # all shell escaping and size issues. GQL_TMPFILE=$(mktemp /tmp/lerna-release-graphql-XXXXXX.json) - trap 'rm -f "$GQL_TMPFILE"' EXIT + ADDITIONS_FILE=$(mktemp /tmp/lerna-release-additions-XXXXXX.json) + DELETIONS_FILE=$(mktemp /tmp/lerna-release-deletions-XXXXXX.json) + trap 'rm -f "$GQL_TMPFILE" "$ADDITIONS_FILE" "$DELETIONS_FILE"' EXIT + + # Spill additions/deletions to files and load with --slurpfile. Passing the + # base64-encoded file contents via --argjson exceeds ARG_MAX (~128 KB on + # Linux) once a release touches more than a handful of sizeable files. + printf '%s' "$ADDITIONS" > "$ADDITIONS_FILE" + printf '%s' "$DELETIONS" > "$DELETIONS_FILE" jq -n \ --arg query 'mutation CreateSignedCommit($input: CreateCommitOnBranchInput!) { @@ -280,15 +288,15 @@ else --arg headline "$COMMIT_HEADLINE" \ --arg body "$COMMIT_BODY" \ --arg expectedHeadOid "$PARENT_SHA" \ - --argjson additions "$ADDITIONS" \ - --argjson deletions "$DELETIONS" \ + --slurpfile additions "$ADDITIONS_FILE" \ + --slurpfile deletions "$DELETIONS_FILE" \ '{ "query": $query, "variables": { "input": { "branch": {"repositoryNameWithOwner": $repo, "branchName": $branch}, "message": {"headline": $headline, "body": $body}, - "fileChanges": {"additions": $additions, "deletions": $deletions}, + "fileChanges": {"additions": $additions[0], "deletions": $deletions[0]}, "expectedHeadOid": $expectedHeadOid } } From d9872ebc8c7d0422af4e871e8e84d04080962f5a Mon Sep 17 00:00:00 2001 From: Daryl Collins Date: Tue, 21 Apr 2026 15:53:21 +0100 Subject: [PATCH 2/6] feat(cli): drop bundled skills and sync hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @polygonlabs/agent-cli no longer ships a skills/ directory inside the published tarball. Installing the CLI via npm has never been the agent-facing skill install path — the recommended flow is `npx skills add https://github.com/0xPolygon/polygon-agent-cli`, which reads from the GitHub repo, not from npm. The bundled copy was vestigial: no CLI code reads it, no postinstall hook registers it, Claude Code does not auto-discover skills from installed npm packages, and the `skills` CLI (vercel-labs/skills) has no npm-package resolver at all — its `parseSource` function accepts GitHub/GitLab/local paths only. Removing it also deletes the duplicated copies under packages/connector-ui/public/ (root SKILL.md, skills/ tree, and per-sub-skill root mirrors) and packages/polygon-agent-cli/skills/ that the pre-commit hook was keeping in sync. The sync hook itself goes too — nothing left to sync. skills/ at the repo root is now the single source of truth. Note: this is technically a published-surface change — the tarball has shipped the skills/ path since 0.1.2. Pre-1.0 semver accepts surface changes in minor bumps, so this is intentionally NOT marked with a `!` or BREAKING CHANGE footer; @polygonlabs/agent-cli will bump 0.8.0 -> 0.9.0. No consumer has been found in or outside the repo that reads the bundled path. A following commit adds a Vite plugin that serves the CDN URL surface (/SKILL.md, /skills/*, //SKILL.md) directly from skills/ at build time, so the agentconnect URLs keep resolving with no committed duplicates. --- .husky/pre-commit | 64 ---- packages/connector-ui/public/SKILL.md | 221 ------------ .../connector-ui/public/polygon-defi/SKILL.md | 228 ------------ .../public/polygon-discovery/SKILL.md | 117 ------- .../public/polygon-polymarket/SKILL.md | 330 ------------------ packages/connector-ui/public/skills/SKILL.md | 219 ------------ .../public/skills/polygon-defi/SKILL.md | 229 ------------ .../public/skills/polygon-discovery/SKILL.md | 117 ------- .../public/skills/polygon-polymarket/SKILL.md | 330 ------------------ packages/polygon-agent-cli/package.json | 3 +- packages/polygon-agent-cli/skills/SKILL.md | 221 ------------ .../skills/polygon-defi/SKILL.md | 210 ----------- .../skills/polygon-discovery/SKILL.md | 117 ------- .../skills/polygon-polymarket/SKILL.md | 330 ------------------ 14 files changed, 1 insertion(+), 2735 deletions(-) delete mode 100644 packages/connector-ui/public/SKILL.md delete mode 100644 packages/connector-ui/public/polygon-defi/SKILL.md delete mode 100644 packages/connector-ui/public/polygon-discovery/SKILL.md delete mode 100644 packages/connector-ui/public/polygon-polymarket/SKILL.md delete mode 100644 packages/connector-ui/public/skills/SKILL.md delete mode 100644 packages/connector-ui/public/skills/polygon-defi/SKILL.md delete mode 100644 packages/connector-ui/public/skills/polygon-discovery/SKILL.md delete mode 100644 packages/connector-ui/public/skills/polygon-polymarket/SKILL.md delete mode 100644 packages/polygon-agent-cli/skills/SKILL.md delete mode 100644 packages/polygon-agent-cli/skills/polygon-defi/SKILL.md delete mode 100644 packages/polygon-agent-cli/skills/polygon-discovery/SKILL.md delete mode 100644 packages/polygon-agent-cli/skills/polygon-polymarket/SKILL.md diff --git a/.husky/pre-commit b/.husky/pre-commit index a9909fd..30ae3e8 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,66 +1,2 @@ -# ============================================================================= -# SKILL.md sync -# -# skills/ is the single source of truth for all agent skill definitions. -# The entire directory is synced to two locations on every commit: -# -# packages/connector-ui/public/SKILL.md -# Served at https://agentconnect.polygon.technology/SKILL.md — the root -# skill entry point for the agent. -# -# packages/connector-ui/public/skills/ -# Served at https://agentconnect.polygon.technology/skills/ — full tree. -# -# packages/connector-ui/public// -# Also served at https://agentconnect.polygon.technology//SKILL.md -# (e.g. /polygon-discovery/SKILL.md) to match the URLs in the root SKILL.md. -# -# packages/polygon-agent-cli/skills/ -# Bundled inside the published npm package so skills are available -# locally after install. The `name` field in SKILL.md is rewritten from -# `polygon-agent-kit` (monorepo name) to `polygon-agent-cli` (the -# installed skill identifier) to match what Claude Code registers. -# -# DO NOT edit the package copies directly — they will be overwritten. -# Always edit files under skills/ at the repo root. -# ============================================================================= -node -e " -const fs = require('fs'); -const path = require('path'); - -function copyDir(src, dest) { - fs.mkdirSync(dest, { recursive: true }); - for (const entry of fs.readdirSync(src, { withFileTypes: true })) { - const srcPath = path.join(src, entry.name); - const destPath = path.join(dest, entry.name); - if (entry.isDirectory()) { - copyDir(srcPath, destPath); - } else { - fs.copyFileSync(srcPath, destPath); - } - } -} - -// Sync root SKILL.md to connector-ui public root (served at /SKILL.md) -fs.copyFileSync('skills/SKILL.md', 'packages/connector-ui/public/SKILL.md'); - -// Sync to connector-ui (verbatim — full tree under /skills/) -copyDir('skills', 'packages/connector-ui/public/skills'); - -// Also serve each sub-skill at the root level (e.g. /polygon-discovery/SKILL.md) -// to match the URLs referenced in the root SKILL.md -for (const entry of fs.readdirSync('skills', { withFileTypes: true })) { - if (entry.isDirectory()) { - copyDir(path.join('skills', entry.name), path.join('packages/connector-ui/public', entry.name)); - } -} - -// Sync to CLI package (rewrite name field in root SKILL.md only) -copyDir('skills', 'packages/polygon-agent-cli/skills'); -const cliSkill = path.join('packages/polygon-agent-cli/skills/SKILL.md'); -fs.writeFileSync(cliSkill, fs.readFileSync(cliSkill, 'utf8').replace('name: polygon-agent-kit', 'name: polygon-agent-cli')); -" -git add packages/connector-ui/public/SKILL.md packages/connector-ui/public/skills packages/connector-ui/public/polygon-* packages/polygon-agent-cli/skills - pnpm exec lint-staged pnpm run typecheck diff --git a/packages/connector-ui/public/SKILL.md b/packages/connector-ui/public/SKILL.md deleted file mode 100644 index 1d373b2..0000000 --- a/packages/connector-ui/public/SKILL.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -name: Polygon Agent -description: "Complete Polygon agent toolkit for on-chain operations on Polygon. Use this skill whenever helping an agent set up a wallet, check balances, send or swap tokens, bridge assets, deposit or withdraw from yield (Aave aTokens, ERC-4626 vaults), register on-chain identity, submit or query reputation/feedback, or make x402 micropayments. Covers the full lifecycle: Sequence smart contract wallets, Trails DeFi actions, ERC-8004 identity + reputation, x402 payments. Single CLI entry point (`polygon-agent`), AES-256-GCM encrypted storage." ---- - -# Polygon Agentic CLI - -## Prerequisites -- Node.js 20+ -- Install globally: `npm install -g @polygonlabs/agent-cli` (reinstall to update) -- Entry point: `polygon-agent ` -- Storage: `~/.polygon-agent/` (AES-256-GCM encrypted) - -## Architecture - -| Wallet | Created by | Purpose | Fund? | -|--------|-----------|---------|-------| -| EOA | `setup` | Auth with Sequence Builder | NO | -| Ecosystem Wallet | `wallet create` | Primary spending wallet | YES | - -## Environment Variables - -### Access key — auto-loaded, no export needed - -After `setup` runs, the access key is stored in `~/.polygon-agent/builder.json`. The CLI bootstraps it into `SEQUENCE_PROJECT_ACCESS_KEY` and `SEQUENCE_INDEXER_ACCESS_KEY` automatically on every invocation. Trails commands additionally fall back through `session.projectAccessKey` → `SEQUENCE_PROJECT_ACCESS_KEY`, so `TRAILS_API_KEY` also does not need to be exported manually. - -**In a fresh agent session with no environment variables set**, simply run commands — the CLI reads credentials from disk. No `export` step is required between phases. - -Only set these manually to override the stored value (e.g. to point at a different project): -```bash -export SEQUENCE_PROJECT_ACCESS_KEY= -``` - -### Optional overrides -| Variable | Default | -|----------|---------| -| `SEQUENCE_ECOSYSTEM_CONNECTOR_URL` | `https://agentconnect.polygon.technology` | -| `SEQUENCE_DAPP_ORIGIN` | Same as connector URL origin | -| `TRAILS_TOKEN_MAP_JSON` | Token-directory lookup | -| `POLYGON_AGENT_DEBUG_FETCH` | Off — logs HTTP to `~/.polygon-agent/fetch-debug.log` | -| `POLYGON_AGENT_DEBUG_FEE` | Off — dumps fee options to stderr | - -## Complete Setup Flow - -```bash -# Step 1: Setup (creates EOA + Sequence project, stores access key to disk) -polygon-agent setup --name "MyAgent" -# → saves privateKey (not shown again), eoaAddress, accessKey to ~/.polygon-agent/builder.json -# → all subsequent commands auto-load the access key from disk — no export needed - -# Step 2: Create ecosystem wallet (opens browser, waits for 6-digit code) -polygon-agent wallet create --usdc-limit 100 --native-limit 5 -# → opens https://agentconnect.polygon.technology/link?rid=&... -# → user approves in browser, browser shows a 6-digit code -# → enter the 6-digit code in the terminal when prompted -# → session saved to ~/.polygon-agent/wallets/main.json -# → notify the user and send them to https://agentconnect.polygon.technology/?rid= -# so they can fund their wallet with access to the session - -# Step 3: Fund wallet -polygon-agent fund -# → reads walletAddress from session, builds Trails widget URL with toAddress= -# → ALWAYS run this command to get the URL — never construct it manually or hardcode any address -# → send the returned `fundingUrl` to the user; `walletAddress` in the output confirms the recipient - -# Step 4: Verify balances -polygon-agent balances - -# Step 5: Register agent on-chain (ERC-8004, Polygon mainnet only) -polygon-agent agent register --name "MyAgent" --broadcast -# → mints ERC-721 NFT, emits Registered event containing agentId -# → retrieve agentId: open the tx on https://polygonscan.com, go to Logs tab, -# find the Registered event — agentId is the first indexed parameter -# → use agentId for reputation queries, reviews, and feedback -``` - -## Commands Reference - -### Setup -```bash -polygon-agent setup --name [--force] -``` - -### Wallet -Valid `--chain` values: `polygon` (default/mainnet), `amoy` (Polygon testnet), `mainnet` (Ethereum), `arbitrum`, `optimism`, `base`. ERC-8004 agent operations only support `polygon`. - -```bash -polygon-agent wallet create [--name ] [--chain polygon] [--timeout ] [--print-url] - [--native-limit ] [--usdc-limit ] [--usdt-limit ] - [--token-limit ] # repeatable - [--usdc-to --usdc-amount ] # one-off scoped transfer - [--contract ] # whitelist contract (repeatable) -polygon-agent wallet import --code <6-digit-code> --rid [--name ] -polygon-agent wallet import --ciphertext '|@' [--name ] # legacy -polygon-agent wallet list -polygon-agent wallet address [--name ] -polygon-agent wallet remove [--name ] -``` - -### Operations -```bash -polygon-agent balances [--wallet ] [--chain ] [--chains ] -polygon-agent send --to --amount [--symbol ] [--token ] [--decimals ] [--broadcast] -polygon-agent send-native --to --amount [--broadcast] [--direct] -polygon-agent send-token --symbol --to --amount [--token ] [--decimals ] [--broadcast] -polygon-agent swap --from --to --amount [--to-chain ] [--slippage ] [--broadcast] -polygon-agent deposit --asset --amount [--protocol aave|morpho] [--broadcast] -polygon-agent withdraw --position --amount [--chain ] [--broadcast] -polygon-agent fund [--wallet ] [--token ] -polygon-agent x402-pay --url --wallet [--method GET] [--body ] [--header Key:Value] -``` - -### Agent (ERC-8004) -```bash -polygon-agent agent register --name [--agent-uri ] [--metadata ] [--broadcast] -polygon-agent agent wallet --agent-id -polygon-agent agent metadata --agent-id --key -polygon-agent agent reputation --agent-id [--tag1 ] [--tag2 ] -polygon-agent agent reviews --agent-id [--tag1 ] [--tag2 ] [--revoked] -polygon-agent agent feedback --agent-id --value [--tag1 ] [--tag2 ] [--endpoint ] [--feedback-uri ] [--broadcast] -``` - -**ERC-8004 contracts (Polygon mainnet):** -- IdentityRegistry: `0x8004A169FB4a3325136EB29fA0ceB6D2e539a432` -- ReputationRegistry: `0x8004BAa17C55a88189AE136b182e5fdA19dE9b63` - -## Key Behaviors - -- **Dry-run by default** — all write commands require `--broadcast` to execute -- **Smart defaults** — `--wallet main`, `--chain polygon`, auto-wait on `wallet create` -- **`balances --chains`** — comma-separated chains (max 20); two or more return JSON with `multiChain: true` and a `chains` array (same wallet address on each) -- **Fee preference** — auto-selects USDC over native POL when both available -- **`fund`** — reads `walletAddress` from the wallet session and sets it as `toAddress` in the Trails widget URL. Always run `polygon-agent fund` to get the correct URL — never construct it manually or hardcode any address. -- **`deposit`** — picks highest-TVL pool via Trails `getEarnPools`. If session rejects (contract not whitelisted), re-create wallet with `--contract ` -- **`withdraw`** — `--position` = aToken or ERC-4626 vault; `--amount` = `max` or underlying units (Aave / vault). Dry-run JSON includes `poolAddress` / `vault`. Broadcast needs session on the **same chain** as `--chain`, with pool/vault + underlying token whitelisted where the relayer touches them -- **`x402-pay`** — probes endpoint for 402, smart wallet funds builder EOA with exact token amount, EOA signs EIP-3009 payment. Chain auto-detected from 402 response -- **`send-native --direct`** — bypasses ValueForwarder contract for direct EOA transfer -- **Session permissions** — without `--usdc-limit` etc., session gets bare-bones defaults and may not transact -- **Session expiry** — 6 months from creation - -## Wallet Creation Flow (v2 Relay) - -`wallet create` uses a Cloudflare Durable Object relay and a 6-digit out-of-band code — no cloudflared tunnel required. The browser encrypts the approved session with an X25519 key negotiated via the relay; the 6-digit code is the decryption key entered in the terminal. - -**`--print-url` flag:** Use this in headless or non-interactive environments (CI, remote shells) where `wallet create` can't block waiting for the code. The CLI prints the approval URL and exits immediately. Complete the flow separately: -```bash -polygon-agent wallet import --code <6-digit-code> --rid -``` - -## CRITICAL: Wallet Approval URL - -When `wallet create` outputs a URL in the `url` or `approvalUrl` field, send the **complete, untruncated URL** to the user. The URL contains the relay request ID required for session approval. - -- Do NOT shorten, summarize, or add `...` to the URL -- Do NOT split the URL across multiple messages -- Output the raw URL exactly as returned by the CLI - -## Presenting Results to the User - -CLI commands output JSON (non-TTY). After running a command, always render the result as formatted markdown — never paste raw JSON into the conversation. - -| Command | How to present | -|---------|---------------| -| `balances` | Markdown table: Token / Balance columns. Show wallet address and chain above the table. | -| `send` / `send-token` / `send-native` | One-liner summary: amount, symbol, recipient. If broadcast, show tx hash as a code span and explorer URL as a link. | -| `swap` | Summary: `X FROM → Y TO` with chain. If broadcast, show deposit tx hash + explorer link. | -| `deposit` | Summary: amount, asset, protocol, pool address. If broadcast, show tx hash + explorer link. | -| `withdraw` | Summary: `kind` (aave / erc4626), position, amount, pool or vault. If broadcast, show tx hash + explorer link. | -| `fund` | Show the `fundingUrl` as a clickable link with a brief instruction to open it. | -| `wallet create` / `wallet list` | Wallet name, truncated address, chain in a small table or bullet list. | -| `agent register` | Show agent name and tx hash as a code span with Polygonscan link. Remind user to retrieve `agentId` from the Registered event on the Logs tab. | -| `agent wallet` | Show `agentId`, wallet address, and whether a wallet is set. | -| `agent metadata` | Show `agentId`, key, and decoded value. | -| `agent reputation` | Format score and tag breakdown as a small table. | - -**Dry-run results** — always make it visually clear this was a simulation. Prefix with `⚡ Dry run` and show what *would* happen. Remind the user to re-run with `--broadcast` to execute. - -**Errors** — extract the `error` field and present it as a clear sentence, not a JSON blob. Include the relevant fix from the Troubleshooting table if applicable. - ---- - -## Use-Case Skills - -For specific workflows, fetch and load the relevant sub-skill: - -| Use Case | Skill URL | -|----------|-----------| -| Polymarket prediction market trading | https://agentconnect.polygon.technology/polygon-polymarket/SKILL.md | -| DeFi — swap, deposit, withdraw, yield | https://agentconnect.polygon.technology/polygon-defi/SKILL.md | -| x402 discovery & pay-per-call APIs | https://agentconnect.polygon.technology/polygon-discovery/SKILL.md | - ---- - -## Troubleshooting - -| Issue | Fix | -|-------|-----| -| `Builder configured already` | Add `--force` | -| `Missing SEQUENCE_PROJECT_ACCESS_KEY` | Run `setup` first | -| `Missing wallet` | `wallet list`, re-run `wallet create` | -| `Session expired` | Re-run `wallet create` (6-month expiry) | -| `Fee option errors` | Set `POLYGON_AGENT_DEBUG_FEE=1`, ensure wallet has funds | -| `Timed out waiting for wallet approval` | Add `--timeout 600` | -| `Invalid code: hash mismatch` | Wrong 6-digit code entered — retry (3 attempts allowed) | -| `Relay request not found` | Session expired or already used — re-run `wallet create` (or `wallet create --print-url`) | -| Deposit session rejected | Re-create wallet with `--contract ` | -| `withdraw` / broadcast: wrong chain or session rejects | Use `wallet create --chain ` and `--contract` for pool/vault + underlying ERC-20 on that chain; omit tight `--usdc-limit` if it blocks fee transfers | -| `Stored explicit session is missing pk` | Re-link: `wallet import --code …` after `wallet create` | -| Wrong recipient in Trails widget | Run `polygon-agent fund` (do not construct the URL manually) | -| `x402-pay`: no 402 response | Endpoint doesn't require x402 payment, or URL is wrong | -| `x402-pay`: payment token mismatch | Chain/token in the 402 response differs from wallet — check `--wallet` points to the right chain | -| `x402-pay`: EOA funding failed | Wallet lacks sufficient balance to cover the payment amount — run `balances` and fund if needed | - -## File Structure -``` -~/.polygon-agent/ -├── .encryption-key # AES-256-GCM key (auto-generated, 0600) -├── builder.json # EOA privateKey (encrypted), eoaAddress, accessKey, projectId -├── wallets/.json # walletAddress, session, chainId, chain -└── requests/.json # Pending wallet creation requests (deleted after successful import) -``` diff --git a/packages/connector-ui/public/polygon-defi/SKILL.md b/packages/connector-ui/public/polygon-defi/SKILL.md deleted file mode 100644 index 0afcbff..0000000 --- a/packages/connector-ui/public/polygon-defi/SKILL.md +++ /dev/null @@ -1,228 +0,0 @@ ---- -name: polygon-defi -description: DeFi operations on Polygon using the Polygon Agent CLI. Covers same-chain token swaps, cross-chain bridging, and yield deposits into Aave v3 and Morpho vaults via Trails earn pool discovery. All commands dry-run by default — add --broadcast to execute. ---- - -# Polygon DeFi Skill - -## Swap Tokens (Same-Chain) - -```bash -# Dry-run — shows route and output amount -polygon-agent swap --from USDC --to USDT --amount 5 - -# Execute -polygon-agent swap --from USDC --to USDT --amount 5 --broadcast - -# Custom slippage (default 0.5%) -polygon-agent swap --from USDC --to USDT --amount 5 --slippage 0.005 --broadcast -``` - -## Bridge Tokens (Cross-Chain) - -```bash -# Bridge USDC from Polygon to Arbitrum -polygon-agent swap --from USDC --to USDC --amount 0.5 --to-chain arbitrum --broadcast - -# Bridge to other supported chains -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain optimism --broadcast -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain base --broadcast -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain mainnet --broadcast -``` - -Valid `--to-chain` values: `polygon`, `amoy`, `mainnet`, `arbitrum`, `optimism`, `base`. - -## Query Earn Pools - -Use `getEarnPools` to discover live yield opportunities across protocols before deciding where to deposit. - -### HTTP - -```bash -curl --request POST \ - --url https://trails-api.sequence.app/rpc/Trails/GetEarnPools \ - --header 'Content-Type: application/json' \ - --data '{"chainIds": [137]}' -``` - -All request fields are optional — omit any you don't need to filter on. - -| Field | Type | Description | -|-------|------|-------------| -| `chainIds` | `number[]` | Filter by chain (e.g. `[137]` for Polygon mainnet) | -| `protocols` | `string[]` | Filter by protocol name, e.g. `["Aave"]`, `["Morpho"]` | -| `minTvl` | `number` | Minimum TVL in USD | -| `maxApy` | `number` | Maximum APY (useful to exclude outlier/at-risk pools) | - -### Fetch (agent code) - -The API key is the project access key already available to the agent (`SEQUENCE_PROJECT_ACCESS_KEY`). - -```typescript -const res = await fetch('https://trails-api.sequence.app/rpc/Trails/GetEarnPools', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ chainIds: [137] }), -}); -const { pools } = await res.json(); -``` - -### Response Schema - -```typescript -interface GetEarnPoolsResponse { - pools: EarnPool[]; - timestamp: string; // ISO-8601 fetch time - cached: boolean; -} - -interface EarnPool { - id: string; // "{protocol}-{chainId}-{address}" - name: string; // e.g. "USDC Market" - protocol: string; // "Aave" | "Morpho" - chainId: number; - apy: number; // annualised yield as a decimal percent - tvl: number; // USD - token: PoolTokenInfo; - depositAddress: string; // contract to approve/send to - isActive: boolean; - poolUrl?: string; - protocolUrl?: string; - wrappedTokenGatewayAddress?: string; // non-null for Aave native-token markets -} - -interface PoolTokenInfo { - symbol: string; - name: string; - address: string; - decimals: number; - logoUrl?: string; -} -``` - -> **Tip:** `wrappedTokenGatewayAddress` is set on Aave markets that accept a wrapped native token (WPOL, WETH). Pass this address instead of `depositAddress` when depositing POL/ETH directly. - ---- - -## Deposit to Earn Yield - -Pool discovery uses `TrailsApi.getEarnPools` — picks the most liquid pool (highest TVL) for the asset on the current chain. No hardcoded addresses — the pool is resolved at runtime. - -```bash -# Dry-run — shows pool name, APY, TVL, and deposit address before committing -polygon-agent deposit --asset USDC --amount 0.3 - -# Execute — deposits into the highest-TVL active pool -polygon-agent deposit --asset USDC --amount 0.3 --broadcast - -# Filter by protocol -polygon-agent deposit --asset USDC --amount 0.3 --protocol aave --broadcast -polygon-agent deposit --asset USDC --amount 0.3 --protocol morpho --broadcast -``` - -### Supported Protocols - -| Protocol | Encoding | Description | -|----------|----------|-------------| -| **Aave v3** | `supply(asset, amount, onBehalfOf, referralCode)` | Lending pool deposit | -| **Morpho** | `deposit(assets, receiver)` — ERC-4626 | Vault deposit | - -Vault/pool addresses are resolved dynamically from Trails — they are not hardcoded. The dry-run output includes `depositAddress` so you can inspect the exact contract before broadcasting. - -## Withdraw (Aave aToken or ERC-4626 vault) - -Pass the **position token** you hold: an **Aave aToken** address, or a **Morpho / ERC-4626 vault** (share) address. The CLI resolves the Aave **Pool** via `POOL()` on the aToken, or uses `redeem` on the vault. Dry-run by default. - -```bash -# Full exit from an Aave position (aToken from balances output) -polygon-agent withdraw --position 0x68215b6533c47ff9f7125ac95adf00fe4a62f79e --amount max --chain mainnet - -# Partial Aave withdraw (underlying units, e.g. USDC) -polygon-agent withdraw --position --amount 0.5 --chain mainnet --broadcast - -# ERC-4626: max redeems all shares; partial amount is underlying units (convertToShares) -polygon-agent withdraw --position --amount max --chain polygon --broadcast -``` - -Whitelist the **pool** (Aave) or **vault** contract on the session if the wallet rejects the call (`polygon-agent wallet create --contract `). - -**Same chain as the transaction:** if you use `withdraw --chain mainnet`, create or refresh the session with **`wallet create --chain mainnet`** (not only Polygon defaults). Include **`--contract`** for the **pool** and for the **underlying ERC-20** on that chain (e.g. mainnet USDC `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`) so fee / helper transfers are allowed. Tight **`--usdc-limit`** can block those — omit or relax for yield exits. - -### Session Whitelisting - -If the deposit is rejected with a session permission error, the pool's contract address needs to be whitelisted when creating the wallet session: - -```bash -# 1. Dry-run first to get the depositAddress -polygon-agent deposit --asset USDC --amount 0.3 -# → note the depositAddress in output - -# 2. Re-create wallet session with that contract whitelisted -polygon-agent wallet create --contract - -# 3. Retry -polygon-agent deposit --asset USDC --amount 0.3 --broadcast -``` - -When creating a wallet specifically for yield, add `--contract` flags for all intended vaults upfront and omit `--usdc-limit`: - -```bash -polygon-agent wallet create \ - --contract 0x794a61358d6845594f94dc1db02a252b5b4814ad \ - --contract 0x781fb7f6d845e3be129289833b04d43aa8558c42 -``` - -### Yield Vault Contract Whitelist - -#### Polygon Mainnet (chainId 137) - -| Protocol | Asset | Address | -|----------|-------|---------| -| Aave V3 Pool (all markets) | USDC, USDT, WETH, WMATIC… | `0x794a61358d6845594f94dc1db02a252b5b4814ad` | -| Morpho Compound USDC | USDC | `0x781fb7f6d845e3be129289833b04d43aa8558c42` | -| Morpho Compound WETH | WETH | `0xf5c81d25ee174d83f1fd202ca94ae6070d073ccf` | -| Morpho Compound POL | POL | `0x3f33f9f7e2d7cfbcbdf8ea8b870a6e3d449664c2` | - -#### Katana (chainId 747474) — Morpho Vaults - -| Vault | Asset | TVL | Address | -|-------|-------|-----|---------| -| Gauntlet USDT | USDT | ~$97M | `0x1ecdc3f2b5e90bfb55ff45a7476ff98a8957388e` | -| Steakhouse Prime USDC | USDC | ~$54M | `0x61d4f9d3797ba4da152238c53a6f93fb665c3c1d` | -| Yearn OG ETH | WETH | ~$16M | `0xfade0c546f44e33c134c4036207b314ac643dc2e` | -| Yearn OG USDC | USDC | ~$16M | `0xce2b8e464fc7b5e58710c24b7e5ebfb6027f29d7` | -| Gauntlet USDC | USDC | ~$8M | `0xe4248e2105508fcbad3fe95691551d1af14015f7` | -| Yearn OG USDT | USDT | ~$8M | `0x8ed68f91afbe5871dce31ae007a936ebe8511d47` | -| Gauntlet WETH | WETH | ~$6M | `0xc5e7ab07030305fc925175b25b93b285d40dcdff` | -| Hyperithm vbUSDC Apex | USDC | ~$3M | `0xef77f8c53af95f3348cee0fb2a02ee02ab9cdca5` | - ---- - -## Full DeFi Flow Example - -```bash -# 1. Check balances -polygon-agent balances - -# 2. Swap POL → USDC -polygon-agent swap --from POL --to USDC --amount 1 --broadcast - -# 3. Deposit USDC into highest-TVL yield pool -polygon-agent deposit --asset USDC --amount 1 --broadcast -# → protocol: morpho (or aave, whichever has highest TVL at the time) -# → poolApy shown in dry-run output - -# 4. Bridge remaining USDC to Arbitrum -polygon-agent swap --from USDC --to USDC --amount 0.5 --to-chain arbitrum --broadcast -``` - ---- - -## Troubleshooting - -| Error | Cause | Fix | -|-------|-------|-----| -| `Deposit session rejected` | Pool contract not whitelisted in session | Re-create wallet with `--contract ` | -| `Protocol X not yet supported` | Trails returned a protocol other than aave/morpho | Use `polygon-agent swap` to obtain the yield-bearing token manually | -| `Fee option errors` | Wallet has insufficient balance | Run `polygon-agent balances` and fund the wallet | -| `swap`: no route found | Insufficient liquidity for the pair | Try a different amount or token pair | diff --git a/packages/connector-ui/public/polygon-discovery/SKILL.md b/packages/connector-ui/public/polygon-discovery/SKILL.md deleted file mode 100644 index 27509bb..0000000 --- a/packages/connector-ui/public/polygon-discovery/SKILL.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -name: polygon-discovery -description: x402 Bazaar — pay-per-call API services accessible via the Polygon Agent CLI. No API keys or subscriptions needed. Each call costs a small USDC amount drawn from the agent's smart wallet. Covers web search, news, AI image generation, Twitter/X data, code review, text summarization, sentiment analysis, and article extraction. ---- - -# x402 Bazaar Services - -Pay-per-call APIs accessible via `x402-pay`. No API keys or subscriptions — each call costs a small USDC amount drawn from your wallet. The CLI detects the 402 response, funds the exact amount, and retries automatically. - -**Catalog:** `GET https://x402-api.onrender.com/api/catalog?status=online` - ---- - -## Prerequisites — Check Before Any x402 Call - -Before running any `x402-pay` command, verify the wallet session exists and is funded: - -```bash -# Check if a wallet is configured -polygon-agent wallet list -``` - -**If no wallet is listed**, the smart session has not been created. Run through the complete setup flow before proceeding: - -1. `polygon-agent setup --name "MyAgent"` — creates EOA and Sequence project -2. `polygon-agent wallet create --usdc-limit 100` — opens browser for session approval; enter the 6-digit code when prompted -3. `polygon-agent wallet address` — get address, then fund via https://agentconnect.polygon.technology -4. `polygon-agent balances` — confirm USDC is available before calling any x402 endpoint - -**If a wallet exists but `balances` shows 0 USDC**, direct the user to fund it via the UI — `x402-pay` will fail with an EOA funding error otherwise. - -Once a funded wallet is confirmed, proceed with the x402 calls below. - ---- - -## Read Twitter/X Profile - -$0.005 USDC per call. - -> **Note:** The catalog proxy (`/api/call/99063826-...`) returns 401 or HTML for this service. -> Use the direct endpoint below instead. - -```bash -# Profile + recent tweets -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/twitter?user=" \ - --wallet main --method POST - -# Specific tweet -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/twitter?tweet=https://x.com/user/status/" \ - --wallet main --method POST -``` - -Returns: follower/following counts and tweet metrics. - -**Troubleshooting:** If the direct endpoint fails, check the live catalog for the current URL: -```bash -curl -s "https://x402-api.onrender.com/api/catalog?status=online" \ - | jq '.[] | select(.name | test("twitter"; "i"))' -``` - ---- - -## Generate an AI Image - -$0.02 USDC per call. Powered by Google Gemini. - -```bash -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/call/2998d205-94d9-4f7e-8f8a-201a090a5530?prompt=&size=512" \ - --wallet main --method GET -``` - -`size` options: `256`, `512`, `1024`. Returns JSON with `data_uri` (base64 PNG) for embedding. - ---- - -## Review Code for Bugs & Security - -$0.01 USDC per call. Powered by GPT-4o. - -```bash -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/call/7f21e675-9fdc-4ba3-9a8d-145c6ac703c7" \ - --wallet main \ - --body '{"code": "", "language": ""}' -``` - -Returns: bugs, security issues, performance problems, and style suggestions — each with line number, severity, and fix suggestion. Plus an overall quality score. - ---- - -## Other Services - -| Service | Price | Endpoint | Key param | -|---------|-------|----------|-----------| -| Web search (DuckDuckGo) | $0.005 | `9b0f5b5f-8e6c-4b55-a264-008e4e490c26` | `?q=&max=10` | -| Latest news (Google News) | $0.005 | `266d045f-bae2-4c71-9469-3638ec860fc4` | `?topic=&lang=en` | -| Summarize text (GPT-4o-mini) | $0.01 | `dd9b5098-700d-47a9-a41a-c9eae66ca49d` | `?text=&maxLength=200` | -| Article → Markdown | $0.005 | `87b50238-5b99-4521-b5e1-7515a9c1526d` | `?url=` | -| Sentiment analysis (GPT-4o-mini) | $0.005 | `66d68ca6-a8d9-41a3-b024-a3fac2f5c7ba` | `?text=` | - -All use GET via `polygon-agent x402-pay --url "https://x402-api.onrender.com/api/call/" --wallet main --method GET`. - ---- - -## How x402 Works - -1. CLI sends the request to the endpoint -2. Endpoint responds with `HTTP 402 Payment Required` + payment details -3. CLI automatically funds the builder EOA with the exact token amount from the smart wallet -4. EOA signs an EIP-3009 payment authorization -5. CLI retries the original request with the payment header -6. Response is returned — the whole flow is transparent to the agent - -Chain and token are auto-detected from the 402 response. No manual configuration needed. diff --git a/packages/connector-ui/public/polygon-polymarket/SKILL.md b/packages/connector-ui/public/polygon-polymarket/SKILL.md deleted file mode 100644 index 0cac0ff..0000000 --- a/packages/connector-ui/public/polygon-polymarket/SKILL.md +++ /dev/null @@ -1,330 +0,0 @@ ---- -name: polymarket-skill -description: Place bets on Polymarket prediction markets using the Polygon Agent CLI. Browse markets, check prices, buy YES/NO positions, sell positions, manage orders. All commands are JSON output. Dry-run by default — always add --broadcast to execute. ---- - -# Polymarket Skill - -## Session Initialization - -Before any polymarket command, initialize the session. Read `~/.polygon-agent/builder.json` and export the access key: - -```bash -export SEQUENCE_PROJECT_ACCESS_KEY= -export SEQUENCE_INDEXER_ACCESS_KEY=$SEQUENCE_PROJECT_ACCESS_KEY -``` - -Also verify the Polymarket key is set: -```bash -polygon-agent polymarket proxy-wallet -``` -If this returns `ok: true` with an `eoaAddress` and `proxyWalletAddress`, the key is configured. If it errors, the user needs to run `set-key` (see Onboarding below). - ---- - -## Understanding the 3 Addresses - -Every Polymarket user has three addresses. Do not confuse them: - -| Name | What it is | Used for | -|------|-----------|---------| -| EOA | Private key owner. Shown as `eoaAddress` in CLI output | Signs transactions and CLOB orders. Holds POL for gas | -| Proxy Wallet | Shown as `proxyWalletAddress` in CLI output. This is what Polymarket shows as "your address" in the UI | Holds USDC.e and outcome tokens. The CLOB `maker` | -| Deposit Address | A cross-chain bridge ingress — only relevant for bridging from other chains | Ignore for Polygon-native usage | - -**For trading:** funds go from the Sequence smart wallet → proxy wallet → CLOB orders. The proxy wallet is the trading identity. - ---- - -## Onboarding: First-Time Setup - -### Option A — Using email login (Polymarket account) - -If the user has a Polymarket account via email login: - -**Step 1: Get the private key from Polymarket** -``` -1. Go to: https://reveal.magic.link/polymarket -2. Connect/authenticate with the same email used for Polymarket -3. Copy the exported private key (0x...) -``` - -**Step 2: Accept Terms of Service** -``` -1. Go to: https://polymarket.com -2. Connect wallet using the exported private key (import to MetaMask or similar) -3. Accept Terms of Service when prompted - — This is REQUIRED for CLOB order placement. Without it, orders will fail. -``` - -**Step 3: Import the key into the CLI** -```bash -polygon-agent polymarket set-key -``` -Output confirms the `eoaAddress` and `proxyWalletAddress`. - -**Step 3b: Confirm your addresses (show this to the user)** -```bash -polygon-agent polymarket proxy-wallet -``` -**Tell the user:** "Your EOA is `` — this needs POL for gas. Your Polymarket trading address (proxy wallet) is `` — this is where your USDC.e and outcome tokens live. The proxy wallet does not need POL. You must fund the EOA with POL and run approvals before trading." - -**Step 4: Fund the EOA with POL for gas** -```bash -# Check EOA address from set-key output, then send ~0.1 POL to it -polygon-agent send-native --to --amount 0.1 --broadcast -``` - -**Step 5: Set proxy wallet approvals (one-time, permanent)** -```bash -polygon-agent polymarket approve --broadcast -``` -This sends a transaction directly from the EOA (not through Polymarket's UI), so the EOA must hold POL for gas. This is different from trading on polymarket.com, where their UI sponsors gas for you. - -### Option B — Using the builder EOA (no Polymarket account needed) - -If the user has done `polygon-agent setup` already, the builder EOA can be used directly. Skip `set-key`. - -**Step 1: Confirm addresses (show this to the user)** -```bash -polygon-agent polymarket proxy-wallet -``` -**Tell the user:** "Your EOA is `` — this needs POL for gas. Your Polymarket trading address (proxy wallet) is `` — this is where your USDC.e and outcome tokens live. The proxy wallet does not need POL. You must accept Polymarket ToS, fund the EOA with POL, and run approvals before trading." - -**Step 2: Accept Terms of Service (required — CLOB orders will fail without this)** -``` -1. Go to https://polymarket.com -2. Connect with the EOA wallet address shown above -3. Accept Terms of Service when prompted -``` - -**Step 3: Fund the EOA with POL for gas** -```bash -polygon-agent send-native --to --amount 0.1 --broadcast -``` - -**Step 4: Set proxy wallet approvals (one-time)** -```bash -polygon-agent polymarket approve --broadcast -``` -This sends a transaction directly from the EOA (not through Polymarket's UI), so the EOA must hold POL for gas. - ---- - -## Commands - -### Browse Markets - -```bash -# List top markets by volume -polygon-agent polymarket markets - -# Search by keyword -polygon-agent polymarket markets --search "bitcoin" --limit 10 - -# Paginate -polygon-agent polymarket markets --limit 20 --offset 20 -``` - -Key output fields per market: -- `conditionId` — the ID needed for all trading commands -- `question` — what the market is asking -- `yesPrice` / `noPrice` — current probability (0 to 1, e.g. `0.65` = 65%) -- `negRisk` — if `true`, set neg-risk approvals before trading this market -- `endDate` — when the market resolves - -### Get a Single Market - -```bash -polygon-agent polymarket market -``` - -Use this to confirm prices and token IDs before placing an order. - -### Show Proxy Wallet Address - -```bash -polygon-agent polymarket proxy-wallet -``` - -Confirms which EOA and proxy wallet are active. The proxy wallet is where USDC.e and tokens are held. - -### Set Approvals (One-Time) - -```bash -# Standard markets -polygon-agent polymarket approve --broadcast - -# Neg-risk markets (if you see negRisk: true on any market you want to trade) -polygon-agent polymarket approve --neg-risk --broadcast -``` - -Run once per EOA. Permanent on-chain — no need to repeat unless enabling neg-risk. -**Dry-run (no --broadcast) shows what will be approved without executing.** - -### Buy a Position - -```bash -# Dry-run first — always check before executing -polygon-agent polymarket clob-buy YES|NO - -# Execute — funds proxy wallet from smart wallet, then places order -polygon-agent polymarket clob-buy YES|NO --broadcast - -# If proxy wallet already has USDC.e (skip the funding step) -polygon-agent polymarket clob-buy YES|NO --skip-fund --broadcast - -# Limit order — fill only at this price or better -polygon-agent polymarket clob-buy YES --price 0.45 --broadcast -``` - -**How it works:** -1. Smart wallet transfers `usdcAmount` USDC.e to the proxy wallet (Sequence tx, USDC.e fee) -2. Posts CLOB BUY order: maker=proxy wallet, signer=EOA (off-chain, no gas) -3. Tokens arrive in proxy wallet on fill - -**Order types:** -- No `--price`: FOK market order (fill entirely or cancel) -- `--fak`: FAK market order (partial fills allowed) -- `--price 0.x`: GTC limit order (stays open until filled or cancelled) - -**Minimum order size: $1 USDC.** The CLOB rejects marketable BUY orders below $1. If the fund step runs but the order is rejected, the USDC.e stays in the proxy wallet — use `--skip-fund` on the retry. - -### Sell a Position - -```bash -# Dry-run first -polygon-agent polymarket sell YES|NO - -# Execute -polygon-agent polymarket sell YES|NO --broadcast - -# Limit sell -polygon-agent polymarket sell YES --price 0.80 --broadcast -``` - -`` is the number of outcome tokens (not USD). Get share count from `positions`. -Selling is pure off-chain — no gas, no on-chain tx. - -### Check Positions - -```bash -polygon-agent polymarket positions -``` - -Shows all open positions in the proxy wallet with current value, P&L, and outcome. - -### Check Open Orders - -```bash -polygon-agent polymarket orders -``` - -Lists GTC limit orders that are still open (FOK/FAK orders are never "open" — they fill or cancel immediately). - -### Cancel an Order - -```bash -polygon-agent polymarket cancel -``` - -Get `orderId` from the `orders` command or from the `orderId` field in `clob-buy` output. - ---- - -## Full Autonomous Trading Flow - -This is the exact sequence to go from zero to a filled trade: - -```bash -# ── SETUP (run once per EOA) ──────────────────────────────────────────── - -# 1. Import your Polymarket private key -# (get it from https://reveal.magic.link/polymarket after email login) -polygon-agent polymarket set-key 0x -# → save eoaAddress and proxyWalletAddress from output - -# 2. Fund the EOA with POL for gas -polygon-agent send-native --to --amount 0.1 --broadcast - -# 3. Set proxy wallet approvals (one-time) -polygon-agent polymarket approve --broadcast -# → save approveTxHash, wait for confirmation - -# ── FIND A MARKET ──────────────────────────────────────────────────────── - -# 4. Search for markets -polygon-agent polymarket markets --search "fed rate" --limit 10 - -# 5. Get details on a specific market -polygon-agent polymarket market 0x -# → check: yesPrice, noPrice, negRisk, endDate -# → if negRisk: true → run approve --neg-risk --broadcast first - -# ── ENTER A POSITION ──────────────────────────────────────────────────── - -# 6. Dry-run to confirm everything -polygon-agent polymarket clob-buy 0x YES 5 -# → review: currentPrice, proxyWalletAddress, flow - -# 7. Execute -polygon-agent polymarket clob-buy 0x YES 5 --broadcast -# → save orderId, check orderStatus === "matched" - -# ── MANAGE ────────────────────────────────────────────────────────────── - -# 8. Check your positions -polygon-agent polymarket positions -# → review: size (shares), curPrice, cashPnl, title, outcome - -# 9. Sell when ready -polygon-agent polymarket sell 0x YES --broadcast -# → orderStatus === "matched" means USDC.e is back in proxy wallet -``` - ---- - -## Decision Logic for an Autonomous Agent - -When deciding whether to buy: -1. Check `positions` — avoid doubling up on already-held positions -2. Check `markets` — use `yesPrice`/`noPrice` as probability inputs -3. Check `negRisk` — if `true`, verify neg-risk approvals were set -4. Check proxy wallet USDC.e balance before buying (use `proxy-wallet` to get address, then check balance externally or via `balances`) -5. Use `--skip-fund` if the proxy wallet already has enough USDC.e from a previous `clob-buy` -6. Always dry-run first, then broadcast - -When deciding whether to sell: -1. Get current `size` (shares) from `positions` -2. Use `curPrice` vs `avgPrice` to assess profit/loss -3. Market sell (`sell --broadcast`) for immediate exit -4. Limit sell (`--price 0.x --broadcast`) to wait for a better price - ---- - -## Troubleshooting - -| Error | Cause | Fix | -|-------|-------|-----| -| `No EOA key found` | `set-key` not run | Run `polygon-agent polymarket set-key ` | -| `Could not create api key` (stderr) | ToS not accepted | Visit polymarket.com, connect EOA wallet, accept terms. This error in **stderr** is non-fatal — the CLI retries with `deriveApiKey` and may still succeed. | -| `CLOB order error: not authorized` | ToS not accepted | Same as above — fatal for order posting | -| `insufficient funds for gas` | EOA has no POL | `polygon-agent send-native --to --amount 0.1 --broadcast` | -| `execution reverted: must be called be owner` | Old code calling proxy directly | Upgrade CLI — fixed in current version (calls factory) | -| `Market not found` | Low-volume or closed market | Market may have resolved; try `--search` with different terms | -| `Market has no tokenIds` | Closed market | Check `endDate` — market resolved | -| `orderStatus: "unmatched"` on FOK | No liquidity at market price | Try `--fak` for partial fill, or `--price 0.x` for limit order | -| `invalid amount for a marketable BUY order ($X), min size: $1` | Amount below CLOB minimum | Use at least $1. If USDC.e was already funded, retry with `--skip-fund` | -| `Wallet not found: main` | No Sequence wallet | Run `polygon-agent wallet create` | - ---- - -## Key Facts for Agents - -- **All commands are dry-run by default.** `approve`, `clob-buy`, `sell` do nothing without `--broadcast`. -- **`clob-buy` transfers USDC.e from the smart wallet to the proxy wallet automatically** (unless `--skip-fund`). -- **Positions live in the proxy wallet**, not the Sequence smart wallet. `positions` queries the proxy wallet. -- **Approvals are one-time.** Don't run `approve` before every trade — only once per EOA (and once more if enabling neg-risk). -- **Sell is free.** No gas, no on-chain tx. Selling via CLOB is a signed off-chain message only. -- **`orderStatus: "matched"`** means the trade filled. `"unmatched"` means FOK failed (no liquidity). -- **The proxy wallet address never changes.** It is deterministic from the EOA via CREATE2. diff --git a/packages/connector-ui/public/skills/SKILL.md b/packages/connector-ui/public/skills/SKILL.md deleted file mode 100644 index e8feeb8..0000000 --- a/packages/connector-ui/public/skills/SKILL.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -name: Polygon Agent -description: "Complete Polygon agent toolkit for on-chain operations on Polygon. Use this skill whenever helping an agent set up a wallet, check balances, send or swap tokens, bridge assets, deposit or withdraw from yield (Aave aTokens, ERC-4626 vaults), register on-chain identity, submit or query reputation/feedback, or make x402 micropayments. Covers the full lifecycle: Sequence smart contract wallets, Trails DeFi actions, ERC-8004 identity + reputation, x402 payments. Single CLI entry point (`polygon-agent`), AES-256-GCM encrypted storage." ---- - -# Polygon Agentic CLI - -## Prerequisites -- Node.js 20+ -- Install globally: `npm install -g @polygonlabs/agent-cli` (reinstall to update) -- Entry point: `polygon-agent ` -- Storage: `~/.polygon-agent/` (AES-256-GCM encrypted) - -## Architecture - -| Wallet | Created by | Purpose | Fund? | -|--------|-----------|---------|-------| -| EOA | `setup` | Auth with Sequence Builder | NO | -| Ecosystem Wallet | `wallet create` | Primary spending wallet | YES | - -## Environment Variables - -### Access key — one key, many names - -`SEQUENCE_PROJECT_ACCESS_KEY`, `SEQUENCE_INDEXER_ACCESS_KEY`, and `TRAILS_API_KEY` are **all the same key** — the Sequence project access key created during `setup`. The CLI treats them as aliases and falls back through all of them automatically. - -After `setup` runs the key is stored in `~/.polygon-agent/builder.json`. Every CLI invocation bootstraps it into the environment — no `export` is needed. In a fresh agent session with no environment variables set, simply run commands and the CLI reads credentials from disk. - -Only set these manually to override the stored value (e.g. to point at a different project): -```bash -export SEQUENCE_PROJECT_ACCESS_KEY= # also covers TRAILS_API_KEY and indexer calls -``` - -### Optional overrides -| Variable | Default | -|----------|---------| -| `SEQUENCE_ECOSYSTEM_CONNECTOR_URL` | `https://agentconnect.polygon.technology` | -| `SEQUENCE_DAPP_ORIGIN` | Same as connector URL origin | -| `TRAILS_TOKEN_MAP_JSON` | Token-directory lookup | -| `POLYGON_AGENT_DEBUG_FETCH` | Off — logs HTTP to `~/.polygon-agent/fetch-debug.log` | -| `POLYGON_AGENT_DEBUG_FEE` | Off — dumps fee options to stderr | - -## Complete Setup Flow - -```bash -# Step 1: Setup (creates EOA + Sequence project, stores access key to disk) -polygon-agent setup --name "MyAgent" -# → saves privateKey (not shown again), eoaAddress, accessKey to ~/.polygon-agent/builder.json -# → all subsequent commands auto-load the access key from disk — no export needed - -# Step 2: Create ecosystem wallet (opens browser, waits for 6-digit code) -polygon-agent wallet create --usdc-limit 100 --native-limit 5 -# → opens https://agentconnect.polygon.technology/link?rid=&... -# → user approves in browser, browser shows a 6-digit code -# → enter the 6-digit code in the terminal when prompted -# → session saved to ~/.polygon-agent/wallets/main.json -# → notify the user and send them to https://agentconnect.polygon.technology/?rid= -# so they can fund their wallet with access to the session - -# Step 3: Fund wallet -polygon-agent fund -# → reads walletAddress from session, builds Trails widget URL with toAddress= -# → ALWAYS run this command to get the URL — never construct it manually or hardcode any address -# → send the returned `fundingUrl` to the user; `walletAddress` in the output confirms the recipient - -# Step 4: Verify balances -polygon-agent balances - -# Step 5: Register agent on-chain (ERC-8004, Polygon mainnet only) -polygon-agent agent register --name "MyAgent" --broadcast -# → mints ERC-721 NFT, emits Registered event containing agentId -# → retrieve agentId: open the tx on https://polygonscan.com, go to Logs tab, -# find the Registered event — agentId is the first indexed parameter -# → use agentId for reputation queries, reviews, and feedback -``` - -## Commands Reference - -### Setup -```bash -polygon-agent setup --name [--force] -``` - -### Wallet -Valid `--chain` values: `polygon` (default/mainnet), `amoy` (Polygon testnet), `mainnet` (Ethereum), `arbitrum`, `optimism`, `base`. ERC-8004 agent operations only support `polygon`. - -```bash -polygon-agent wallet create [--name ] [--chain polygon] [--timeout ] [--print-url] - [--native-limit ] [--usdc-limit ] [--usdt-limit ] - [--token-limit ] # repeatable - [--usdc-to --usdc-amount ] # one-off scoped transfer - [--contract ] # whitelist contract (repeatable) -polygon-agent wallet import --code <6-digit-code> --rid [--name ] -polygon-agent wallet import --ciphertext '|@' [--name ] # legacy -polygon-agent wallet list -polygon-agent wallet address [--name ] -polygon-agent wallet remove [--name ] -``` - -### Operations -```bash -polygon-agent balances [--wallet ] [--chain ] [--chains ] -polygon-agent send --to --amount [--symbol ] [--token ] [--decimals ] [--broadcast] -polygon-agent send-native --to --amount [--broadcast] [--direct] -polygon-agent send-token --symbol --to --amount [--token ] [--decimals ] [--broadcast] -polygon-agent swap --from --to --amount [--to-chain ] [--slippage ] [--broadcast] -polygon-agent deposit --asset --amount [--protocol aave|morpho] [--broadcast] -polygon-agent withdraw --position --amount [--chain ] [--broadcast] -polygon-agent fund [--wallet ] [--token ] -polygon-agent x402-pay --url --wallet [--method GET] [--body ] [--header Key:Value] -``` - -### Agent (ERC-8004) -```bash -polygon-agent agent register --name [--agent-uri ] [--metadata ] [--broadcast] -polygon-agent agent wallet --agent-id -polygon-agent agent metadata --agent-id --key -polygon-agent agent reputation --agent-id [--tag1 ] [--tag2 ] -polygon-agent agent reviews --agent-id [--tag1 ] [--tag2 ] [--revoked] -polygon-agent agent feedback --agent-id --value [--tag1 ] [--tag2 ] [--endpoint ] [--feedback-uri ] [--broadcast] -``` - -**ERC-8004 contracts (Polygon mainnet):** -- IdentityRegistry: `0x8004A169FB4a3325136EB29fA0ceB6D2e539a432` -- ReputationRegistry: `0x8004BAa17C55a88189AE136b182e5fdA19dE9b63` - -## Key Behaviors - -- **Dry-run by default** — all write commands require `--broadcast` to execute -- **Smart defaults** — `--wallet main`, `--chain polygon`, auto-wait on `wallet create` -- **`balances --chains`** — comma-separated chains (max 20); two or more return JSON with `multiChain: true` and a `chains` array (same wallet address on each) -- **Fee preference** — auto-selects USDC over native POL when both available -- **`fund`** — reads `walletAddress` from the wallet session and sets it as `toAddress` in the Trails widget URL. Always run `polygon-agent fund` to get the correct URL — never construct it manually or hardcode any address. -- **`deposit`** — picks highest-TVL pool via Trails `getEarnPools`. If session rejects (contract not whitelisted), re-create wallet with `--contract ` -- **`withdraw`** — `--position` = aToken or ERC-4626 vault; `--amount` = `max` or underlying units (Aave / vault). Dry-run JSON includes `poolAddress` / `vault`. Broadcast needs session on the **same chain** as `--chain`, with pool/vault + underlying token whitelisted where the relayer touches them -- **`x402-pay`** — probes endpoint for 402, smart wallet funds builder EOA with exact token amount, EOA signs EIP-3009 payment. Chain auto-detected from 402 response -- **`send-native --direct`** — bypasses ValueForwarder contract for direct EOA transfer -- **Session permissions** — without `--usdc-limit` etc., session gets bare-bones defaults and may not transact -- **Session expiry** — 6 months from creation - -## Wallet Creation Flow (v2 Relay) - -`wallet create` uses a Cloudflare Durable Object relay and a 6-digit out-of-band code — no cloudflared tunnel required. The browser encrypts the approved session with an X25519 key negotiated via the relay; the 6-digit code is the decryption key entered in the terminal. - -**`--print-url` flag:** Use this in headless or non-interactive environments (CI, remote shells) where `wallet create` can't block waiting for the code. The CLI prints the approval URL and exits immediately. Complete the flow separately: -```bash -polygon-agent wallet import --code <6-digit-code> --rid -``` - -## CRITICAL: Wallet Approval URL - -When `wallet create` outputs a URL in the `url` or `approvalUrl` field, send the **complete, untruncated URL** to the user. The URL contains the relay request ID required for session approval. - -- Do NOT shorten, summarize, or add `...` to the URL -- Do NOT split the URL across multiple messages -- Output the raw URL exactly as returned by the CLI - -## Presenting Results to the User - -CLI commands output JSON (non-TTY). After running a command, always render the result as formatted markdown — never paste raw JSON into the conversation. - -| Command | How to present | -|---------|---------------| -| `balances` | Markdown table: Token / Balance columns. Show wallet address and chain above the table. | -| `send` / `send-token` / `send-native` | One-liner summary: amount, symbol, recipient. If broadcast, show tx hash as a code span and explorer URL as a link. | -| `swap` | Summary: `X FROM → Y TO` with chain. If broadcast, show deposit tx hash + explorer link. | -| `deposit` | Summary: amount, asset, protocol, pool address. If broadcast, show tx hash + explorer link. | -| `withdraw` | Summary: `kind` (aave / erc4626), position, amount, pool or vault. If broadcast, show tx hash + explorer link. | -| `fund` | Show the `fundingUrl` as a clickable link with a brief instruction to open it. | -| `wallet create` / `wallet list` | Wallet name, truncated address, chain in a small table or bullet list. | -| `agent register` | Show agent name and tx hash as a code span with Polygonscan link. Remind user to retrieve `agentId` from the Registered event on the Logs tab. | -| `agent wallet` | Show `agentId`, wallet address, and whether a wallet is set. | -| `agent metadata` | Show `agentId`, key, and decoded value. | -| `agent reputation` | Format score and tag breakdown as a small table. | - -**Dry-run results** — always make it visually clear this was a simulation. Prefix with `⚡ Dry run` and show what *would* happen. Remind the user to re-run with `--broadcast` to execute. - -**Errors** — extract the `error` field and present it as a clear sentence, not a JSON blob. Include the relevant fix from the Troubleshooting table if applicable. - ---- - -## Use-Case Skills - -For specific workflows, fetch and load the relevant sub-skill: - -| Use Case | Skill URL | -|----------|-----------| -| Polymarket prediction market trading | https://agentconnect.polygon.technology/polygon-polymarket/SKILL.md | -| DeFi — swap, deposit, withdraw, yield | https://agentconnect.polygon.technology/polygon-defi/SKILL.md | -| x402 discovery & pay-per-call APIs | https://agentconnect.polygon.technology/polygon-discovery/SKILL.md | - ---- - -## Troubleshooting - -| Issue | Fix | -|-------|-----| -| `Builder configured already` | Add `--force` | -| `Missing SEQUENCE_PROJECT_ACCESS_KEY` | Run `setup` first | -| `Missing wallet` | `wallet list`, re-run `wallet create` | -| `Session expired` | Re-run `wallet create` (6-month expiry) | -| `Fee option errors` | Set `POLYGON_AGENT_DEBUG_FEE=1`, ensure wallet has funds | -| `Timed out waiting for wallet approval` | Add `--timeout 600` | -| `Invalid code: hash mismatch` | Wrong 6-digit code entered — retry (3 attempts allowed) | -| `Relay request not found` | Session expired or already used — re-run `wallet create` (or `wallet create --print-url`) | -| Deposit session rejected | Re-create wallet with `--contract --contract ` (both required: token approve + pool call) | -| Wrong recipient in Trails widget | Run `polygon-agent fund` (do not construct the URL manually) | -| `x402-pay`: no 402 response | Endpoint doesn't require x402 payment, or URL is wrong | -| `x402-pay`: payment token mismatch | Chain/token in the 402 response differs from wallet — check `--wallet` points to the right chain | -| `x402-pay`: EOA funding failed | Wallet lacks sufficient balance to cover the payment amount — run `balances` and fund if needed | - -## File Structure -``` -~/.polygon-agent/ -├── .encryption-key # AES-256-GCM key (auto-generated, 0600) -├── builder.json # EOA privateKey (encrypted), eoaAddress, accessKey, projectId -├── wallets/.json # walletAddress, session, chainId, chain -└── requests/.json # Pending wallet creation requests (deleted after successful import) -``` diff --git a/packages/connector-ui/public/skills/polygon-defi/SKILL.md b/packages/connector-ui/public/skills/polygon-defi/SKILL.md deleted file mode 100644 index 3d9dc9f..0000000 --- a/packages/connector-ui/public/skills/polygon-defi/SKILL.md +++ /dev/null @@ -1,229 +0,0 @@ ---- -name: polygon-defi -description: DeFi operations on Polygon using the Polygon Agent CLI. Covers same-chain token swaps, cross-chain bridging, and yield deposits into Aave v3 and Morpho vaults via Trails earn pool discovery. All commands dry-run by default — add --broadcast to execute. ---- - -# Polygon DeFi Skill - -## Swap Tokens (Same-Chain) - -```bash -# Dry-run — shows route and output amount -polygon-agent swap --from USDC --to USDT --amount 5 - -# Execute -polygon-agent swap --from USDC --to USDT --amount 5 --broadcast - -# Custom slippage (default 0.5%) -polygon-agent swap --from USDC --to USDT --amount 5 --slippage 0.005 --broadcast -``` - -## Bridge Tokens (Cross-Chain) - -```bash -# Bridge USDC from Polygon to Arbitrum -polygon-agent swap --from USDC --to USDC --amount 0.5 --to-chain arbitrum --broadcast - -# Bridge to other supported chains -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain optimism --broadcast -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain base --broadcast -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain mainnet --broadcast -``` - -Valid `--to-chain` values: `polygon`, `amoy`, `mainnet`, `arbitrum`, `optimism`, `base`. - -## Query Earn Pools - -Use `getEarnPools` to discover live yield opportunities across protocols before deciding where to deposit. - -### HTTP - -```bash -curl --request POST \ - --url https://trails-api.sequence.app/rpc/Trails/GetEarnPools \ - --header 'Content-Type: application/json' \ - --data '{"chainIds": [137]}' -``` - -All request fields are optional — omit any you don't need to filter on. - -| Field | Type | Description | -|-------|------|-------------| -| `chainIds` | `number[]` | Filter by chain (e.g. `[137]` for Polygon mainnet) | -| `protocols` | `string[]` | Filter by protocol name, e.g. `["Aave"]`, `["Morpho"]` | -| `minTvl` | `number` | Minimum TVL in USD | -| `maxApy` | `number` | Maximum APY (useful to exclude outlier/at-risk pools) | - -### Fetch (agent code) - -The API key is the project access key already available to the agent (`SEQUENCE_PROJECT_ACCESS_KEY`). - -```typescript -const res = await fetch('https://trails-api.sequence.app/rpc/Trails/GetEarnPools', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ chainIds: [137] }), -}); -const { pools } = await res.json(); -``` - -### Response Schema - -```typescript -interface GetEarnPoolsResponse { - pools: EarnPool[]; - timestamp: string; // ISO-8601 fetch time - cached: boolean; -} - -interface EarnPool { - id: string; // "{protocol}-{chainId}-{address}" - name: string; // e.g. "USDC Market" - protocol: string; // "Aave" | "Morpho" - chainId: number; - apy: number; // annualised yield as a decimal percent - tvl: number; // USD - token: PoolTokenInfo; - depositAddress: string; // contract to approve/send to - isActive: boolean; - poolUrl?: string; - protocolUrl?: string; - wrappedTokenGatewayAddress?: string; // non-null for Aave native-token markets -} - -interface PoolTokenInfo { - symbol: string; - name: string; - address: string; - decimals: number; - logoUrl?: string; -} -``` - -> **Tip:** `wrappedTokenGatewayAddress` is set on Aave markets that accept a wrapped native token (WPOL, WETH). Pass this address instead of `depositAddress` when depositing POL/ETH directly. - ---- - -## Deposit to Earn Yield - -Pool discovery uses `TrailsApi.getEarnPools` — picks the most liquid pool (highest TVL) for the asset on the current chain. No hardcoded addresses — the pool is resolved at runtime. - -**Note on Morpho Vaults:** -Trails categorizes Morpho vaults by their *receipt* token symbol (e.g., `STEAKUSDC` or `gtUSDCp`), rather than the underlying token. To deposit into a Morpho vault, you must provide the vault's exact receipt token symbol as the `--asset`. -If you try to deposit using `--asset USDC`, it may fail to find the pool. In those cases, you can use the `swap` command to swap `USDC` directly for the vault's receipt token address. - -```bash -# Dry-run — shows pool name, APY, TVL, and deposit address before committing -polygon-agent deposit --asset STEAKUSDC --amount 0.3 --protocol morpho - -# Execute — deposits into the highest-TVL active pool -polygon-agent deposit --asset STEAKUSDC --amount 0.3 --protocol morpho --broadcast - -# Filter by protocol (Aave uses the underlying asset name) -polygon-agent deposit --asset USDC --amount 0.3 --protocol aave --broadcast -``` - -### Supported Protocols - -| Protocol | Encoding | Description | -|----------|----------|-------------| -| **Aave v3** | `supply(asset, amount, onBehalfOf, referralCode)` | Lending pool deposit | -| **Morpho** | `deposit(assets, receiver)` — ERC-4626 | Vault deposit | - -Vault/pool addresses are resolved dynamically from Trails — they are not hardcoded. The dry-run output includes `depositAddress` so you can inspect the exact contract before broadcasting. - -## Withdraw (Aave aToken or ERC-4626 vault) - -Pass the **position token** you hold: an **Aave aToken** address, or a **Morpho / ERC-4626 vault** (share) address. The CLI resolves the Aave **Pool** via `POOL()` on the aToken, or uses `redeem` on the vault. Dry-run by default. - -```bash -# Full exit from an Aave position (aToken from balances output) -polygon-agent withdraw --position 0x68215b6533c47ff9f7125ac95adf00fe4a62f79e --amount max --chain mainnet - -# Partial Aave withdraw (underlying units, e.g. USDC) -polygon-agent withdraw --position --amount 0.5 --chain mainnet --broadcast - -# ERC-4626: max redeems all shares; partial amount is underlying units (convertToShares) -polygon-agent withdraw --position --amount max --chain polygon --broadcast -``` - -Whitelist the **pool** (Aave) or **vault** contract on the session if the wallet rejects the call (`polygon-agent wallet create --contract `). - -**Same chain as the transaction:** if you use `withdraw --chain mainnet`, create or refresh the session with **`wallet create --chain mainnet`** (not only Polygon defaults). Include **`--contract`** for the **pool** and for the **underlying ERC-20** on that chain (e.g. mainnet USDC `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`) so fee / helper transfers are allowed. Tight **`--usdc-limit`** can block those — omit or relax for yield exits. - -### Session Whitelisting - -A deposit sends **two transactions**: an ERC-20 `approve()` on the token contract, then the pool deposit call. Both contracts must be whitelisted in the session. If the deposit is rejected with a session permission error: - -```bash -# 1. Dry-run first — output includes both addresses under `transactions[0].to` (token) and `depositAddress` (pool) -polygon-agent deposit --asset USDC --amount 0.3 -# → note the token contract address (e.g. USDC: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359) -# → note the depositAddress (e.g. Aave V3: 0x794a61358d6845594f94dc1db02a252b5b4814ad) - -# 2. Re-create wallet session with BOTH contracts whitelisted -polygon-agent wallet create --contract --contract - -# 3. Retry -polygon-agent deposit --asset USDC --amount 0.3 --broadcast -``` - -Common token contracts on Polygon mainnet (already auto-whitelisted in sessions created by the CLI): -- USDC: `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` -- USDT: `0xc2132D05D31c914a87C6611C10748AEb04B58e8F` -- WETH: `0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619` - -### Yield Vault Contract Whitelist - -#### Polygon Mainnet (chainId 137) - -| Protocol | Asset | Address | -|----------|-------|---------| -| Aave V3 Pool (all markets) | USDC, USDT, WETH, WMATIC… | `0x794a61358d6845594f94dc1db02a252b5b4814ad` | -| Morpho Compound USDC | USDC | `0x781fb7f6d845e3be129289833b04d43aa8558c42` | -| Morpho Compound WETH | WETH | `0xf5c81d25ee174d83f1fd202ca94ae6070d073ccf` | -| Morpho Compound POL | POL | `0x3f33f9f7e2d7cfbcbdf8ea8b870a6e3d449664c2` | - -#### Katana (chainId 747474) — Morpho Vaults - -| Vault | Asset | TVL | Address | -|-------|-------|-----|---------| -| Gauntlet USDT | USDT | ~$97M | `0x1ecdc3f2b5e90bfb55ff45a7476ff98a8957388e` | -| Steakhouse Prime USDC | USDC | ~$54M | `0x61d4f9d3797ba4da152238c53a6f93fb665c3c1d` | -| Yearn OG ETH | WETH | ~$16M | `0xfade0c546f44e33c134c4036207b314ac643dc2e` | -| Yearn OG USDC | USDC | ~$16M | `0xce2b8e464fc7b5e58710c24b7e5ebfb6027f29d7` | -| Gauntlet USDC | USDC | ~$8M | `0xe4248e2105508fcbad3fe95691551d1af14015f7` | -| Yearn OG USDT | USDT | ~$8M | `0x8ed68f91afbe5871dce31ae007a936ebe8511d47` | -| Gauntlet WETH | WETH | ~$6M | `0xc5e7ab07030305fc925175b25b93b285d40dcdff` | -| Hyperithm vbUSDC Apex | USDC | ~$3M | `0xef77f8c53af95f3348cee0fb2a02ee02ab9cdca5` | - ---- - -## Full DeFi Flow Example - -```bash -# 1. Check balances -polygon-agent balances - -# 2. Swap POL → USDC -polygon-agent swap --from POL --to USDC --amount 1 --broadcast - -# 3. Deposit USDC into highest-TVL yield pool -polygon-agent deposit --asset USDC --amount 1 --broadcast -# → protocol: morpho (or aave, whichever has highest TVL at the time) -# → poolApy shown in dry-run output - -# 4. Bridge remaining USDC to Arbitrum -polygon-agent swap --from USDC --to USDC --amount 0.5 --to-chain arbitrum --broadcast -``` - ---- - -## Troubleshooting - -| Error | Cause | Fix | -|-------|-------|-----| -| `Deposit session rejected` | Pool or token contract not whitelisted | Re-create wallet with `--contract --contract ` (both required) | -| `Protocol X not yet supported` | Trails returned a protocol other than aave/morpho | Use `polygon-agent swap` to obtain the yield-bearing token manually | -| `Fee option errors` | Wallet has insufficient balance | Run `polygon-agent balances` and fund the wallet | -| `swap`: no route found | Insufficient liquidity for the pair | Try a different amount or token pair | diff --git a/packages/connector-ui/public/skills/polygon-discovery/SKILL.md b/packages/connector-ui/public/skills/polygon-discovery/SKILL.md deleted file mode 100644 index 27509bb..0000000 --- a/packages/connector-ui/public/skills/polygon-discovery/SKILL.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -name: polygon-discovery -description: x402 Bazaar — pay-per-call API services accessible via the Polygon Agent CLI. No API keys or subscriptions needed. Each call costs a small USDC amount drawn from the agent's smart wallet. Covers web search, news, AI image generation, Twitter/X data, code review, text summarization, sentiment analysis, and article extraction. ---- - -# x402 Bazaar Services - -Pay-per-call APIs accessible via `x402-pay`. No API keys or subscriptions — each call costs a small USDC amount drawn from your wallet. The CLI detects the 402 response, funds the exact amount, and retries automatically. - -**Catalog:** `GET https://x402-api.onrender.com/api/catalog?status=online` - ---- - -## Prerequisites — Check Before Any x402 Call - -Before running any `x402-pay` command, verify the wallet session exists and is funded: - -```bash -# Check if a wallet is configured -polygon-agent wallet list -``` - -**If no wallet is listed**, the smart session has not been created. Run through the complete setup flow before proceeding: - -1. `polygon-agent setup --name "MyAgent"` — creates EOA and Sequence project -2. `polygon-agent wallet create --usdc-limit 100` — opens browser for session approval; enter the 6-digit code when prompted -3. `polygon-agent wallet address` — get address, then fund via https://agentconnect.polygon.technology -4. `polygon-agent balances` — confirm USDC is available before calling any x402 endpoint - -**If a wallet exists but `balances` shows 0 USDC**, direct the user to fund it via the UI — `x402-pay` will fail with an EOA funding error otherwise. - -Once a funded wallet is confirmed, proceed with the x402 calls below. - ---- - -## Read Twitter/X Profile - -$0.005 USDC per call. - -> **Note:** The catalog proxy (`/api/call/99063826-...`) returns 401 or HTML for this service. -> Use the direct endpoint below instead. - -```bash -# Profile + recent tweets -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/twitter?user=" \ - --wallet main --method POST - -# Specific tweet -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/twitter?tweet=https://x.com/user/status/" \ - --wallet main --method POST -``` - -Returns: follower/following counts and tweet metrics. - -**Troubleshooting:** If the direct endpoint fails, check the live catalog for the current URL: -```bash -curl -s "https://x402-api.onrender.com/api/catalog?status=online" \ - | jq '.[] | select(.name | test("twitter"; "i"))' -``` - ---- - -## Generate an AI Image - -$0.02 USDC per call. Powered by Google Gemini. - -```bash -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/call/2998d205-94d9-4f7e-8f8a-201a090a5530?prompt=&size=512" \ - --wallet main --method GET -``` - -`size` options: `256`, `512`, `1024`. Returns JSON with `data_uri` (base64 PNG) for embedding. - ---- - -## Review Code for Bugs & Security - -$0.01 USDC per call. Powered by GPT-4o. - -```bash -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/call/7f21e675-9fdc-4ba3-9a8d-145c6ac703c7" \ - --wallet main \ - --body '{"code": "", "language": ""}' -``` - -Returns: bugs, security issues, performance problems, and style suggestions — each with line number, severity, and fix suggestion. Plus an overall quality score. - ---- - -## Other Services - -| Service | Price | Endpoint | Key param | -|---------|-------|----------|-----------| -| Web search (DuckDuckGo) | $0.005 | `9b0f5b5f-8e6c-4b55-a264-008e4e490c26` | `?q=&max=10` | -| Latest news (Google News) | $0.005 | `266d045f-bae2-4c71-9469-3638ec860fc4` | `?topic=&lang=en` | -| Summarize text (GPT-4o-mini) | $0.01 | `dd9b5098-700d-47a9-a41a-c9eae66ca49d` | `?text=&maxLength=200` | -| Article → Markdown | $0.005 | `87b50238-5b99-4521-b5e1-7515a9c1526d` | `?url=` | -| Sentiment analysis (GPT-4o-mini) | $0.005 | `66d68ca6-a8d9-41a3-b024-a3fac2f5c7ba` | `?text=` | - -All use GET via `polygon-agent x402-pay --url "https://x402-api.onrender.com/api/call/" --wallet main --method GET`. - ---- - -## How x402 Works - -1. CLI sends the request to the endpoint -2. Endpoint responds with `HTTP 402 Payment Required` + payment details -3. CLI automatically funds the builder EOA with the exact token amount from the smart wallet -4. EOA signs an EIP-3009 payment authorization -5. CLI retries the original request with the payment header -6. Response is returned — the whole flow is transparent to the agent - -Chain and token are auto-detected from the 402 response. No manual configuration needed. diff --git a/packages/connector-ui/public/skills/polygon-polymarket/SKILL.md b/packages/connector-ui/public/skills/polygon-polymarket/SKILL.md deleted file mode 100644 index 0cac0ff..0000000 --- a/packages/connector-ui/public/skills/polygon-polymarket/SKILL.md +++ /dev/null @@ -1,330 +0,0 @@ ---- -name: polymarket-skill -description: Place bets on Polymarket prediction markets using the Polygon Agent CLI. Browse markets, check prices, buy YES/NO positions, sell positions, manage orders. All commands are JSON output. Dry-run by default — always add --broadcast to execute. ---- - -# Polymarket Skill - -## Session Initialization - -Before any polymarket command, initialize the session. Read `~/.polygon-agent/builder.json` and export the access key: - -```bash -export SEQUENCE_PROJECT_ACCESS_KEY= -export SEQUENCE_INDEXER_ACCESS_KEY=$SEQUENCE_PROJECT_ACCESS_KEY -``` - -Also verify the Polymarket key is set: -```bash -polygon-agent polymarket proxy-wallet -``` -If this returns `ok: true` with an `eoaAddress` and `proxyWalletAddress`, the key is configured. If it errors, the user needs to run `set-key` (see Onboarding below). - ---- - -## Understanding the 3 Addresses - -Every Polymarket user has three addresses. Do not confuse them: - -| Name | What it is | Used for | -|------|-----------|---------| -| EOA | Private key owner. Shown as `eoaAddress` in CLI output | Signs transactions and CLOB orders. Holds POL for gas | -| Proxy Wallet | Shown as `proxyWalletAddress` in CLI output. This is what Polymarket shows as "your address" in the UI | Holds USDC.e and outcome tokens. The CLOB `maker` | -| Deposit Address | A cross-chain bridge ingress — only relevant for bridging from other chains | Ignore for Polygon-native usage | - -**For trading:** funds go from the Sequence smart wallet → proxy wallet → CLOB orders. The proxy wallet is the trading identity. - ---- - -## Onboarding: First-Time Setup - -### Option A — Using email login (Polymarket account) - -If the user has a Polymarket account via email login: - -**Step 1: Get the private key from Polymarket** -``` -1. Go to: https://reveal.magic.link/polymarket -2. Connect/authenticate with the same email used for Polymarket -3. Copy the exported private key (0x...) -``` - -**Step 2: Accept Terms of Service** -``` -1. Go to: https://polymarket.com -2. Connect wallet using the exported private key (import to MetaMask or similar) -3. Accept Terms of Service when prompted - — This is REQUIRED for CLOB order placement. Without it, orders will fail. -``` - -**Step 3: Import the key into the CLI** -```bash -polygon-agent polymarket set-key -``` -Output confirms the `eoaAddress` and `proxyWalletAddress`. - -**Step 3b: Confirm your addresses (show this to the user)** -```bash -polygon-agent polymarket proxy-wallet -``` -**Tell the user:** "Your EOA is `` — this needs POL for gas. Your Polymarket trading address (proxy wallet) is `` — this is where your USDC.e and outcome tokens live. The proxy wallet does not need POL. You must fund the EOA with POL and run approvals before trading." - -**Step 4: Fund the EOA with POL for gas** -```bash -# Check EOA address from set-key output, then send ~0.1 POL to it -polygon-agent send-native --to --amount 0.1 --broadcast -``` - -**Step 5: Set proxy wallet approvals (one-time, permanent)** -```bash -polygon-agent polymarket approve --broadcast -``` -This sends a transaction directly from the EOA (not through Polymarket's UI), so the EOA must hold POL for gas. This is different from trading on polymarket.com, where their UI sponsors gas for you. - -### Option B — Using the builder EOA (no Polymarket account needed) - -If the user has done `polygon-agent setup` already, the builder EOA can be used directly. Skip `set-key`. - -**Step 1: Confirm addresses (show this to the user)** -```bash -polygon-agent polymarket proxy-wallet -``` -**Tell the user:** "Your EOA is `` — this needs POL for gas. Your Polymarket trading address (proxy wallet) is `` — this is where your USDC.e and outcome tokens live. The proxy wallet does not need POL. You must accept Polymarket ToS, fund the EOA with POL, and run approvals before trading." - -**Step 2: Accept Terms of Service (required — CLOB orders will fail without this)** -``` -1. Go to https://polymarket.com -2. Connect with the EOA wallet address shown above -3. Accept Terms of Service when prompted -``` - -**Step 3: Fund the EOA with POL for gas** -```bash -polygon-agent send-native --to --amount 0.1 --broadcast -``` - -**Step 4: Set proxy wallet approvals (one-time)** -```bash -polygon-agent polymarket approve --broadcast -``` -This sends a transaction directly from the EOA (not through Polymarket's UI), so the EOA must hold POL for gas. - ---- - -## Commands - -### Browse Markets - -```bash -# List top markets by volume -polygon-agent polymarket markets - -# Search by keyword -polygon-agent polymarket markets --search "bitcoin" --limit 10 - -# Paginate -polygon-agent polymarket markets --limit 20 --offset 20 -``` - -Key output fields per market: -- `conditionId` — the ID needed for all trading commands -- `question` — what the market is asking -- `yesPrice` / `noPrice` — current probability (0 to 1, e.g. `0.65` = 65%) -- `negRisk` — if `true`, set neg-risk approvals before trading this market -- `endDate` — when the market resolves - -### Get a Single Market - -```bash -polygon-agent polymarket market -``` - -Use this to confirm prices and token IDs before placing an order. - -### Show Proxy Wallet Address - -```bash -polygon-agent polymarket proxy-wallet -``` - -Confirms which EOA and proxy wallet are active. The proxy wallet is where USDC.e and tokens are held. - -### Set Approvals (One-Time) - -```bash -# Standard markets -polygon-agent polymarket approve --broadcast - -# Neg-risk markets (if you see negRisk: true on any market you want to trade) -polygon-agent polymarket approve --neg-risk --broadcast -``` - -Run once per EOA. Permanent on-chain — no need to repeat unless enabling neg-risk. -**Dry-run (no --broadcast) shows what will be approved without executing.** - -### Buy a Position - -```bash -# Dry-run first — always check before executing -polygon-agent polymarket clob-buy YES|NO - -# Execute — funds proxy wallet from smart wallet, then places order -polygon-agent polymarket clob-buy YES|NO --broadcast - -# If proxy wallet already has USDC.e (skip the funding step) -polygon-agent polymarket clob-buy YES|NO --skip-fund --broadcast - -# Limit order — fill only at this price or better -polygon-agent polymarket clob-buy YES --price 0.45 --broadcast -``` - -**How it works:** -1. Smart wallet transfers `usdcAmount` USDC.e to the proxy wallet (Sequence tx, USDC.e fee) -2. Posts CLOB BUY order: maker=proxy wallet, signer=EOA (off-chain, no gas) -3. Tokens arrive in proxy wallet on fill - -**Order types:** -- No `--price`: FOK market order (fill entirely or cancel) -- `--fak`: FAK market order (partial fills allowed) -- `--price 0.x`: GTC limit order (stays open until filled or cancelled) - -**Minimum order size: $1 USDC.** The CLOB rejects marketable BUY orders below $1. If the fund step runs but the order is rejected, the USDC.e stays in the proxy wallet — use `--skip-fund` on the retry. - -### Sell a Position - -```bash -# Dry-run first -polygon-agent polymarket sell YES|NO - -# Execute -polygon-agent polymarket sell YES|NO --broadcast - -# Limit sell -polygon-agent polymarket sell YES --price 0.80 --broadcast -``` - -`` is the number of outcome tokens (not USD). Get share count from `positions`. -Selling is pure off-chain — no gas, no on-chain tx. - -### Check Positions - -```bash -polygon-agent polymarket positions -``` - -Shows all open positions in the proxy wallet with current value, P&L, and outcome. - -### Check Open Orders - -```bash -polygon-agent polymarket orders -``` - -Lists GTC limit orders that are still open (FOK/FAK orders are never "open" — they fill or cancel immediately). - -### Cancel an Order - -```bash -polygon-agent polymarket cancel -``` - -Get `orderId` from the `orders` command or from the `orderId` field in `clob-buy` output. - ---- - -## Full Autonomous Trading Flow - -This is the exact sequence to go from zero to a filled trade: - -```bash -# ── SETUP (run once per EOA) ──────────────────────────────────────────── - -# 1. Import your Polymarket private key -# (get it from https://reveal.magic.link/polymarket after email login) -polygon-agent polymarket set-key 0x -# → save eoaAddress and proxyWalletAddress from output - -# 2. Fund the EOA with POL for gas -polygon-agent send-native --to --amount 0.1 --broadcast - -# 3. Set proxy wallet approvals (one-time) -polygon-agent polymarket approve --broadcast -# → save approveTxHash, wait for confirmation - -# ── FIND A MARKET ──────────────────────────────────────────────────────── - -# 4. Search for markets -polygon-agent polymarket markets --search "fed rate" --limit 10 - -# 5. Get details on a specific market -polygon-agent polymarket market 0x -# → check: yesPrice, noPrice, negRisk, endDate -# → if negRisk: true → run approve --neg-risk --broadcast first - -# ── ENTER A POSITION ──────────────────────────────────────────────────── - -# 6. Dry-run to confirm everything -polygon-agent polymarket clob-buy 0x YES 5 -# → review: currentPrice, proxyWalletAddress, flow - -# 7. Execute -polygon-agent polymarket clob-buy 0x YES 5 --broadcast -# → save orderId, check orderStatus === "matched" - -# ── MANAGE ────────────────────────────────────────────────────────────── - -# 8. Check your positions -polygon-agent polymarket positions -# → review: size (shares), curPrice, cashPnl, title, outcome - -# 9. Sell when ready -polygon-agent polymarket sell 0x YES --broadcast -# → orderStatus === "matched" means USDC.e is back in proxy wallet -``` - ---- - -## Decision Logic for an Autonomous Agent - -When deciding whether to buy: -1. Check `positions` — avoid doubling up on already-held positions -2. Check `markets` — use `yesPrice`/`noPrice` as probability inputs -3. Check `negRisk` — if `true`, verify neg-risk approvals were set -4. Check proxy wallet USDC.e balance before buying (use `proxy-wallet` to get address, then check balance externally or via `balances`) -5. Use `--skip-fund` if the proxy wallet already has enough USDC.e from a previous `clob-buy` -6. Always dry-run first, then broadcast - -When deciding whether to sell: -1. Get current `size` (shares) from `positions` -2. Use `curPrice` vs `avgPrice` to assess profit/loss -3. Market sell (`sell --broadcast`) for immediate exit -4. Limit sell (`--price 0.x --broadcast`) to wait for a better price - ---- - -## Troubleshooting - -| Error | Cause | Fix | -|-------|-------|-----| -| `No EOA key found` | `set-key` not run | Run `polygon-agent polymarket set-key ` | -| `Could not create api key` (stderr) | ToS not accepted | Visit polymarket.com, connect EOA wallet, accept terms. This error in **stderr** is non-fatal — the CLI retries with `deriveApiKey` and may still succeed. | -| `CLOB order error: not authorized` | ToS not accepted | Same as above — fatal for order posting | -| `insufficient funds for gas` | EOA has no POL | `polygon-agent send-native --to --amount 0.1 --broadcast` | -| `execution reverted: must be called be owner` | Old code calling proxy directly | Upgrade CLI — fixed in current version (calls factory) | -| `Market not found` | Low-volume or closed market | Market may have resolved; try `--search` with different terms | -| `Market has no tokenIds` | Closed market | Check `endDate` — market resolved | -| `orderStatus: "unmatched"` on FOK | No liquidity at market price | Try `--fak` for partial fill, or `--price 0.x` for limit order | -| `invalid amount for a marketable BUY order ($X), min size: $1` | Amount below CLOB minimum | Use at least $1. If USDC.e was already funded, retry with `--skip-fund` | -| `Wallet not found: main` | No Sequence wallet | Run `polygon-agent wallet create` | - ---- - -## Key Facts for Agents - -- **All commands are dry-run by default.** `approve`, `clob-buy`, `sell` do nothing without `--broadcast`. -- **`clob-buy` transfers USDC.e from the smart wallet to the proxy wallet automatically** (unless `--skip-fund`). -- **Positions live in the proxy wallet**, not the Sequence smart wallet. `positions` queries the proxy wallet. -- **Approvals are one-time.** Don't run `approve` before every trade — only once per EOA (and once more if enabling neg-risk). -- **Sell is free.** No gas, no on-chain tx. Selling via CLOB is a signed off-chain message only. -- **`orderStatus: "matched"`** means the trade filled. `"unmatched"` means FOK failed (no liquidity). -- **The proxy wallet address never changes.** It is deterministic from the EOA via CREATE2. diff --git a/packages/polygon-agent-cli/package.json b/packages/polygon-agent-cli/package.json index 761d15e..eb10040 100644 --- a/packages/polygon-agent-cli/package.json +++ b/packages/polygon-agent-cli/package.json @@ -16,8 +16,7 @@ }, "files": [ "dist", - "contracts", - "skills" + "contracts" ], "scripts": { "build": "node scripts/build.mjs", diff --git a/packages/polygon-agent-cli/skills/SKILL.md b/packages/polygon-agent-cli/skills/SKILL.md deleted file mode 100644 index 9617e24..0000000 --- a/packages/polygon-agent-cli/skills/SKILL.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -name: Polygon Agent -description: "Complete Polygon agent toolkit for on-chain operations on Polygon. Use this skill whenever helping an agent set up a wallet, check balances, send or swap tokens, bridge assets, deposit or withdraw from yield (Aave aTokens, ERC-4626 vaults), register on-chain identity, submit or query reputation/feedback, or make x402 micropayments. Covers the full lifecycle: Sequence smart contract wallets, Trails DeFi actions, ERC-8004 identity + reputation, x402 payments. Single CLI entry point (`polygon-agent`), AES-256-GCM encrypted storage." ---- - -# Polygon Agentic CLI - -## Prerequisites -- Node.js 20+ -- Install globally: `npm install -g @polygonlabs/agent-cli` (reinstall to update) -- Entry point: `polygon-agent ` -- Storage: `~/.polygon-agent/` (AES-256-GCM encrypted) - -## Architecture - -| Wallet | Created by | Purpose | Fund? | -|--------|-----------|---------|-------| -| EOA | `setup` | Auth with Sequence Builder | NO | -| Ecosystem Wallet | `wallet create` | Primary spending wallet | YES | - -## Environment Variables - -### Access key — one key, many names - -`SEQUENCE_PROJECT_ACCESS_KEY`, `SEQUENCE_INDEXER_ACCESS_KEY`, and `TRAILS_API_KEY` are **all the same key** — the Sequence project access key created during `setup`. The CLI treats them as aliases and falls back through all of them automatically. - -After `setup` runs the key is stored in `~/.polygon-agent/builder.json`. Every CLI invocation bootstraps it into the environment — no `export` is needed. In a fresh agent session with no environment variables set, simply run commands and the CLI reads credentials from disk. - -Only set these manually to override the stored value (e.g. to point at a different project): -```bash -export SEQUENCE_PROJECT_ACCESS_KEY= # also covers TRAILS_API_KEY and indexer calls -``` - -### Optional overrides -| Variable | Default | -|----------|---------| -| `SEQUENCE_ECOSYSTEM_CONNECTOR_URL` | `https://agentconnect.polygon.technology` | -| `SEQUENCE_DAPP_ORIGIN` | Same as connector URL origin | -| `TRAILS_TOKEN_MAP_JSON` | Token-directory lookup | -| `POLYGON_AGENT_DEBUG_FETCH` | Off — logs HTTP to `~/.polygon-agent/fetch-debug.log` | -| `POLYGON_AGENT_DEBUG_FEE` | Off — dumps fee options to stderr | - -## Complete Setup Flow - -```bash -# Step 1: Setup (creates EOA + Sequence project, stores access key to disk) -polygon-agent setup --name "MyAgent" -# → saves privateKey (not shown again), eoaAddress, accessKey to ~/.polygon-agent/builder.json -# → all subsequent commands auto-load the access key from disk — no export needed - -# Step 2: Create ecosystem wallet (opens browser, waits for 6-digit code) -polygon-agent wallet create --usdc-limit 100 --native-limit 5 -# → opens https://agentconnect.polygon.technology/link?rid=&... -# → user approves in browser, browser shows a 6-digit code -# → enter the 6-digit code in the terminal when prompted -# → session saved to ~/.polygon-agent/wallets/main.json -# → notify the user and send them to https://agentconnect.polygon.technology/?rid= -# so they can fund their wallet with access to the session - -# Step 3: Fund wallet -polygon-agent fund -# → reads walletAddress from session, builds Trails widget URL with toAddress= -# → ALWAYS run this command to get the URL — never construct it manually or hardcode any address -# → send the returned `fundingUrl` to the user; `walletAddress` in the output confirms the recipient - -# Step 4: Verify balances -polygon-agent balances - -# Step 5: Register agent on-chain (ERC-8004, Polygon mainnet only) -polygon-agent agent register --name "MyAgent" --broadcast -# → mints ERC-721 NFT, emits Registered event containing agentId -# → retrieve agentId: open the tx on https://polygonscan.com, go to Logs tab, -# find the Registered event — agentId is the first indexed parameter -# → use agentId for reputation queries, reviews, and feedback -``` - -## Commands Reference - -### Setup -```bash -polygon-agent setup --name [--force] -``` - -### Wallet -Valid `--chain` values: `polygon` (default/mainnet), `amoy` (Polygon testnet), `mainnet` (Ethereum), `arbitrum`, `optimism`, `base`. ERC-8004 agent operations only support `polygon`. - -```bash -polygon-agent wallet create [--name ] [--chain polygon] [--timeout ] [--print-url] - [--native-limit ] [--usdc-limit ] [--usdt-limit ] - [--token-limit ] # repeatable - [--usdc-to --usdc-amount ] # one-off scoped transfer - [--contract ] # whitelist contract (repeatable) -polygon-agent wallet import --code <6-digit-code> --rid [--name ] -polygon-agent wallet import --ciphertext '|@' [--name ] # legacy -polygon-agent wallet list -polygon-agent wallet address [--name ] -polygon-agent wallet remove [--name ] -``` - -### Operations -```bash -polygon-agent balances [--wallet ] [--chain ] [--chains ] -polygon-agent send --to --amount [--symbol ] [--token ] [--decimals ] [--broadcast] -polygon-agent send-native --to --amount [--broadcast] [--direct] -polygon-agent send-token --symbol --to --amount [--token ] [--decimals ] [--broadcast] -polygon-agent swap --from --to --amount [--to-chain ] [--slippage ] [--broadcast] -polygon-agent deposit --asset --amount [--protocol aave|morpho] [--broadcast] -polygon-agent withdraw --position --amount [--chain ] [--broadcast] -polygon-agent fund [--wallet ] [--token ] -polygon-agent x402-pay --url --wallet [--method GET] [--body ] [--header Key:Value] -``` - -### Agent (ERC-8004) -```bash -polygon-agent agent register --name [--agent-uri ] [--metadata ] [--broadcast] -polygon-agent agent wallet --agent-id -polygon-agent agent metadata --agent-id --key -polygon-agent agent reputation --agent-id [--tag1 ] [--tag2 ] -polygon-agent agent reviews --agent-id [--tag1 ] [--tag2 ] [--revoked] -polygon-agent agent feedback --agent-id --value [--tag1 ] [--tag2 ] [--endpoint ] [--feedback-uri ] [--broadcast] -``` - -**ERC-8004 contracts (Polygon mainnet):** -- IdentityRegistry: `0x8004A169FB4a3325136EB29fA0ceB6D2e539a432` -- ReputationRegistry: `0x8004BAa17C55a88189AE136b182e5fdA19dE9b63` - -## Key Behaviors - -- **Dry-run by default** — all write commands require `--broadcast` to execute -- **Smart defaults** — `--wallet main`, `--chain polygon`, auto-wait on `wallet create` -- **`balances --chains`** — comma-separated chains (max 20); two or more return JSON with `multiChain: true` and a `chains` array (same wallet address on each) -- **Fee preference** — auto-selects USDC over native POL when both available -- **`fund`** — reads `walletAddress` from the wallet session and sets it as `toAddress` in the Trails widget URL. Always run `polygon-agent fund` to get the correct URL — never construct it manually or hardcode any address. -- **`deposit`** — picks highest-TVL pool via Trails `getEarnPools`. Sends two txs: ERC-20 `approve()` on the token contract, then the pool deposit. If session rejects, re-create wallet with both `--contract --contract ` (the dry-run output shows both addresses). -- **`withdraw`** — `--position` = aToken or ERC-4626 vault; `--amount` = `max` or underlying units (Aave / vault). Dry-run JSON includes `poolAddress` / `vault`. Broadcast needs session on the **same chain** as `--chain`, with pool/vault + underlying token whitelisted where the relayer touches them -- **`x402-pay`** — probes endpoint for 402, smart wallet funds builder EOA with exact token amount, EOA signs EIP-3009 payment. Chain auto-detected from 402 response -- **`send-native --direct`** — bypasses ValueForwarder contract for direct EOA transfer -- **Session permissions** — without `--usdc-limit` etc., session gets bare-bones defaults and may not transact -- **Session expiry** — 6 months from creation - -## Wallet Creation Flow (v2 Relay) - -`wallet create` uses a Cloudflare Durable Object relay and a 6-digit out-of-band code — no cloudflared tunnel required. The browser encrypts the approved session with an X25519 key negotiated via the relay; the 6-digit code is the decryption key entered in the terminal. - -**`--print-url` flag:** Use this in headless or non-interactive environments (CI, remote shells) where `wallet create` can't block waiting for the code. The CLI prints the approval URL and exits immediately. Complete the flow separately: -```bash -polygon-agent wallet import --code <6-digit-code> --rid -``` - -## CRITICAL: Wallet Approval URL - -When `wallet create` outputs a URL in the `url` or `approvalUrl` field, send the **complete, untruncated URL** to the user. The URL contains the relay request ID required for session approval. - -- Do NOT shorten, summarize, or add `...` to the URL -- Do NOT split the URL across multiple messages -- Output the raw URL exactly as returned by the CLI - -## Presenting Results to the User - -CLI commands output JSON (non-TTY). After running a command, always render the result as formatted markdown — never paste raw JSON into the conversation. - -| Command | How to present | -|---------|---------------| -| `balances` | Markdown table: Token / Balance columns. Show wallet address and chain above the table. | -| `send` / `send-token` / `send-native` | One-liner summary: amount, symbol, recipient. If broadcast, show tx hash as a code span and explorer URL as a link. | -| `swap` | Summary: `X FROM → Y TO` with chain. If broadcast, show deposit tx hash + explorer link. | -| `deposit` | Summary: amount, asset, protocol, pool address. If broadcast, show tx hash + explorer link. | -| `withdraw` | Summary: `kind` (aave / erc4626), position, amount, pool or vault. If broadcast, show tx hash + explorer link. | -| `fund` | Show the `fundingUrl` as a clickable link with a brief instruction to open it. | -| `wallet create` / `wallet list` | Wallet name, truncated address, chain in a small table or bullet list. | -| `agent register` | Show agent name and tx hash as a code span with Polygonscan link. Remind user to retrieve `agentId` from the Registered event on the Logs tab. | -| `agent wallet` | Show `agentId`, wallet address, and whether a wallet is set. | -| `agent metadata` | Show `agentId`, key, and decoded value. | -| `agent reputation` | Format score and tag breakdown as a small table. | - -**Dry-run results** — always make it visually clear this was a simulation. Prefix with `⚡ Dry run` and show what *would* happen. Remind the user to re-run with `--broadcast` to execute. - -**Errors** — extract the `error` field and present it as a clear sentence, not a JSON blob. Include the relevant fix from the Troubleshooting table if applicable. - ---- - -## Use-Case Skills - -For specific workflows, fetch and load the relevant sub-skill: - -| Use Case | Skill URL | -|----------|-----------| -| Polymarket prediction market trading | https://agentconnect.polygon.technology/polygon-polymarket/SKILL.md | -| DeFi — swap, deposit, withdraw, yield | https://agentconnect.polygon.technology/polygon-defi/SKILL.md | -| x402 discovery & pay-per-call APIs | https://agentconnect.polygon.technology/polygon-discovery/SKILL.md | - ---- - -## Troubleshooting - -| Issue | Fix | -|-------|-----| -| `Builder configured already` | Add `--force` | -| `Missing SEQUENCE_PROJECT_ACCESS_KEY` | Run `setup` first | -| `Missing wallet` | `wallet list`, re-run `wallet create` | -| `Session expired` | Re-run `wallet create` (6-month expiry) | -| `Fee option errors` | Set `POLYGON_AGENT_DEBUG_FEE=1`, ensure wallet has funds | -| `Timed out waiting for wallet approval` | Add `--timeout 600` | -| `Invalid code: hash mismatch` | Wrong 6-digit code entered — retry (3 attempts allowed) | -| `Relay request not found` | Session expired or already used — re-run `wallet create` (or `wallet create --print-url`) | -| Deposit session rejected | Re-create wallet with `--contract --contract ` (both required: token approve + pool call) | -| `withdraw` / broadcast: wrong chain or session rejects | Use `wallet create --chain ` and `--contract` for pool/vault + underlying ERC-20 on that chain; omit tight `--usdc-limit` if it blocks fee transfers | -| `Stored explicit session is missing pk` | Re-link: `wallet import --code …` after `wallet create` | -| Wrong recipient in Trails widget | Run `polygon-agent fund` (do not construct the URL manually) | -| `x402-pay`: no 402 response | Endpoint doesn't require x402 payment, or URL is wrong | -| `x402-pay`: payment token mismatch | Chain/token in the 402 response differs from wallet — check `--wallet` points to the right chain | -| `x402-pay`: EOA funding failed | Wallet lacks sufficient balance to cover the payment amount — run `balances` and fund if needed | - -## File Structure -``` -~/.polygon-agent/ -├── .encryption-key # AES-256-GCM key (auto-generated, 0600) -├── builder.json # EOA privateKey (encrypted), eoaAddress, accessKey, projectId -├── wallets/.json # walletAddress, session, chainId, chain -└── requests/.json # Pending wallet creation requests (deleted after successful import) -``` diff --git a/packages/polygon-agent-cli/skills/polygon-defi/SKILL.md b/packages/polygon-agent-cli/skills/polygon-defi/SKILL.md deleted file mode 100644 index cdd61fe..0000000 --- a/packages/polygon-agent-cli/skills/polygon-defi/SKILL.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -name: polygon-defi -description: DeFi operations on Polygon using the Polygon Agent CLI. Covers same-chain token swaps, cross-chain bridging, and yield deposits into Aave v3 and Morpho vaults via Trails earn pool discovery. All commands dry-run by default — add --broadcast to execute. ---- - -# Polygon DeFi Skill - -## Swap Tokens (Same-Chain) - -```bash -# Dry-run — shows route and output amount -polygon-agent swap --from USDC --to USDT --amount 5 - -# Execute -polygon-agent swap --from USDC --to USDT --amount 5 --broadcast - -# Custom slippage (default 0.5%) -polygon-agent swap --from USDC --to USDT --amount 5 --slippage 0.005 --broadcast -``` - -## Bridge Tokens (Cross-Chain) - -```bash -# Bridge USDC from Polygon to Arbitrum -polygon-agent swap --from USDC --to USDC --amount 0.5 --to-chain arbitrum --broadcast - -# Bridge to other supported chains -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain optimism --broadcast -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain base --broadcast -polygon-agent swap --from USDC --to USDC --amount 1 --to-chain mainnet --broadcast -``` - -Valid `--to-chain` values: `polygon`, `amoy`, `mainnet`, `arbitrum`, `optimism`, `base`. - -## Query Earn Pools - -Use `getEarnPools` to discover live yield opportunities across protocols before deciding where to deposit. - -### HTTP - -```bash -curl --request POST \ - --url https://trails-api.sequence.app/rpc/Trails/GetEarnPools \ - --header 'Content-Type: application/json' \ - --data '{"chainIds": [137]}' -``` - -All request fields are optional — omit any you don't need to filter on. - -| Field | Type | Description | -|-------|------|-------------| -| `chainIds` | `number[]` | Filter by chain (e.g. `[137]` for Polygon mainnet) | -| `protocols` | `string[]` | Filter by protocol name, e.g. `["Aave"]`, `["Morpho"]` | -| `minTvl` | `number` | Minimum TVL in USD | -| `maxApy` | `number` | Maximum APY (useful to exclude outlier/at-risk pools) | - -### Fetch (agent code) - -The API key is the project access key already available to the agent (`SEQUENCE_PROJECT_ACCESS_KEY`). - -```typescript -const res = await fetch('https://trails-api.sequence.app/rpc/Trails/GetEarnPools', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ chainIds: [137] }), -}); -const { pools } = await res.json(); -``` - -### Response Schema - -```typescript -interface GetEarnPoolsResponse { - pools: EarnPool[]; - timestamp: string; // ISO-8601 fetch time - cached: boolean; -} - -interface EarnPool { - id: string; // "{protocol}-{chainId}-{address}" - name: string; // e.g. "USDC Market" - protocol: string; // "Aave" | "Morpho" - chainId: number; - apy: number; // annualised yield as a decimal percent - tvl: number; // USD - token: PoolTokenInfo; - depositAddress: string; // contract to approve/send to - isActive: boolean; - poolUrl?: string; - protocolUrl?: string; - wrappedTokenGatewayAddress?: string; // non-null for Aave native-token markets -} - -interface PoolTokenInfo { - symbol: string; - name: string; - address: string; - decimals: number; - logoUrl?: string; -} -``` - -> **Tip:** `wrappedTokenGatewayAddress` is set on Aave markets that accept a wrapped native token (WPOL, WETH). Pass this address instead of `depositAddress` when depositing POL/ETH directly. - ---- - -## Deposit to Earn Yield - -Pool discovery uses `TrailsApi.getEarnPools` — picks the most liquid pool (highest TVL) for the asset on the current chain. No hardcoded addresses — the pool is resolved at runtime. - -**Note on Morpho Vaults:** -Trails categorizes Morpho vaults by their *receipt* token symbol (e.g., `STEAKUSDC` or `gtUSDCp`), rather than the underlying token. To deposit into a Morpho vault, you must provide the vault's exact receipt token symbol as the `--asset`. -If you try to deposit using `--asset USDC`, it may fail to find the pool. In those cases, you can use the `swap` command to swap `USDC` directly for the vault's receipt token address. - -```bash -# Dry-run — shows pool name, APY, TVL, and deposit address before committing -polygon-agent deposit --asset STEAKUSDC --amount 0.3 --protocol morpho - -# Execute — deposits into the highest-TVL active pool -polygon-agent deposit --asset STEAKUSDC --amount 0.3 --protocol morpho --broadcast - -# Filter by protocol (Aave uses the underlying asset name) -polygon-agent deposit --asset USDC --amount 0.3 --protocol aave --broadcast -``` - -### Supported Protocols - -| Protocol | Encoding | Description | -|----------|----------|-------------| -| **Aave v3** | `supply(asset, amount, onBehalfOf, referralCode)` | Lending pool deposit | -| **Morpho** | `deposit(assets, receiver)` — ERC-4626 | Vault deposit | - -Vault/pool addresses are resolved dynamically from Trails — they are not hardcoded. The dry-run output includes `depositAddress` so you can inspect the exact contract before broadcasting. - -### Session Whitelisting - -A deposit sends **two transactions**: an ERC-20 `approve()` on the token contract, then the pool deposit call. Both contracts must be whitelisted in the session. If the deposit is rejected with a session permission error: - -```bash -# 1. Dry-run first — output includes both addresses under `transactions[0].to` (token) and `depositAddress` (pool) -polygon-agent deposit --asset USDC --amount 0.3 -# → note the token contract address (e.g. USDC: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359) -# → note the depositAddress (e.g. Aave V3: 0x794a61358d6845594f94dc1db02a252b5b4814ad) - -# 2. Re-create wallet session with BOTH contracts whitelisted -polygon-agent wallet create --contract --contract - -# 3. Retry -polygon-agent deposit --asset USDC --amount 0.3 --broadcast -``` - -Common token contracts on Polygon mainnet (already auto-whitelisted in sessions created by the CLI): -- USDC: `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` -- USDT: `0xc2132D05D31c914a87C6611C10748AEb04B58e8F` -- WETH: `0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619` - -### Yield Vault Contract Whitelist - -#### Polygon Mainnet (chainId 137) - -| Protocol | Asset | Address | -|----------|-------|---------| -| Aave V3 Pool (all markets) | USDC, USDT, WETH, WMATIC… | `0x794a61358d6845594f94dc1db02a252b5b4814ad` | -| Morpho Compound USDC | USDC | `0x781fb7f6d845e3be129289833b04d43aa8558c42` | -| Morpho Compound WETH | WETH | `0xf5c81d25ee174d83f1fd202ca94ae6070d073ccf` | -| Morpho Compound POL | POL | `0x3f33f9f7e2d7cfbcbdf8ea8b870a6e3d449664c2` | - -#### Katana (chainId 747474) — Morpho Vaults - -| Vault | Asset | TVL | Address | -|-------|-------|-----|---------| -| Gauntlet USDT | USDT | ~$97M | `0x1ecdc3f2b5e90bfb55ff45a7476ff98a8957388e` | -| Steakhouse Prime USDC | USDC | ~$54M | `0x61d4f9d3797ba4da152238c53a6f93fb665c3c1d` | -| Yearn OG ETH | WETH | ~$16M | `0xfade0c546f44e33c134c4036207b314ac643dc2e` | -| Yearn OG USDC | USDC | ~$16M | `0xce2b8e464fc7b5e58710c24b7e5ebfb6027f29d7` | -| Gauntlet USDC | USDC | ~$8M | `0xe4248e2105508fcbad3fe95691551d1af14015f7` | -| Yearn OG USDT | USDT | ~$8M | `0x8ed68f91afbe5871dce31ae007a936ebe8511d47` | -| Gauntlet WETH | WETH | ~$6M | `0xc5e7ab07030305fc925175b25b93b285d40dcdff` | -| Hyperithm vbUSDC Apex | USDC | ~$3M | `0xef77f8c53af95f3348cee0fb2a02ee02ab9cdca5` | - ---- - -## Full DeFi Flow Example - -```bash -# 1. Check balances -polygon-agent balances - -# 2. Swap POL → USDC -polygon-agent swap --from POL --to USDC --amount 1 --broadcast - -# 3. Deposit USDC into highest-TVL yield pool -polygon-agent deposit --asset USDC --amount 1 --broadcast -# → protocol: morpho (or aave, whichever has highest TVL at the time) -# → poolApy shown in dry-run output - -# 4. Bridge remaining USDC to Arbitrum -polygon-agent swap --from USDC --to USDC --amount 0.5 --to-chain arbitrum --broadcast -``` - ---- - -## Troubleshooting - -| Error | Cause | Fix | -|-------|-------|-----| -| `Deposit session rejected` | Pool or token contract not whitelisted | Re-create wallet with `--contract --contract ` (both required) | -| `Protocol X not yet supported` | Trails returned a protocol other than aave/morpho | Use `polygon-agent swap` to obtain the yield-bearing token manually | -| `Fee option errors` | Wallet has insufficient balance | Run `polygon-agent balances` and fund the wallet | -| `swap`: no route found | Insufficient liquidity for the pair | Try a different amount or token pair | diff --git a/packages/polygon-agent-cli/skills/polygon-discovery/SKILL.md b/packages/polygon-agent-cli/skills/polygon-discovery/SKILL.md deleted file mode 100644 index 27509bb..0000000 --- a/packages/polygon-agent-cli/skills/polygon-discovery/SKILL.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -name: polygon-discovery -description: x402 Bazaar — pay-per-call API services accessible via the Polygon Agent CLI. No API keys or subscriptions needed. Each call costs a small USDC amount drawn from the agent's smart wallet. Covers web search, news, AI image generation, Twitter/X data, code review, text summarization, sentiment analysis, and article extraction. ---- - -# x402 Bazaar Services - -Pay-per-call APIs accessible via `x402-pay`. No API keys or subscriptions — each call costs a small USDC amount drawn from your wallet. The CLI detects the 402 response, funds the exact amount, and retries automatically. - -**Catalog:** `GET https://x402-api.onrender.com/api/catalog?status=online` - ---- - -## Prerequisites — Check Before Any x402 Call - -Before running any `x402-pay` command, verify the wallet session exists and is funded: - -```bash -# Check if a wallet is configured -polygon-agent wallet list -``` - -**If no wallet is listed**, the smart session has not been created. Run through the complete setup flow before proceeding: - -1. `polygon-agent setup --name "MyAgent"` — creates EOA and Sequence project -2. `polygon-agent wallet create --usdc-limit 100` — opens browser for session approval; enter the 6-digit code when prompted -3. `polygon-agent wallet address` — get address, then fund via https://agentconnect.polygon.technology -4. `polygon-agent balances` — confirm USDC is available before calling any x402 endpoint - -**If a wallet exists but `balances` shows 0 USDC**, direct the user to fund it via the UI — `x402-pay` will fail with an EOA funding error otherwise. - -Once a funded wallet is confirmed, proceed with the x402 calls below. - ---- - -## Read Twitter/X Profile - -$0.005 USDC per call. - -> **Note:** The catalog proxy (`/api/call/99063826-...`) returns 401 or HTML for this service. -> Use the direct endpoint below instead. - -```bash -# Profile + recent tweets -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/twitter?user=" \ - --wallet main --method POST - -# Specific tweet -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/twitter?tweet=https://x.com/user/status/" \ - --wallet main --method POST -``` - -Returns: follower/following counts and tweet metrics. - -**Troubleshooting:** If the direct endpoint fails, check the live catalog for the current URL: -```bash -curl -s "https://x402-api.onrender.com/api/catalog?status=online" \ - | jq '.[] | select(.name | test("twitter"; "i"))' -``` - ---- - -## Generate an AI Image - -$0.02 USDC per call. Powered by Google Gemini. - -```bash -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/call/2998d205-94d9-4f7e-8f8a-201a090a5530?prompt=&size=512" \ - --wallet main --method GET -``` - -`size` options: `256`, `512`, `1024`. Returns JSON with `data_uri` (base64 PNG) for embedding. - ---- - -## Review Code for Bugs & Security - -$0.01 USDC per call. Powered by GPT-4o. - -```bash -polygon-agent x402-pay \ - --url "https://x402-api.onrender.com/api/call/7f21e675-9fdc-4ba3-9a8d-145c6ac703c7" \ - --wallet main \ - --body '{"code": "", "language": ""}' -``` - -Returns: bugs, security issues, performance problems, and style suggestions — each with line number, severity, and fix suggestion. Plus an overall quality score. - ---- - -## Other Services - -| Service | Price | Endpoint | Key param | -|---------|-------|----------|-----------| -| Web search (DuckDuckGo) | $0.005 | `9b0f5b5f-8e6c-4b55-a264-008e4e490c26` | `?q=&max=10` | -| Latest news (Google News) | $0.005 | `266d045f-bae2-4c71-9469-3638ec860fc4` | `?topic=&lang=en` | -| Summarize text (GPT-4o-mini) | $0.01 | `dd9b5098-700d-47a9-a41a-c9eae66ca49d` | `?text=&maxLength=200` | -| Article → Markdown | $0.005 | `87b50238-5b99-4521-b5e1-7515a9c1526d` | `?url=` | -| Sentiment analysis (GPT-4o-mini) | $0.005 | `66d68ca6-a8d9-41a3-b024-a3fac2f5c7ba` | `?text=` | - -All use GET via `polygon-agent x402-pay --url "https://x402-api.onrender.com/api/call/" --wallet main --method GET`. - ---- - -## How x402 Works - -1. CLI sends the request to the endpoint -2. Endpoint responds with `HTTP 402 Payment Required` + payment details -3. CLI automatically funds the builder EOA with the exact token amount from the smart wallet -4. EOA signs an EIP-3009 payment authorization -5. CLI retries the original request with the payment header -6. Response is returned — the whole flow is transparent to the agent - -Chain and token are auto-detected from the 402 response. No manual configuration needed. diff --git a/packages/polygon-agent-cli/skills/polygon-polymarket/SKILL.md b/packages/polygon-agent-cli/skills/polygon-polymarket/SKILL.md deleted file mode 100644 index 0cac0ff..0000000 --- a/packages/polygon-agent-cli/skills/polygon-polymarket/SKILL.md +++ /dev/null @@ -1,330 +0,0 @@ ---- -name: polymarket-skill -description: Place bets on Polymarket prediction markets using the Polygon Agent CLI. Browse markets, check prices, buy YES/NO positions, sell positions, manage orders. All commands are JSON output. Dry-run by default — always add --broadcast to execute. ---- - -# Polymarket Skill - -## Session Initialization - -Before any polymarket command, initialize the session. Read `~/.polygon-agent/builder.json` and export the access key: - -```bash -export SEQUENCE_PROJECT_ACCESS_KEY= -export SEQUENCE_INDEXER_ACCESS_KEY=$SEQUENCE_PROJECT_ACCESS_KEY -``` - -Also verify the Polymarket key is set: -```bash -polygon-agent polymarket proxy-wallet -``` -If this returns `ok: true` with an `eoaAddress` and `proxyWalletAddress`, the key is configured. If it errors, the user needs to run `set-key` (see Onboarding below). - ---- - -## Understanding the 3 Addresses - -Every Polymarket user has three addresses. Do not confuse them: - -| Name | What it is | Used for | -|------|-----------|---------| -| EOA | Private key owner. Shown as `eoaAddress` in CLI output | Signs transactions and CLOB orders. Holds POL for gas | -| Proxy Wallet | Shown as `proxyWalletAddress` in CLI output. This is what Polymarket shows as "your address" in the UI | Holds USDC.e and outcome tokens. The CLOB `maker` | -| Deposit Address | A cross-chain bridge ingress — only relevant for bridging from other chains | Ignore for Polygon-native usage | - -**For trading:** funds go from the Sequence smart wallet → proxy wallet → CLOB orders. The proxy wallet is the trading identity. - ---- - -## Onboarding: First-Time Setup - -### Option A — Using email login (Polymarket account) - -If the user has a Polymarket account via email login: - -**Step 1: Get the private key from Polymarket** -``` -1. Go to: https://reveal.magic.link/polymarket -2. Connect/authenticate with the same email used for Polymarket -3. Copy the exported private key (0x...) -``` - -**Step 2: Accept Terms of Service** -``` -1. Go to: https://polymarket.com -2. Connect wallet using the exported private key (import to MetaMask or similar) -3. Accept Terms of Service when prompted - — This is REQUIRED for CLOB order placement. Without it, orders will fail. -``` - -**Step 3: Import the key into the CLI** -```bash -polygon-agent polymarket set-key -``` -Output confirms the `eoaAddress` and `proxyWalletAddress`. - -**Step 3b: Confirm your addresses (show this to the user)** -```bash -polygon-agent polymarket proxy-wallet -``` -**Tell the user:** "Your EOA is `` — this needs POL for gas. Your Polymarket trading address (proxy wallet) is `` — this is where your USDC.e and outcome tokens live. The proxy wallet does not need POL. You must fund the EOA with POL and run approvals before trading." - -**Step 4: Fund the EOA with POL for gas** -```bash -# Check EOA address from set-key output, then send ~0.1 POL to it -polygon-agent send-native --to --amount 0.1 --broadcast -``` - -**Step 5: Set proxy wallet approvals (one-time, permanent)** -```bash -polygon-agent polymarket approve --broadcast -``` -This sends a transaction directly from the EOA (not through Polymarket's UI), so the EOA must hold POL for gas. This is different from trading on polymarket.com, where their UI sponsors gas for you. - -### Option B — Using the builder EOA (no Polymarket account needed) - -If the user has done `polygon-agent setup` already, the builder EOA can be used directly. Skip `set-key`. - -**Step 1: Confirm addresses (show this to the user)** -```bash -polygon-agent polymarket proxy-wallet -``` -**Tell the user:** "Your EOA is `` — this needs POL for gas. Your Polymarket trading address (proxy wallet) is `` — this is where your USDC.e and outcome tokens live. The proxy wallet does not need POL. You must accept Polymarket ToS, fund the EOA with POL, and run approvals before trading." - -**Step 2: Accept Terms of Service (required — CLOB orders will fail without this)** -``` -1. Go to https://polymarket.com -2. Connect with the EOA wallet address shown above -3. Accept Terms of Service when prompted -``` - -**Step 3: Fund the EOA with POL for gas** -```bash -polygon-agent send-native --to --amount 0.1 --broadcast -``` - -**Step 4: Set proxy wallet approvals (one-time)** -```bash -polygon-agent polymarket approve --broadcast -``` -This sends a transaction directly from the EOA (not through Polymarket's UI), so the EOA must hold POL for gas. - ---- - -## Commands - -### Browse Markets - -```bash -# List top markets by volume -polygon-agent polymarket markets - -# Search by keyword -polygon-agent polymarket markets --search "bitcoin" --limit 10 - -# Paginate -polygon-agent polymarket markets --limit 20 --offset 20 -``` - -Key output fields per market: -- `conditionId` — the ID needed for all trading commands -- `question` — what the market is asking -- `yesPrice` / `noPrice` — current probability (0 to 1, e.g. `0.65` = 65%) -- `negRisk` — if `true`, set neg-risk approvals before trading this market -- `endDate` — when the market resolves - -### Get a Single Market - -```bash -polygon-agent polymarket market -``` - -Use this to confirm prices and token IDs before placing an order. - -### Show Proxy Wallet Address - -```bash -polygon-agent polymarket proxy-wallet -``` - -Confirms which EOA and proxy wallet are active. The proxy wallet is where USDC.e and tokens are held. - -### Set Approvals (One-Time) - -```bash -# Standard markets -polygon-agent polymarket approve --broadcast - -# Neg-risk markets (if you see negRisk: true on any market you want to trade) -polygon-agent polymarket approve --neg-risk --broadcast -``` - -Run once per EOA. Permanent on-chain — no need to repeat unless enabling neg-risk. -**Dry-run (no --broadcast) shows what will be approved without executing.** - -### Buy a Position - -```bash -# Dry-run first — always check before executing -polygon-agent polymarket clob-buy YES|NO - -# Execute — funds proxy wallet from smart wallet, then places order -polygon-agent polymarket clob-buy YES|NO --broadcast - -# If proxy wallet already has USDC.e (skip the funding step) -polygon-agent polymarket clob-buy YES|NO --skip-fund --broadcast - -# Limit order — fill only at this price or better -polygon-agent polymarket clob-buy YES --price 0.45 --broadcast -``` - -**How it works:** -1. Smart wallet transfers `usdcAmount` USDC.e to the proxy wallet (Sequence tx, USDC.e fee) -2. Posts CLOB BUY order: maker=proxy wallet, signer=EOA (off-chain, no gas) -3. Tokens arrive in proxy wallet on fill - -**Order types:** -- No `--price`: FOK market order (fill entirely or cancel) -- `--fak`: FAK market order (partial fills allowed) -- `--price 0.x`: GTC limit order (stays open until filled or cancelled) - -**Minimum order size: $1 USDC.** The CLOB rejects marketable BUY orders below $1. If the fund step runs but the order is rejected, the USDC.e stays in the proxy wallet — use `--skip-fund` on the retry. - -### Sell a Position - -```bash -# Dry-run first -polygon-agent polymarket sell YES|NO - -# Execute -polygon-agent polymarket sell YES|NO --broadcast - -# Limit sell -polygon-agent polymarket sell YES --price 0.80 --broadcast -``` - -`` is the number of outcome tokens (not USD). Get share count from `positions`. -Selling is pure off-chain — no gas, no on-chain tx. - -### Check Positions - -```bash -polygon-agent polymarket positions -``` - -Shows all open positions in the proxy wallet with current value, P&L, and outcome. - -### Check Open Orders - -```bash -polygon-agent polymarket orders -``` - -Lists GTC limit orders that are still open (FOK/FAK orders are never "open" — they fill or cancel immediately). - -### Cancel an Order - -```bash -polygon-agent polymarket cancel -``` - -Get `orderId` from the `orders` command or from the `orderId` field in `clob-buy` output. - ---- - -## Full Autonomous Trading Flow - -This is the exact sequence to go from zero to a filled trade: - -```bash -# ── SETUP (run once per EOA) ──────────────────────────────────────────── - -# 1. Import your Polymarket private key -# (get it from https://reveal.magic.link/polymarket after email login) -polygon-agent polymarket set-key 0x -# → save eoaAddress and proxyWalletAddress from output - -# 2. Fund the EOA with POL for gas -polygon-agent send-native --to --amount 0.1 --broadcast - -# 3. Set proxy wallet approvals (one-time) -polygon-agent polymarket approve --broadcast -# → save approveTxHash, wait for confirmation - -# ── FIND A MARKET ──────────────────────────────────────────────────────── - -# 4. Search for markets -polygon-agent polymarket markets --search "fed rate" --limit 10 - -# 5. Get details on a specific market -polygon-agent polymarket market 0x -# → check: yesPrice, noPrice, negRisk, endDate -# → if negRisk: true → run approve --neg-risk --broadcast first - -# ── ENTER A POSITION ──────────────────────────────────────────────────── - -# 6. Dry-run to confirm everything -polygon-agent polymarket clob-buy 0x YES 5 -# → review: currentPrice, proxyWalletAddress, flow - -# 7. Execute -polygon-agent polymarket clob-buy 0x YES 5 --broadcast -# → save orderId, check orderStatus === "matched" - -# ── MANAGE ────────────────────────────────────────────────────────────── - -# 8. Check your positions -polygon-agent polymarket positions -# → review: size (shares), curPrice, cashPnl, title, outcome - -# 9. Sell when ready -polygon-agent polymarket sell 0x YES --broadcast -# → orderStatus === "matched" means USDC.e is back in proxy wallet -``` - ---- - -## Decision Logic for an Autonomous Agent - -When deciding whether to buy: -1. Check `positions` — avoid doubling up on already-held positions -2. Check `markets` — use `yesPrice`/`noPrice` as probability inputs -3. Check `negRisk` — if `true`, verify neg-risk approvals were set -4. Check proxy wallet USDC.e balance before buying (use `proxy-wallet` to get address, then check balance externally or via `balances`) -5. Use `--skip-fund` if the proxy wallet already has enough USDC.e from a previous `clob-buy` -6. Always dry-run first, then broadcast - -When deciding whether to sell: -1. Get current `size` (shares) from `positions` -2. Use `curPrice` vs `avgPrice` to assess profit/loss -3. Market sell (`sell --broadcast`) for immediate exit -4. Limit sell (`--price 0.x --broadcast`) to wait for a better price - ---- - -## Troubleshooting - -| Error | Cause | Fix | -|-------|-------|-----| -| `No EOA key found` | `set-key` not run | Run `polygon-agent polymarket set-key ` | -| `Could not create api key` (stderr) | ToS not accepted | Visit polymarket.com, connect EOA wallet, accept terms. This error in **stderr** is non-fatal — the CLI retries with `deriveApiKey` and may still succeed. | -| `CLOB order error: not authorized` | ToS not accepted | Same as above — fatal for order posting | -| `insufficient funds for gas` | EOA has no POL | `polygon-agent send-native --to --amount 0.1 --broadcast` | -| `execution reverted: must be called be owner` | Old code calling proxy directly | Upgrade CLI — fixed in current version (calls factory) | -| `Market not found` | Low-volume or closed market | Market may have resolved; try `--search` with different terms | -| `Market has no tokenIds` | Closed market | Check `endDate` — market resolved | -| `orderStatus: "unmatched"` on FOK | No liquidity at market price | Try `--fak` for partial fill, or `--price 0.x` for limit order | -| `invalid amount for a marketable BUY order ($X), min size: $1` | Amount below CLOB minimum | Use at least $1. If USDC.e was already funded, retry with `--skip-fund` | -| `Wallet not found: main` | No Sequence wallet | Run `polygon-agent wallet create` | - ---- - -## Key Facts for Agents - -- **All commands are dry-run by default.** `approve`, `clob-buy`, `sell` do nothing without `--broadcast`. -- **`clob-buy` transfers USDC.e from the smart wallet to the proxy wallet automatically** (unless `--skip-fund`). -- **Positions live in the proxy wallet**, not the Sequence smart wallet. `positions` queries the proxy wallet. -- **Approvals are one-time.** Don't run `approve` before every trade — only once per EOA (and once more if enabling neg-risk). -- **Sell is free.** No gas, no on-chain tx. Selling via CLOB is a signed off-chain message only. -- **`orderStatus: "matched"`** means the trade filled. `"unmatched"` means FOK failed (no liquidity). -- **The proxy wallet address never changes.** It is deterministic from the EOA via CREATE2. From d6b32a7b178e1f69fd9acb002e7cd6b36d775f21 Mon Sep 17 00:00:00 2001 From: Daryl Collins Date: Tue, 21 Apr 2026 15:55:58 +0100 Subject: [PATCH 3/6] refactor(connector-ui): serve skills from single source via Vite plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A small Vite plugin (mirrorSkills) mirrors the canonical skills/ directory at the repo root onto the CDN URL surface in memory — no symlinks, no committed duplicates. Three URL patterns, all derived dynamically from skills/ contents: /SKILL.md -> skills/SKILL.md /skills/<...> -> skills/<...> (full tree) //SKILL.md -> skills//SKILL.md (compat for URLs referenced in older CLIs' bundled root SKILL.md) configureServer handles dev requests via middleware; generateBundle emits every path into dist/ for the Cloudflare Pages build. Adding skills//SKILL.md starts serving both /skills// and // automatically on the next dev-server start or build — this restores the dynamism the old pre-commit hook had, without committing anything to git. Verified that `pnpm run build` emits all 8 expected SKILL.md paths (root, four under /skills/, three sub-skill siblings at root), each with the correct per-skill content. --- packages/connector-ui/vite.config.ts | 87 +++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/packages/connector-ui/vite.config.ts b/packages/connector-ui/vite.config.ts index 7006f31..1a343d0 100644 --- a/packages/connector-ui/vite.config.ts +++ b/packages/connector-ui/vite.config.ts @@ -1,10 +1,95 @@ +import type { Plugin } from 'vite'; + +import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; +// Mirror skills/ at the repo root onto the following URL surface, purely in +// memory — no symlinks, no committed duplicates: +// +// /SKILL.md <- skills/SKILL.md (root entrypoint) +// /skills/<...> <- skills/<...> (full tree) +// //SKILL.md <- skills//SKILL.md +// (compat with URLs referenced in older +// CLIs' bundled root SKILL.md) +// +// Every pattern is derived dynamically from skills/ contents at build and +// dev-server startup. Adding skills//SKILL.md starts serving +// /skills//SKILL.md and //SKILL.md automatically. +function mirrorSkills(): Plugin { + const here = dirname(fileURLToPath(import.meta.url)); + const skillsDir = resolve(here, '../../skills'); + + const withinSkillsDir = (candidate: string) => + candidate === skillsDir || candidate.startsWith(`${skillsDir}/`); + + const contentType = (file: string) => + file.endsWith('.md') ? 'text/markdown; charset=utf-8' : 'application/octet-stream'; + + function walk(dir: string, prefix: string, emit: (fileName: string, source: Buffer) => void) { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const full = resolve(dir, entry.name); + if (entry.isDirectory()) { + walk(full, `${prefix}${entry.name}/`, emit); + } else { + emit(`${prefix}${entry.name}`, readFileSync(full)); + } + } + } + + function resolveRequest(url: string): string | null { + if (url === '/SKILL.md') return resolve(skillsDir, 'SKILL.md'); + if (url.startsWith('/skills/')) return resolve(skillsDir, url.slice('/skills/'.length)); + const match = url.match(/^\/([^/]+)\/SKILL\.md$/); + if (match) return resolve(skillsDir, match[1], 'SKILL.md'); + return null; + } + + return { + name: 'mirror-skills', + configureServer(server) { + server.middlewares.use((req, res, next) => { + const url = req.url?.split('?')[0] ?? ''; + const file = resolveRequest(url); + if (file && withinSkillsDir(file) && existsSync(file) && statSync(file).isFile()) { + res.setHeader('content-type', contentType(file)); + res.end(readFileSync(file)); + return; + } + next(); + }); + }, + generateBundle() { + if (!existsSync(skillsDir)) return; + + const emit = (fileName: string, source: Buffer) => { + this.emitFile({ type: 'asset', fileName, source }); + }; + + // /SKILL.md + emit('SKILL.md', readFileSync(resolve(skillsDir, 'SKILL.md'))); + + // /skills/* (whole tree, recursive) + walk(skillsDir, 'skills/', emit); + + // //SKILL.md (compat mirror for older-CLI URLs) + for (const entry of readdirSync(skillsDir, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const file = resolve(skillsDir, entry.name, 'SKILL.md'); + if (!existsSync(file)) continue; + emit(`${entry.name}/SKILL.md`, readFileSync(file)); + } + } + }; +} + // https://vite.dev/config/ export default defineConfig({ - plugins: [react(), tailwindcss()], + plugins: [react(), tailwindcss(), mirrorSkills()], server: { port: 4444 } From 7cde2a06bc3638f882ba9eedd6355a5ceadf104d Mon Sep 17 00:00:00 2001 From: Daryl Collins Date: Tue, 21 Apr 2026 16:03:09 +0100 Subject: [PATCH 4/6] docs(skills): add CLI version-mismatch troubleshooting note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skills reference explicit polygon-agent commands and flags — a CLI predating a given skill revision will fail with "Unknown argument" or "command not found" when the agent follows example invocations. Without a self-diagnostic pointer, the agent has no way to identify this as a version-drift issue. Add a compact section right after Prerequisites pointing the agent at `polygon-agent --version`, `npm view @polygonlabs/agent-cli version`, and the upgrade command. Placed in the root SKILL.md only — it is always read first, so one well-placed note covers every sub-skill that inherits its commands from the same CLI. --- skills/SKILL.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/skills/SKILL.md b/skills/SKILL.md index 9617e24..018814c 100644 --- a/skills/SKILL.md +++ b/skills/SKILL.md @@ -11,6 +11,16 @@ description: "Complete Polygon agent toolkit for on-chain operations on Polygon. - Entry point: `polygon-agent ` - Storage: `~/.polygon-agent/` (AES-256-GCM encrypted) +## If a command fails with "Unknown argument" or "command not found" + +This skill is versioned with the CLI — commands and flags drift across releases. Check your version, compare to latest, and upgrade if behind: + +```bash +polygon-agent --version # currently installed +npm view @polygonlabs/agent-cli version # latest published +npm install -g @polygonlabs/agent-cli@latest # upgrade +``` + ## Architecture | Wallet | Created by | Purpose | Fund? | From c5155e8ce08f44d0279f6296ae8fae49de670e76 Mon Sep 17 00:00:00 2001 From: Daryl Collins Date: Tue, 21 Apr 2026 16:18:57 +0100 Subject: [PATCH 5/6] refactor(connector-ui): extract mirror-skills plugin to its own file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vite.config.ts had grown to ~100 lines with the inline plugin; a build config file that quietly owns a chunk of the public URL surface is harder to discover than a plugin with a descriptive filename. Move the plugin into packages/connector-ui/vite-plugins/mirror-skills.ts and import it. Behaviour-preserving move — build output is byte-identical. The following commit tightens the emit contract. Also extend tsconfig.node.json's include to cover the new plugin file so it gets typechecked alongside vite.config.ts. --- packages/connector-ui/tsconfig.node.json | 2 +- .../connector-ui/tsconfig.node.tsbuildinfo | 2 +- .../vite-plugins/mirror-skills.ts | 84 ++++++++++++++++++ packages/connector-ui/vite.config.ts | 85 +------------------ 4 files changed, 87 insertions(+), 86 deletions(-) create mode 100644 packages/connector-ui/vite-plugins/mirror-skills.ts diff --git a/packages/connector-ui/tsconfig.node.json b/packages/connector-ui/tsconfig.node.json index 0d3d714..98f5e42 100644 --- a/packages/connector-ui/tsconfig.node.json +++ b/packages/connector-ui/tsconfig.node.json @@ -18,5 +18,5 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "vite-plugins/**/*.ts"] } diff --git a/packages/connector-ui/tsconfig.node.tsbuildinfo b/packages/connector-ui/tsconfig.node.tsbuildinfo index 62c7bf9..cbccb2c 100644 --- a/packages/connector-ui/tsconfig.node.tsbuildinfo +++ b/packages/connector-ui/tsconfig.node.tsbuildinfo @@ -1 +1 @@ -{"root":["./vite.config.ts"],"version":"5.9.3"} \ No newline at end of file +{"root":["./vite.config.ts","./vite-plugins/mirror-skills.ts"],"version":"5.9.3"} \ No newline at end of file diff --git a/packages/connector-ui/vite-plugins/mirror-skills.ts b/packages/connector-ui/vite-plugins/mirror-skills.ts new file mode 100644 index 0000000..bad4b74 --- /dev/null +++ b/packages/connector-ui/vite-plugins/mirror-skills.ts @@ -0,0 +1,84 @@ +import type { Plugin } from 'vite'; + +import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +// Mirror skills/ at the repo root onto the following URL surface, purely in +// memory — no symlinks, no committed duplicates: +// +// /SKILL.md <- skills/SKILL.md (root entrypoint) +// /skills/<...> <- skills/<...> (full tree) +// //SKILL.md <- skills//SKILL.md +// (compat with URLs referenced in older +// CLIs' bundled root SKILL.md) +// +// Every pattern is derived dynamically from skills/ contents at build and +// dev-server startup. Adding skills//SKILL.md starts serving +// /skills//SKILL.md and //SKILL.md automatically. +export function mirrorSkills(): Plugin { + const here = dirname(fileURLToPath(import.meta.url)); + const skillsDir = resolve(here, '../../../skills'); + + const withinSkillsDir = (candidate: string) => + candidate === skillsDir || candidate.startsWith(`${skillsDir}/`); + + const contentType = (file: string) => + file.endsWith('.md') ? 'text/markdown; charset=utf-8' : 'application/octet-stream'; + + function walk(dir: string, prefix: string, emit: (fileName: string, source: Buffer) => void) { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const full = resolve(dir, entry.name); + if (entry.isDirectory()) { + walk(full, `${prefix}${entry.name}/`, emit); + } else { + emit(`${prefix}${entry.name}`, readFileSync(full)); + } + } + } + + function resolveRequest(url: string): string | null { + if (url === '/SKILL.md') return resolve(skillsDir, 'SKILL.md'); + if (url.startsWith('/skills/')) return resolve(skillsDir, url.slice('/skills/'.length)); + const match = url.match(/^\/([^/]+)\/SKILL\.md$/); + if (match) return resolve(skillsDir, match[1], 'SKILL.md'); + return null; + } + + return { + name: 'mirror-skills', + configureServer(server) { + server.middlewares.use((req, res, next) => { + const url = req.url?.split('?')[0] ?? ''; + const file = resolveRequest(url); + if (file && withinSkillsDir(file) && existsSync(file) && statSync(file).isFile()) { + res.setHeader('content-type', contentType(file)); + res.end(readFileSync(file)); + return; + } + next(); + }); + }, + generateBundle() { + if (!existsSync(skillsDir)) return; + + const emit = (fileName: string, source: Buffer) => { + this.emitFile({ type: 'asset', fileName, source }); + }; + + // /SKILL.md + emit('SKILL.md', readFileSync(resolve(skillsDir, 'SKILL.md'))); + + // /skills/* (whole tree, recursive) + walk(skillsDir, 'skills/', emit); + + // //SKILL.md (compat mirror for older-CLI URLs) + for (const entry of readdirSync(skillsDir, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const file = resolve(skillsDir, entry.name, 'SKILL.md'); + if (!existsSync(file)) continue; + emit(`${entry.name}/SKILL.md`, readFileSync(file)); + } + } + }; +} diff --git a/packages/connector-ui/vite.config.ts b/packages/connector-ui/vite.config.ts index 1a343d0..1db9486 100644 --- a/packages/connector-ui/vite.config.ts +++ b/packages/connector-ui/vite.config.ts @@ -1,91 +1,8 @@ -import type { Plugin } from 'vite'; - -import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; -// Mirror skills/ at the repo root onto the following URL surface, purely in -// memory — no symlinks, no committed duplicates: -// -// /SKILL.md <- skills/SKILL.md (root entrypoint) -// /skills/<...> <- skills/<...> (full tree) -// //SKILL.md <- skills//SKILL.md -// (compat with URLs referenced in older -// CLIs' bundled root SKILL.md) -// -// Every pattern is derived dynamically from skills/ contents at build and -// dev-server startup. Adding skills//SKILL.md starts serving -// /skills//SKILL.md and //SKILL.md automatically. -function mirrorSkills(): Plugin { - const here = dirname(fileURLToPath(import.meta.url)); - const skillsDir = resolve(here, '../../skills'); - - const withinSkillsDir = (candidate: string) => - candidate === skillsDir || candidate.startsWith(`${skillsDir}/`); - - const contentType = (file: string) => - file.endsWith('.md') ? 'text/markdown; charset=utf-8' : 'application/octet-stream'; - - function walk(dir: string, prefix: string, emit: (fileName: string, source: Buffer) => void) { - for (const entry of readdirSync(dir, { withFileTypes: true })) { - const full = resolve(dir, entry.name); - if (entry.isDirectory()) { - walk(full, `${prefix}${entry.name}/`, emit); - } else { - emit(`${prefix}${entry.name}`, readFileSync(full)); - } - } - } - - function resolveRequest(url: string): string | null { - if (url === '/SKILL.md') return resolve(skillsDir, 'SKILL.md'); - if (url.startsWith('/skills/')) return resolve(skillsDir, url.slice('/skills/'.length)); - const match = url.match(/^\/([^/]+)\/SKILL\.md$/); - if (match) return resolve(skillsDir, match[1], 'SKILL.md'); - return null; - } - - return { - name: 'mirror-skills', - configureServer(server) { - server.middlewares.use((req, res, next) => { - const url = req.url?.split('?')[0] ?? ''; - const file = resolveRequest(url); - if (file && withinSkillsDir(file) && existsSync(file) && statSync(file).isFile()) { - res.setHeader('content-type', contentType(file)); - res.end(readFileSync(file)); - return; - } - next(); - }); - }, - generateBundle() { - if (!existsSync(skillsDir)) return; - - const emit = (fileName: string, source: Buffer) => { - this.emitFile({ type: 'asset', fileName, source }); - }; - - // /SKILL.md - emit('SKILL.md', readFileSync(resolve(skillsDir, 'SKILL.md'))); - - // /skills/* (whole tree, recursive) - walk(skillsDir, 'skills/', emit); - - // //SKILL.md (compat mirror for older-CLI URLs) - for (const entry of readdirSync(skillsDir, { withFileTypes: true })) { - if (!entry.isDirectory()) continue; - const file = resolve(skillsDir, entry.name, 'SKILL.md'); - if (!existsSync(file)) continue; - emit(`${entry.name}/SKILL.md`, readFileSync(file)); - } - } - }; -} +import { mirrorSkills } from './vite-plugins/mirror-skills'; // https://vite.dev/config/ export default defineConfig({ From c2aa3ce2140421b934742ba42b1c31a5f1a57a63 Mon Sep 17 00:00:00 2001 From: Daryl Collins Date: Tue, 21 Apr 2026 16:20:37 +0100 Subject: [PATCH 6/6] refactor(connector-ui): restrict mirror-skills to explicit SKILL.md paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recursive walk that emitted /skills/<...> was inherited from the old pre-commit hook's copyDir. It would blindly publish every file under skills/ — a stray .DS_Store, a repo-local README explaining the skill-authoring convention, lint config, any future skills/examples/foo.md would all reach the CDN with no gatekeeping. Drop the walk. The SKILL protocol defines exactly one file per skill directory (SKILL.md), so the emit surface is now an explicit enumeration of that contract: /SKILL.md <- skills/SKILL.md /skills/SKILL.md <- skills/SKILL.md /skills//SKILL.md <- skills//SKILL.md //SKILL.md <- skills//SKILL.md (flattened mirror, compat with URLs in older CLIs' root SKILL.md) Anything else in skills/ — whether accidental (.DS_Store) or intentional (examples, images) — is not served. If a future sub-skill needs non-SKILL.md assets, extend the plugin explicitly. Middleware's resolveRequest tightened to match: only recognises /SKILL.md, /skills/SKILL.md, //SKILL.md, and /skills//SKILL.md. Path traversal guarded by the regex (single path component only) plus the existing withinSkillsDir check for defence in depth. Build output unchanged — same 8 SKILL.md paths in dist/ with identical byte content to the previous commit. --- .../vite-plugins/mirror-skills.ts | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/connector-ui/vite-plugins/mirror-skills.ts b/packages/connector-ui/vite-plugins/mirror-skills.ts index bad4b74..7bf20e4 100644 --- a/packages/connector-ui/vite-plugins/mirror-skills.ts +++ b/packages/connector-ui/vite-plugins/mirror-skills.ts @@ -4,18 +4,26 @@ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -// Mirror skills/ at the repo root onto the following URL surface, purely in -// memory — no symlinks, no committed duplicates: +// Mirror skills/ at the repo root onto an explicit, enumerated URL surface. +// The SKILL protocol defines one file per skill directory (SKILL.md), and +// the published surface is exactly that — nothing else from skills/ is +// served, so stray files (.DS_Store, repo-local READMEs, lint configs) +// cannot leak to the CDN. // -// /SKILL.md <- skills/SKILL.md (root entrypoint) -// /skills/<...> <- skills/<...> (full tree) +// Emitted paths, derived from skills/ contents at build and dev-server +// startup: +// +// /SKILL.md <- skills/SKILL.md +// /skills/SKILL.md <- skills/SKILL.md +// /skills//SKILL.md <- skills//SKILL.md // //SKILL.md <- skills//SKILL.md -// (compat with URLs referenced in older -// CLIs' bundled root SKILL.md) +// (flattened mirror; compat with URLs +// referenced in older CLIs' bundled +// root SKILL.md) // -// Every pattern is derived dynamically from skills/ contents at build and -// dev-server startup. Adding skills//SKILL.md starts serving -// /skills//SKILL.md and //SKILL.md automatically. +// Adding skills//SKILL.md starts serving both +// /skills//SKILL.md and //SKILL.md automatically +// on the next build. export function mirrorSkills(): Plugin { const here = dirname(fileURLToPath(import.meta.url)); const skillsDir = resolve(here, '../../../skills'); @@ -23,26 +31,13 @@ export function mirrorSkills(): Plugin { const withinSkillsDir = (candidate: string) => candidate === skillsDir || candidate.startsWith(`${skillsDir}/`); - const contentType = (file: string) => - file.endsWith('.md') ? 'text/markdown; charset=utf-8' : 'application/octet-stream'; - - function walk(dir: string, prefix: string, emit: (fileName: string, source: Buffer) => void) { - for (const entry of readdirSync(dir, { withFileTypes: true })) { - const full = resolve(dir, entry.name); - if (entry.isDirectory()) { - walk(full, `${prefix}${entry.name}/`, emit); - } else { - emit(`${prefix}${entry.name}`, readFileSync(full)); - } - } - } - function resolveRequest(url: string): string | null { - if (url === '/SKILL.md') return resolve(skillsDir, 'SKILL.md'); - if (url.startsWith('/skills/')) return resolve(skillsDir, url.slice('/skills/'.length)); - const match = url.match(/^\/([^/]+)\/SKILL\.md$/); - if (match) return resolve(skillsDir, match[1], 'SKILL.md'); - return null; + if (url === '/SKILL.md' || url === '/skills/SKILL.md') { + return resolve(skillsDir, 'SKILL.md'); + } + const match = url.match(/^\/(?:skills\/)?([^/]+)\/SKILL\.md$/); + if (!match) return null; + return resolve(skillsDir, match[1], 'SKILL.md'); } return { @@ -52,7 +47,7 @@ export function mirrorSkills(): Plugin { const url = req.url?.split('?')[0] ?? ''; const file = resolveRequest(url); if (file && withinSkillsDir(file) && existsSync(file) && statSync(file).isFile()) { - res.setHeader('content-type', contentType(file)); + res.setHeader('content-type', 'text/markdown; charset=utf-8'); res.end(readFileSync(file)); return; } @@ -62,22 +57,27 @@ export function mirrorSkills(): Plugin { generateBundle() { if (!existsSync(skillsDir)) return; + const rootSkill = resolve(skillsDir, 'SKILL.md'); + if (!existsSync(rootSkill)) return; + const emit = (fileName: string, source: Buffer) => { this.emitFile({ type: 'asset', fileName, source }); }; - // /SKILL.md - emit('SKILL.md', readFileSync(resolve(skillsDir, 'SKILL.md'))); - - // /skills/* (whole tree, recursive) - walk(skillsDir, 'skills/', emit); + // Root entrypoint — served at both /SKILL.md and /skills/SKILL.md + const rootSource = readFileSync(rootSkill); + emit('SKILL.md', rootSource); + emit('skills/SKILL.md', rootSource); - // //SKILL.md (compat mirror for older-CLI URLs) + // Each sub-skill, served at both /skills//SKILL.md (structured) + // and //SKILL.md (flattened, for older-CLI URL compat) for (const entry of readdirSync(skillsDir, { withFileTypes: true })) { if (!entry.isDirectory()) continue; const file = resolve(skillsDir, entry.name, 'SKILL.md'); if (!existsSync(file)) continue; - emit(`${entry.name}/SKILL.md`, readFileSync(file)); + const source = readFileSync(file); + emit(`skills/${entry.name}/SKILL.md`, source); + emit(`${entry.name}/SKILL.md`, source); } } };