diff --git a/packages/polygon-agent-cli/package.json b/packages/polygon-agent-cli/package.json index 65521ff..b4776dd 100644 --- a/packages/polygon-agent-cli/package.json +++ b/packages/polygon-agent-cli/package.json @@ -35,10 +35,13 @@ "@0xsequence/wallet-primitives": "3.0.0-beta.16", "@0xsequence/wallet-wdk": "3.0.0-beta.16", "@0xtrails/api": "^0.10.4", + "@polymarket/clob-client": "^5.2.4", + "@polymarket/sdk": "^6.0.1", "@x402/core": "^2.3.1", "@x402/evm": "^2.3.1", "@x402/fetch": "^2.3.0", "dotenv": "^16.4.5", + "ethers5": "npm:ethers@^5.7.4", "ethers": "^6.13.0", "tweetnacl": "^1.0.3", "tweetnacl-sealedbox-js": "^1.2.0", diff --git a/packages/polygon-agent-cli/skills/POLYMARKET.md b/packages/polygon-agent-cli/skills/POLYMARKET.md new file mode 100644 index 0000000..8c94b52 --- /dev/null +++ b/packages/polygon-agent-cli/skills/POLYMARKET.md @@ -0,0 +1,267 @@ +--- +name: polymarket +description: Developer and architecture reference for the Polymarket integration in Polygon Agent CLI. Covers the 3-address system, proxy wallet factory, on-chain approval model, CLOB auth, neg-risk markets, and SDK internals. +--- + +# Polymarket Integration — Developer Reference + +## The 3-Address Architecture + +Every Polymarket user has exactly three addresses. Understanding the distinction is critical. + +``` +EOA (0x19A413...) + │ Your private key. Signs every on-chain tx and every CLOB API request. + │ Holds POL for gas. Never holds USDC or outcome tokens directly. + │ + │ calls factory.execute([...txs]) + ▼ +Proxy Wallet Factory (0xaB45c5A4...) + │ Owns all proxy wallets. Routes execute() calls to the correct proxy + │ by looking up the EOA → proxy mapping internally. + │ + ▼ +Proxy Wallet (0x07E35CC...) + │ Your "Polymarket account" address — shown in the Polymarket UI. + │ Holds USDC.e and outcome (CTF) tokens. + │ The CLOB uses this as the order `maker`. + │ Address is deterministic: CREATE2(factory, EOA) — never changes. + │ + ▼ +CLOB — maker=proxyWallet, signer=EOA, signatureType=POLY_PROXY + +Deposit Address (0x7c583...) + A separate bridge ingress contract generated by Polymarket's bridge API. + Linked to the proxy wallet — assets sent here (from Ethereum, Arbitrum, + Solana, BTC, Tron) are auto-bridged and credited to the proxy wallet as USDC.e. + Polygon-native flows do NOT use the deposit address. + Send USDC.e directly to the proxy wallet address on Polygon. +``` + +### Address Summary Table + +| Address | Where it appears | Holds | Purpose | +|---------|-----------------|-------|---------| +| EOA | `eoaAddress` in CLI output | POL (gas only) | Signs txs + CLOB requests | +| Proxy Wallet | Polymarket UI "your address" | USDC.e + outcome tokens | On-chain trading identity | +| Deposit Address | Polymarket UI deposit flow | Nothing (pass-through) | Cross-chain bridge ingress | + +### Where the EOA Key Comes From + +**Option A — Email login (Polymarket website)** +1. Create account at polymarket.com using email (Magic Link) +2. After accepting Terms of Service, go to: https://reveal.magic.link/polymarket +3. Export your private key from there +4. The address shown in the Polymarket UI is the **proxy wallet**, not the EOA +5. The EOA address is visible in a connected wallet app (e.g. MetaMask after importing the key) +6. Import into CLI: `polygon-agent polymarket set-key ` + +**Option B — Use the builder EOA from `polygon-agent setup`** +The builder EOA created during setup can be used directly — skip `set-key`. +Run `polygon-agent polymarket proxy-wallet` to see the derived proxy wallet address. + +--- + +## On-Chain Architecture: The Factory Pattern + +### Why `factory.execute()` and not `proxy.execute()` + +Polymarket's v1 proxy wallet factory changed the ownership model. The factory itself is the **owner** of all proxy wallets. The EOA does not own the proxy directly. + +``` +proxy._OWNER_SLOT → stores factory address (0xaB45c5A4...) + NOT the EOA address + +proxy.execute() → reverts: "must be called be owner" +factory.execute(txs) → factory checks EOA → proxy mapping, calls proxy internally ✓ +``` + +Both `proxy.execute()` and `factory.execute()` take the same ABI: +```solidity +function execute(Transaction[] calldata transactions) external returns (bytes[] memory) + +struct Transaction { + uint8 typeCode; // 1 = CALL + address to; + uint256 value; + bytes data; +} +``` + +The CLI always calls `factory.execute()` at `0xaB45c5A4B0c941a2F231C04C3f49182e1A254052`. + +### Proxy Wallet Address Derivation + +The proxy wallet address is deterministic (CREATE2). Given an EOA address: +```ts +import { getProxyWalletAddress } from '@polymarket/sdk'; +const proxyWallet = getProxyWalletAddress(PROXY_WALLET_FACTORY, eoaAddress); +``` + +This matches the address shown in the Polymarket UI. The address never changes. + +--- + +## On-Chain Approvals + +Before trading, the proxy wallet must grant token allowances to the exchange contracts. These are **permanent** — set once, never need repeating (unless you need neg-risk). + +### Standard Markets (negRisk: false) + +``` +proxy wallet grants: + USDC.e.approve(CTF_EXCHANGE, MAX_UINT256) + CTF.setApprovalForAll(CTF_EXCHANGE, true) +``` + +### Neg-Risk Markets (negRisk: true) + +``` +proxy wallet grants: + USDC.e.approve(NEG_RISK_ADAPTER, MAX_UINT256) + USDC.e.approve(NEG_RISK_CTF_EXCHANGE, MAX_UINT256) + CTF.setApprovalForAll(CTF_EXCHANGE, true) + CTF.setApprovalForAll(NEG_RISK_CTF_EXCHANGE, true) + CTF.setApprovalForAll(NEG_RISK_ADAPTER, true) +``` + +All approvals are batched into a single `factory.execute([...txBatch])` transaction. The EOA pays POL gas (~0.001 POL per approval batch). + +--- + +## CLOB Authentication + +The CLOB uses a two-layer auth system: + +**L1 Auth (EIP-712)** — Used to create/derive API credentials. Signs a typed message with the EOA private key. Polymarket derives a deterministic API keypair from this. No stored secrets needed. + +**L2 Auth (HMAC)** — Used for all trading endpoints. HMAC-SHA256 over `timestamp + method + path + body` using the derived API secret. + +Both layers are handled transparently by `@polymarket/clob-client`: +```ts +const creds = await client.createOrDeriveApiKey(); // L1 auth → derives L2 creds +const client = new ClobClient(CLOB_URL, 137, signer, creds, SignatureType.POLY_PROXY, proxyWalletAddress); +``` + +`createOrDeriveApiKey()` is idempotent — safe to call every session. + +**Important:** The EOA must have accepted Polymarket's Terms of Service at polymarket.com at least once. Without this, `createOrDeriveApiKey()` returns `400 "Could not create api key"`. The CLI handles this gracefully (falls back to `deriveApiKey`) but CLOB order posting will fail if ToS was never accepted. + +### Order Signing: POLY_PROXY Signature Type + +``` +maker = proxyWalletAddress (who is committing funds) +signer = EOA address (who signs the EIP-712 payload) +signatureType = POLY_PROXY (tells exchange to verify via proxy wallet ownership) +``` + +The EIP-712 domain `verifyingContract` is `CTF_EXCHANGE` for standard markets and `NEG_RISK_CTF_EXCHANGE` for neg-risk markets. + +--- + +## Gas Model + +| Operation | Who pays | Token | Approx cost | +|-----------|----------|-------|-------------| +| `approve --broadcast` | EOA | POL | ~0.001 POL | +| `clob-buy --broadcast` (fund step) | Sequence relayer | USDC.e | ~$0.01–0.05 USDC.e | +| `clob-buy --broadcast` (order step) | Off-chain | — | Free | +| `sell --broadcast` | Off-chain | — | Free | + +The Sequence gas abstraction (USDC.e fee token) only applies to smart wallet transactions. The EOA must hold POL for the `approve` step. After that, only the Sequence smart wallet needs USDC.e. + +--- + +## Funding Flow (Polygon-Native) + +``` +Sequence Smart Wallet (holds USDC.e) + │ + │ ERC20 transfer: USDC.e → proxy wallet + │ (Sequence tx, paid in USDC.e via fee abstraction) + ▼ +Proxy Wallet (now has USDC.e for trading) + │ + │ CLOB BUY order (off-chain, no gas) + ▼ +Outcome tokens arrive in proxy wallet +``` + +`clob-buy` without `--skip-fund` performs both steps atomically. +`--skip-fund` skips the transfer and uses whatever USDC.e is already in the proxy wallet. + +**Cross-chain funding** (not implemented in CLI — manual): +Use the deposit address from Polymarket UI to bridge from other chains. Assets auto-convert to USDC.e on Polygon. + +--- + +## SDK Stack + +| Package | Version | Used for | +|---------|---------|----------| +| `@polymarket/clob-client` | latest | CLOB API: order creation, posting, cancellation, open orders | +| `@polymarket/sdk` | latest | Proxy wallet address derivation (`getProxyWalletAddress`) | +| `@polymarket/order-utils` | latest | `SignatureType` enum (POLY_PROXY, EOA) | +| `ethers5` | aliased | Required by `@polymarket/clob-client` (ethers v5 only); aliased to coexist with main ethers v6 | +| `viem` | project default | `encodeFunctionData`, wallet/public clients for on-chain calls | + +`ethers5` is aliased in `package.json`: +```json +"ethers5": "npm:ethers@5" +``` + +--- + +## Contracts (Polygon Mainnet, Chain 137) + +| Contract | Address | +|----------|---------| +| USDC.e | `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174` | +| CTF (Conditional Token Framework) | `0x4D97DCd97eC945f40cF65F87097ACe5EA0476045` | +| CTF Exchange | `0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E` | +| Neg Risk CTF Exchange | `0xC5d563A36AE78145C45a50134d48A1215220f80a` | +| Neg Risk Adapter | `0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296` | +| Proxy Wallet Factory | `0xaB45c5A4B0c941a2F231C04C3f49182e1A254052` | + +--- + +## APIs + +| API | Base URL | Auth | +|-----|----------|------| +| Gamma (market discovery) | `https://gamma-api.polymarket.com` | None | +| CLOB (trading) | `https://clob.polymarket.com` | EIP-712 L1 + HMAC L2 | +| Data (positions, trades) | `https://data-api.polymarket.com` | None | +| Bridge | `https://bridge.polymarket.com` | None (deposit address creation) | + +Override via env: `POLYMARKET_GAMMA_URL`, `POLYMARKET_CLOB_URL`, `POLYMARKET_DATA_URL`. + +--- + +## Neg-Risk Markets + +Neg-risk markets are multi-outcome markets (e.g. "Which team wins the NBA Finals?") where outcomes are negatively correlated — if one wins, all others lose. They use different exchange contracts. + +**Detection:** `negRisk: true` in Gamma API market response. + +**Approval difference:** + +| Approval | Standard | Neg-Risk | +|----------|---------|---------| +| USDC.e approve | CTF_EXCHANGE | NEG_RISK_ADAPTER + NEG_RISK_CTF_EXCHANGE | +| CTF setApprovalForAll | CTF_EXCHANGE | CTF_EXCHANGE + NEG_RISK_CTF_EXCHANGE + NEG_RISK_ADAPTER | + +Run `polygon-agent polymarket approve --neg-risk --broadcast` once to enable neg-risk trading. If you already ran standard `approve`, run neg-risk `approve` on top — it adds the missing approvals. + +**Order difference:** The `negRisk: true` option must be passed to `createOrder`/`createMarketOrder` in the CLOB client. The CLI handles this automatically based on the Gamma market data. + +--- + +## Key Implementation Notes + +- **`executeViaProxyWallet` always calls the factory**, not the proxy. `to: PROXY_WALLET_FACTORY`. Calling the proxy directly reverts with "must be called be owner". +- **`positions` command queries the proxy wallet**, not the Sequence smart wallet. The Data API lookup is by `proxyWalletAddress`. +- **`loadPolymarketKey()` has a fallback**: returns the Polymarket-specific key if `set-key` was called, otherwise falls back to the builder EOA key from `setup`. Both are stored encrypted in `~/.polygon-agent/builder.json`. +- **CLOB API key derivation is stateless** — `createOrDeriveApiKey()` always produces the same credentials from the same EOA private key. No API keys are stored on disk. +- **FOK vs FAK vs GTC**: FOK (default) must fill entirely or cancels. FAK allows partial fills. GTC stays open until manually cancelled. Use GTC with `--price` for limit orders. +- **CLOB minimum order size is $1 USD** for marketable BUY orders. Orders below $1 are rejected with `"invalid amount for a marketable BUY order ($X), min size: $1"`. If the fund step completed before the rejection, USDC.e is already in the proxy wallet — retry with `--skip-fund`. diff --git a/packages/polygon-agent-cli/skills/polymarket-skill.md b/packages/polygon-agent-cli/skills/polymarket-skill.md new file mode 100644 index 0000000..0cac0ff --- /dev/null +++ b/packages/polygon-agent-cli/skills/polymarket-skill.md @@ -0,0 +1,330 @@ +--- +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/src/commands/polymarket.ts b/packages/polygon-agent-cli/src/commands/polymarket.ts new file mode 100644 index 0000000..a1cfbae --- /dev/null +++ b/packages/polygon-agent-cli/src/commands/polymarket.ts @@ -0,0 +1,731 @@ +// Polymarket CLI commands +// Architecture: Sequence smart wallet → Polymarket proxy wallet → CLOB +// - `approve`: sets on-chain approvals on proxy wallet (one-time) +// - `clob-buy`: funds proxy wallet from smart wallet, then places CLOB BUY order +// - CLOB orders: maker=proxyWallet, signer=EOA, signatureType=POLY_PROXY + +import type { CommandModule } from 'yargs'; + +import { runDappClientTx } from '../lib/dapp-client.ts'; +import { + getMarkets, + getMarket, + getOpenOrders, + cancelOrder, + createAndPostOrder, + createAndPostMarketOrder, + getPolymarketProxyWalletAddress, + executeViaProxyWallet, + getPositions, + USDC_E, + CTF, + CTF_EXCHANGE, + NEG_RISK_CTF_EXCHANGE, + NEG_RISK_ADAPTER +} from '../lib/polymarket.ts'; +import { loadWalletSession, savePolymarketKey, loadPolymarketKey } from '../lib/storage.ts'; + +// ─── handlers ──────────────────────────────────────────────────────────────── + +async function handleMarkets(argv: { + search?: string; + limit?: number; + offset?: number; +}): Promise { + try { + const markets = await getMarkets({ + search: argv.search, + limit: argv.limit ?? 20, + offset: argv.offset ?? 0 + }); + console.log(JSON.stringify({ ok: true, count: markets.length, markets }, null, 2)); + } catch (err) { + console.error(JSON.stringify({ ok: false, error: (err as Error).message }, null, 2)); + process.exit(1); + } +} + +async function handleMarket(argv: { conditionId: string }): Promise { + try { + const market = await getMarket(argv.conditionId); + console.log(JSON.stringify({ ok: true, market }, null, 2)); + } catch (err) { + console.error(JSON.stringify({ ok: false, error: (err as Error).message }, null, 2)); + process.exit(1); + } +} + +async function handleSetKey(argv: { privateKey: string }): Promise { + const pk = argv.privateKey.startsWith('0x') ? argv.privateKey : `0x${argv.privateKey}`; + + if (!/^0x[0-9a-fA-F]{64}$/.test(pk)) { + console.error( + JSON.stringify( + { ok: false, error: 'Invalid private key — must be 32 bytes (64 hex chars)' }, + null, + 2 + ) + ); + process.exit(1); + } + + try { + const { privateKeyToAccount } = await import('viem/accounts'); + const account = privateKeyToAccount(pk as `0x${string}`); + const proxyWalletAddress = await getPolymarketProxyWalletAddress(account.address); + + await savePolymarketKey(pk); + + console.log( + JSON.stringify( + { + ok: true, + eoaAddress: account.address, + proxyWalletAddress, + note: 'Polymarket signing key saved (encrypted). All polymarket commands will use this EOA. Remember to accept Polymarket ToS at polymarket.com with this address.' + }, + null, + 2 + ) + ); + } catch (err) { + console.error(JSON.stringify({ ok: false, error: (err as Error).message }, null, 2)); + process.exit(1); + } +} + +async function handleProxyWallet(): Promise { + try { + const privateKey = await loadPolymarketKey(); + const { privateKeyToAccount } = await import('viem/accounts'); + const account = privateKeyToAccount(privateKey as `0x${string}`); + const proxyWalletAddress = await getPolymarketProxyWalletAddress(account.address); + + console.log( + JSON.stringify( + { + ok: true, + eoaAddress: account.address, + proxyWalletAddress, + note: 'Fund proxyWalletAddress with USDC.e on Polygon to enable CLOB trading.' + }, + null, + 2 + ) + ); + } catch (err) { + console.error(JSON.stringify({ ok: false, error: (err as Error).message }, null, 2)); + process.exit(1); + } +} + +async function handleApprove(argv: { negRisk?: boolean; broadcast?: boolean }): Promise { + const negRisk = argv.negRisk ?? false; + const broadcast = argv.broadcast ?? false; + + try { + const privateKey = await loadPolymarketKey(); + const { privateKeyToAccount } = await import('viem/accounts'); + const account = privateKeyToAccount(privateKey as `0x${string}`); + const proxyWalletAddress = await getPolymarketProxyWalletAddress(account.address); + + const MAX_UINT256 = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'; + const pad = (val: string, n = 64) => val.replace(/^0x/, '').padStart(n, '0'); + const erc20Approve = (token: string, spender: string, amount: string) => ({ + typeCode: 1, + to: token, + value: '0', + data: '0x095ea7b3' + pad(spender) + pad(amount) + }); + const erc1155ApproveAll = (token: string, operator: string) => ({ + typeCode: 1, + to: token, + value: '0', + data: '0xa22cb465' + pad(operator) + pad('0x01') + }); + + let txBatch; + let approvalLabels: string[]; + if (negRisk) { + txBatch = [ + erc20Approve(USDC_E, NEG_RISK_ADAPTER, MAX_UINT256), + erc20Approve(USDC_E, NEG_RISK_CTF_EXCHANGE, MAX_UINT256), + erc1155ApproveAll(CTF, CTF_EXCHANGE), + erc1155ApproveAll(CTF, NEG_RISK_CTF_EXCHANGE), + erc1155ApproveAll(CTF, NEG_RISK_ADAPTER) + ]; + approvalLabels = [ + 'USDC.e → NEG_RISK_ADAPTER', + 'USDC.e → NEG_RISK_CTF_EXCHANGE', + 'CTF → CTF_EXCHANGE', + 'CTF → NEG_RISK_CTF_EXCHANGE', + 'CTF → NEG_RISK_ADAPTER' + ]; + } else { + txBatch = [ + erc20Approve(USDC_E, CTF_EXCHANGE, MAX_UINT256), + erc1155ApproveAll(CTF, CTF_EXCHANGE) + ]; + approvalLabels = ['USDC.e → CTF_EXCHANGE', 'CTF → CTF_EXCHANGE']; + } + + if (!broadcast) { + console.log( + JSON.stringify( + { + ok: true, + dryRun: true, + proxyWalletAddress, + signerAddress: account.address, + negRisk, + approvals: approvalLabels, + note: 'Re-run with --broadcast to execute. EOA must have POL for gas.' + }, + null, + 2 + ) + ); + return; + } + + const { createWalletClient, createPublicClient, http } = await import('viem'); + const { polygon } = await import('viem/chains'); + const walletClient = createWalletClient({ account, chain: polygon, transport: http() }); + const publicClient = createPublicClient({ chain: polygon, transport: http() }); + + process.stderr.write( + `[polymarket] Setting ${txBatch.length} approvals on proxy wallet ${proxyWalletAddress}...\n` + ); + const approveTxHash = await executeViaProxyWallet( + walletClient, + publicClient, + proxyWalletAddress, + txBatch + ); + process.stderr.write(`[polymarket] Approvals set: ${approveTxHash}\n`); + + console.log( + JSON.stringify( + { + ok: true, + proxyWalletAddress, + signerAddress: account.address, + negRisk, + approveTxHash, + note: 'Proxy wallet approvals set. Ready for clob-buy and sell.' + }, + null, + 2 + ) + ); + } catch (err) { + console.error( + JSON.stringify( + { ok: false, error: (err as Error).message, stack: (err as Error).stack }, + null, + 2 + ) + ); + process.exit(1); + } +} + +async function handleClobBuy(argv: { + conditionId: string; + outcome: string; + amount: number; + wallet?: string; + price?: number; + fak?: boolean; + skipFund?: boolean; + broadcast?: boolean; +}): Promise { + const conditionId = argv.conditionId; + const outcomeArg = argv.outcome.toUpperCase(); + const amountUsd = argv.amount; + const walletName = argv.wallet ?? 'main'; + const priceArg = argv.price; + const useFak = argv.fak ?? false; + const skipFund = argv.skipFund ?? false; + const broadcast = argv.broadcast ?? false; + + if (!['YES', 'NO'].includes(outcomeArg)) { + console.error(JSON.stringify({ ok: false, error: 'Outcome must be YES or NO' }, null, 2)); + process.exit(1); + } + + try { + const market = await getMarket(conditionId); + const tokenId = outcomeArg === 'YES' ? market.yesTokenId : market.noTokenId; + if (!tokenId) + throw new Error(`Market ${conditionId} has no tokenIds (may be closed or invalid)`); + + const currentPrice = outcomeArg === 'YES' ? market.yesPrice : market.noPrice; + const orderType = priceArg ? 'GTC' : useFak ? 'FAK' : 'FOK'; + + if (!broadcast) { + let proxyWalletAddress: string | null = null; + try { + const { privateKeyToAccount } = await import('viem/accounts'); + const pk = await loadPolymarketKey(); + proxyWalletAddress = await getPolymarketProxyWalletAddress( + privateKeyToAccount(pk as `0x${string}`).address + ); + } catch { + /* ignore */ + } + + console.log( + JSON.stringify( + { + ok: true, + dryRun: true, + conditionId, + question: market.question, + outcome: outcomeArg, + tokenId, + currentPrice, + amountUsd, + orderType, + price: priceArg ?? 'market', + proxyWalletAddress, + flow: skipFund + ? ['Place CLOB BUY order (using existing proxy wallet USDC.e balance)'] + : [ + `Smart wallet (${walletName}) → fund proxy wallet with ${amountUsd} USDC.e`, + 'Place CLOB BUY order (maker=proxyWallet, signatureType=POLY_PROXY)' + ], + note: 'Requires proxy wallet approvals — run `polymarket approve --broadcast` once first. Re-run with --broadcast to execute.' + }, + null, + 2 + ) + ); + return; + } + + const [session, privateKey] = await Promise.all([ + loadWalletSession(walletName), + loadPolymarketKey() + ]); + if (!session) throw new Error(`Wallet not found: ${walletName}`); + + const { privateKeyToAccount } = await import('viem/accounts'); + const account = privateKeyToAccount(privateKey as `0x${string}`); + const proxyWalletAddress = await getPolymarketProxyWalletAddress(account.address); + process.stderr.write( + `[polymarket] CLOB BUY ${amountUsd} USDC → ${outcomeArg} via proxy wallet ${proxyWalletAddress}\n` + ); + + let fundTxHash: string | null = null; + if (skipFund) { + process.stderr.write(`[polymarket] --skip-fund: using existing proxy wallet balance\n`); + } else { + process.stderr.write( + `[polymarket] Funding proxy wallet ${proxyWalletAddress} with ${amountUsd} USDC.e...\n` + ); + const amountUnits = BigInt(Math.round(amountUsd * 1e6)); + const pad = (hex: string, n = 64) => String(hex).replace(/^0x/, '').padStart(n, '0'); + const transferData = + '0xa9059cbb' + pad(proxyWalletAddress) + pad('0x' + amountUnits.toString(16)); + const fundResult = await runDappClientTx({ + walletName, + chainId: 137, + transactions: [{ to: USDC_E, value: 0n, data: transferData }], + broadcast: true, + preferNativeFee: false + }); + fundTxHash = fundResult.txHash ?? null; + process.stderr.write(`[polymarket] Funded: ${fundTxHash}\n`); + } + + let orderResult; + if (priceArg) { + const estimatedShares = amountUsd / priceArg; + orderResult = await createAndPostOrder({ + tokenId, + side: 'BUY', + size: estimatedShares, + price: priceArg, + orderType: 'GTC', + privateKey, + proxyWalletAddress + }); + } else { + orderResult = await createAndPostMarketOrder({ + tokenId, + side: 'BUY', + amount: amountUsd, + orderType, + privateKey, + proxyWalletAddress + }); + } + + console.log( + JSON.stringify( + { + ok: true, + conditionId, + question: market.question, + outcome: outcomeArg, + amountUsd, + currentPrice, + proxyWalletAddress, + signerAddress: account.address, + fundTxHash, + orderId: orderResult?.orderId || orderResult?.orderID || orderResult?.id || null, + orderType, + orderStatus: orderResult?.status || null + }, + null, + 2 + ) + ); + } catch (err) { + console.error( + JSON.stringify( + { ok: false, error: (err as Error).message, stack: (err as Error).stack }, + null, + 2 + ) + ); + process.exit(1); + } +} + +async function handleSell(argv: { + conditionId: string; + outcome: string; + shares: number; + price?: number; + fak?: boolean; + broadcast?: boolean; +}): Promise { + const conditionId = argv.conditionId; + const outcomeArg = argv.outcome.toUpperCase(); + const shares = argv.shares; + const priceArg = argv.price; + const useFak = argv.fak ?? false; + const broadcast = argv.broadcast ?? false; + + if (!['YES', 'NO'].includes(outcomeArg)) { + console.error(JSON.stringify({ ok: false, error: 'Outcome must be YES or NO' }, null, 2)); + process.exit(1); + } + + try { + const market = await getMarket(conditionId); + const tokenId = outcomeArg === 'YES' ? market.yesTokenId : market.noTokenId; + if (!tokenId) + throw new Error(`Market ${conditionId} has no tokenIds (may be closed or invalid)`); + + const currentPrice = outcomeArg === 'YES' ? market.yesPrice : market.noPrice; + const estimatedUsd = shares * (currentPrice || 0); + + if (!broadcast) { + let proxyWalletAddress: string | null = null; + try { + const { privateKeyToAccount } = await import('viem/accounts'); + const pk = await loadPolymarketKey(); + proxyWalletAddress = await getPolymarketProxyWalletAddress( + privateKeyToAccount(pk as `0x${string}`).address + ); + } catch { + /* ignore */ + } + + console.log( + JSON.stringify( + { + ok: true, + dryRun: true, + conditionId, + question: market.question, + outcome: outcomeArg, + tokenId, + shares, + currentPrice, + estimatedUsd: Math.round(estimatedUsd * 100) / 100, + orderType: priceArg ? 'GTC' : useFak ? 'FAK' : 'FOK', + price: priceArg ?? 'market', + proxyWalletAddress, + note: 'Direct CLOB SELL of existing position. Tokens must be in proxy wallet. Re-run with --broadcast.' + }, + null, + 2 + ) + ); + return; + } + + const privateKey = await loadPolymarketKey(); + const { privateKeyToAccount } = await import('viem/accounts'); + const account = privateKeyToAccount(privateKey as `0x${string}`); + const proxyWalletAddress = await getPolymarketProxyWalletAddress(account.address); + process.stderr.write( + `[polymarket] CLOB SELL ${shares} ${outcomeArg} tokens via proxy wallet ${proxyWalletAddress}\n` + ); + + let orderResult; + if (priceArg) { + orderResult = await createAndPostOrder({ + tokenId, + side: 'SELL', + size: shares, + price: priceArg, + orderType: 'GTC', + privateKey, + proxyWalletAddress + }); + } else { + const orderType = useFak ? 'FAK' : 'FOK'; + orderResult = await createAndPostMarketOrder({ + tokenId, + side: 'SELL', + amount: shares, + orderType, + privateKey, + proxyWalletAddress + }); + } + + console.log( + JSON.stringify( + { + ok: true, + conditionId, + question: market.question, + outcome: outcomeArg, + shares, + currentPrice, + estimatedUsd: Math.round(estimatedUsd * 100) / 100, + proxyWalletAddress, + signerAddress: account.address, + orderId: orderResult?.orderId || orderResult?.orderID || orderResult?.id || null, + orderStatus: orderResult?.status || null + }, + null, + 2 + ) + ); + } catch (err) { + console.error( + JSON.stringify( + { ok: false, error: (err as Error).message, stack: (err as Error).stack }, + null, + 2 + ) + ); + process.exit(1); + } +} + +async function handlePositions(): Promise { + try { + const privateKey = await loadPolymarketKey(); + const { privateKeyToAccount } = await import('viem/accounts'); + const account = privateKeyToAccount(privateKey as `0x${string}`); + const proxyWalletAddress = await getPolymarketProxyWalletAddress(account.address); + + const positions = await getPositions(proxyWalletAddress); + console.log( + JSON.stringify( + { + ok: true, + proxyWalletAddress, + count: Array.isArray(positions) ? positions.length : 0, + positions + }, + null, + 2 + ) + ); + } catch (err) { + console.error(JSON.stringify({ ok: false, error: (err as Error).message }, null, 2)); + process.exit(1); + } +} + +async function handleOrders(): Promise { + try { + const privateKey = await loadPolymarketKey(); + const orders = await getOpenOrders(privateKey); + console.log( + JSON.stringify( + { + ok: true, + count: Array.isArray(orders) ? orders.length : 0, + orders + }, + null, + 2 + ) + ); + } catch (err) { + console.error(JSON.stringify({ ok: false, error: (err as Error).message }, null, 2)); + process.exit(1); + } +} + +async function handleCancel(argv: { orderId: string }): Promise { + try { + const privateKey = await loadPolymarketKey(); + const result = await cancelOrder(argv.orderId, privateKey); + console.log(JSON.stringify({ ok: true, orderId: argv.orderId, result }, null, 2)); + } catch (err) { + console.error(JSON.stringify({ ok: false, error: (err as Error).message }, null, 2)); + process.exit(1); + } +} + +// ─── Command module ─────────────────────────────────────────────────────────── + +export const polymarketCommand: CommandModule = { + command: 'polymarket', + describe: 'Polymarket prediction market trading', + builder: (yargs) => + yargs + .command({ + command: 'markets', + describe: 'List active markets by volume', + builder: (y) => + y + .option('search', { type: 'string', describe: 'Filter by question text' }) + .option('limit', { type: 'number', default: 20, describe: 'Number of results' }) + .option('offset', { type: 'number', default: 0, describe: 'Pagination offset' }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handler: (argv) => handleMarkets(argv as any) + }) + .command({ + command: 'market ', + describe: 'Get a single market by conditionId', + builder: (y) => + y.positional('conditionId', { + type: 'string', + demandOption: true, + describe: 'Market condition ID' + }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handler: (argv) => handleMarket(argv as any) + }) + .command({ + command: 'set-key ', + describe: 'Import EOA private key for Polymarket signing (stored encrypted)', + builder: (y) => + y.positional('privateKey', { + type: 'string', + demandOption: true, + describe: 'EOA private key (hex)' + }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handler: (argv) => handleSetKey(argv as any) + }) + .command({ + command: 'proxy-wallet', + describe: 'Show Polymarket proxy wallet address for the active EOA', + builder: (y) => y, + handler: () => handleProxyWallet() + }) + .command({ + command: 'approve', + describe: 'Set proxy wallet approvals (run once before clob-buy)', + builder: (y) => + y + .option('neg-risk', { + type: 'boolean', + default: false, + describe: 'Set neg-risk approvals' + }) + .option('broadcast', { + type: 'boolean', + default: false, + describe: 'Execute (dry-run without)' + }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handler: (argv) => handleApprove(argv as any) + }) + .command({ + command: 'clob-buy ', + describe: 'Buy YES/NO tokens via CLOB (funds proxy wallet first)', + builder: (y) => + y + .positional('conditionId', { type: 'string', demandOption: true }) + .positional('outcome', { type: 'string', demandOption: true, describe: 'YES or NO' }) + .positional('amount', { type: 'number', demandOption: true, describe: 'USDC to spend' }) + .option('wallet', { + type: 'string', + default: 'main', + describe: 'Smart wallet to fund from' + }) + .option('price', { + type: 'number', + describe: 'Limit price 0-1 (GTC); omit for market order' + }) + .option('fak', { type: 'boolean', default: false, describe: 'Use FAK instead of FOK' }) + .option('skip-fund', { + type: 'boolean', + default: false, + describe: 'Skip wallet→proxy funding' + }) + .option('broadcast', { + type: 'boolean', + default: false, + describe: 'Execute (dry-run without)' + }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handler: (argv) => handleClobBuy(argv as any) + }) + .command({ + command: 'sell ', + describe: 'Sell YES/NO tokens via CLOB', + builder: (y) => + y + .positional('conditionId', { type: 'string', demandOption: true }) + .positional('outcome', { type: 'string', demandOption: true, describe: 'YES or NO' }) + .positional('shares', { + type: 'number', + demandOption: true, + describe: 'Number of tokens to sell' + }) + .option('price', { + type: 'number', + describe: 'Limit price 0-1 (GTC); omit for market order' + }) + .option('fak', { type: 'boolean', default: false, describe: 'Use FAK instead of FOK' }) + .option('broadcast', { + type: 'boolean', + default: false, + describe: 'Execute (dry-run without)' + }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handler: (argv) => handleSell(argv as any) + }) + .command({ + command: 'positions', + describe: 'List open positions for the Polymarket proxy wallet', + builder: (y) => y, + handler: () => handlePositions() + }) + .command({ + command: 'orders', + describe: 'List open CLOB orders for the active EOA', + builder: (y) => y, + handler: () => handleOrders() + }) + .command({ + command: 'cancel ', + describe: 'Cancel an open CLOB order', + builder: (y) => + y.positional('orderId', { + type: 'string', + demandOption: true, + describe: 'Order ID to cancel' + }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handler: (argv) => handleCancel(argv as any) + }) + .demandCommand(1, '') + .showHelpOnFail(true), + handler: () => {} +}; diff --git a/packages/polygon-agent-cli/src/index.ts b/packages/polygon-agent-cli/src/index.ts index 5df4cca..3c108ef 100644 --- a/packages/polygon-agent-cli/src/index.ts +++ b/packages/polygon-agent-cli/src/index.ts @@ -18,6 +18,7 @@ import { swapCommand, x402PayCommand } from './commands/operations.ts'; +import { polymarketCommand } from './commands/polymarket.ts'; import { setupCommand } from './commands/setup.ts'; import { walletCommand } from './commands/wallet.ts'; @@ -89,7 +90,8 @@ const parser = yargs(hideBin(process.argv)) .command(swapCommand) .command(depositCommand) .command(x402PayCommand) - .command(agentCommand); + .command(agentCommand) + .command(polymarketCommand); // Register legacy aliases for (const alias of legacyAliases) { diff --git a/packages/polygon-agent-cli/src/lib/polymarket.ts b/packages/polygon-agent-cli/src/lib/polymarket.ts new file mode 100644 index 0000000..a76219e --- /dev/null +++ b/packages/polygon-agent-cli/src/lib/polymarket.ts @@ -0,0 +1,359 @@ +// Polymarket integration library +// Covers: Gamma API (market discovery), CLOB API (trading via @polymarket/clob-client), on-chain ops +// +// Architecture: Sequence smart wallet → Polymarket proxy wallet → CLOB +// - Sequence smart wallet funds the Polymarket proxy wallet (USDC.e transfer) +// - EOA calls proxy.execute([approve, split]) to run on-chain ops FROM the proxy wallet +// - CLOB orders use maker=proxyWallet, signer=EOA, signatureType=POLY_PROXY + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AnyWalletClient = any; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AnyPublicClient = any; + +export interface Market { + id: string; + conditionId: string; + question: string; + yesTokenId: string | null; + noTokenId: string | null; + yesPrice: number | null; + noPrice: number | null; + outcomes: string[]; + volume24hr: number; + negRisk: boolean; + endDate: string | null; +} + +export interface ProxyTx { + typeCode?: number; + to: string; + value?: string | number | bigint; + data: string; +} + +// ─── Constants ────────────────────────────────────────────────────────────── + +export const GAMMA_URL = process.env.POLYMARKET_GAMMA_URL || 'https://gamma-api.polymarket.com'; +export const CLOB_URL = process.env.POLYMARKET_CLOB_URL || 'https://clob.polymarket.com'; +export const DATA_URL = process.env.POLYMARKET_DATA_URL || 'https://data-api.polymarket.com'; + +// Polygon mainnet (chain 137) +export const USDC_E = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'; // USDC.e — 6 decimals +export const CTF = '0x4D97DCd97eC945f40cF65F87097ACe5EA0476045'; // Conditional Token Framework +export const CTF_EXCHANGE = '0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E'; // CLOB exchange +export const NEG_RISK_CTF_EXCHANGE = '0xC5d563A36AE78145C45a50134d48A1215220f80a'; +export const NEG_RISK_ADAPTER = '0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296'; + +// Polymarket proxy wallet factory (Polygon mainnet) +export const PROXY_WALLET_FACTORY = '0xaB45c5A4B0c941a2F231C04C3f49182e1A254052'; + +// ─── Proxy wallet helpers ──────────────────────────────────────────────────── + +// Compute the Polymarket proxy wallet address for a given EOA address (CREATE2, deterministic) +export async function getPolymarketProxyWalletAddress(eoaAddress: string): Promise { + const { getProxyWalletAddress } = await import('@polymarket/sdk'); + return getProxyWalletAddress(PROXY_WALLET_FACTORY, eoaAddress); +} + +// Proxy wallet execute ABI: execute(Transaction[]) — selector 0x34ee9791 +const PROXY_EXECUTE_ABI = [ + { + name: 'execute', + type: 'function', + inputs: [ + { + name: 'transactions', + type: 'tuple[]', + components: [ + { name: 'typeCode', type: 'uint8' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' } + ] + } + ], + outputs: [{ name: '', type: 'bytes[]' }] + } +]; + +// Execute a batch of transactions through the Polymarket proxy wallet (EOA is owner/caller) +export async function executeViaProxyWallet( + walletClient: AnyWalletClient, + publicClient: AnyPublicClient, + proxyWalletAddress: string, + txs: ProxyTx[] +): Promise { + const { encodeFunctionData } = await import('viem'); + const transactions = txs.map((t) => ({ + typeCode: Number(t.typeCode ?? 1), + to: t.to, + value: BigInt(t.value || 0), + data: t.data + })); + const data = encodeFunctionData({ + abi: PROXY_EXECUTE_ABI, + functionName: 'execute', + args: [transactions] + }); + const hash = await walletClient.sendTransaction({ to: PROXY_WALLET_FACTORY, data, value: 0n }); + await publicClient.waitForTransactionReceipt({ hash }); + return hash; +} + +// ─── Gamma API ────────────────────────────────────────────────────────────── + +export async function getMarkets({ + search, + limit = 20, + offset = 0 +}: { + search?: string; + limit?: number; + offset?: number; +} = {}): Promise { + const fetchLimit = search ? Math.max(100, limit * 5) : limit; + const params = new URLSearchParams({ + limit: String(fetchLimit), + offset: String(offset), + active: 'true', + closed: 'false', + order: 'volume24hr', + ascending: 'false' + }); + + const res = await fetch(`${GAMMA_URL}/markets?${params}`); + if (!res.ok) throw new Error(`Gamma API error: ${res.status} ${await res.text()}`); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let markets: any[] = (await res.json()) as any[]; + + if (search) { + const q = search.toLowerCase(); + markets = markets.filter((m) => (m.question || '').toLowerCase().includes(q)); + markets = markets.slice(0, limit); + } + + return markets.map(parseMarket); +} + +export async function getMarket(conditionId: string): Promise { + const needle = conditionId.toLowerCase(); + for (let offset = 0; offset < 500; offset += 100) { + const params = new URLSearchParams({ + limit: '100', + offset: String(offset), + active: 'true', + closed: 'false', + order: 'volume24hr', + ascending: 'false' + }); + const res = await fetch(`${GAMMA_URL}/markets?${params}`); + if (!res.ok) throw new Error(`Gamma API error: ${res.status} ${await res.text()}`); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const markets: any[] = (await res.json()) as any[]; + if (!markets?.length) break; + const found = markets.find((m) => m.conditionId?.toLowerCase() === needle); + if (found) return parseMarket(found); + } + const resClosed = await fetch( + `${GAMMA_URL}/markets?conditionId=${encodeURIComponent(conditionId)}&limit=100` + ); + if (resClosed.ok) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const closed: any[] = (await resClosed.json()) as any[]; + const found = (closed || []).find((m) => m.conditionId?.toLowerCase() === needle); + if (found) return parseMarket(found); + } + throw new Error(`Market not found: ${conditionId}`); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function parseMarket(m: any): Market { + let tokenIds: string[] = []; + let prices: string[] = []; + let outcomes: string[] = []; + try { + tokenIds = JSON.parse(m.clobTokenIds || '[]'); + } catch { + /* ignore */ + } + try { + prices = JSON.parse(m.outcomePrices || '[]'); + } catch { + /* ignore */ + } + try { + outcomes = JSON.parse(m.outcomes || '["Yes","No"]'); + } catch { + /* ignore */ + } + + return { + id: m.id, + conditionId: m.conditionId, + question: m.question, + yesTokenId: tokenIds[0] || null, + noTokenId: tokenIds[1] || null, + yesPrice: prices[0] ? Number(prices[0]) : null, + noPrice: prices[1] ? Number(prices[1]) : null, + outcomes, + volume24hr: m.volume24hr || 0, + negRisk: !!m.negRisk, + endDate: m.endDate || null + }; +} + +// ─── CLOB API — public endpoints ───────────────────────────────────────────── + +export async function getClobPrice(tokenId: string, side = 'BUY'): Promise { + const res = await fetch(`${CLOB_URL}/price?token_id=${tokenId}&side=${side}`); + if (!res.ok) throw new Error(`CLOB price error: ${res.status} ${await res.text()}`); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const data: any = await res.json(); + return Number(data.price); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export async function getOrderBook(tokenId: string): Promise { + const res = await fetch(`${CLOB_URL}/book?token_id=${tokenId}`); + if (!res.ok) throw new Error(`CLOB book error: ${res.status} ${await res.text()}`); + return res.json(); +} + +// ─── CLOB API — @polymarket/clob-client ───────────────────────────────────── + +async function getClobClient( + privateKey: string, + proxyWalletAddress?: string + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): Promise<{ client: any; creds: any; address: string }> { + const { Wallet } = await import('ethers5'); + const { ClobClient } = await import('@polymarket/clob-client'); + const { SignatureType } = await import('@polymarket/order-utils'); + const signer = new Wallet(privateKey); + const chainId = 137; + const anonClient = new ClobClient(CLOB_URL, chainId, signer); + const creds = await anonClient.createOrDeriveApiKey(); + const signatureType = proxyWalletAddress ? SignatureType.POLY_PROXY : SignatureType.EOA; + const client = new ClobClient( + CLOB_URL, + chainId, + signer, + creds, + signatureType, + proxyWalletAddress + ); + return { client, creds, address: await signer.getAddress() }; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export async function getOpenOrders(privateKey: string): Promise { + const { client } = await getClobClient(privateKey); + return client.getOpenOrders(); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export async function cancelOrder(orderId: string, privateKey: string): Promise { + const { client } = await getClobClient(privateKey); + return client.cancelOrder({ orderID: orderId }); +} + +// ─── CLOB API — order creation ─────────────────────────────────────────────── + +export async function createAndPostOrder({ + tokenId, + side, + size, + price, + orderType = 'GTC', + privateKey, + proxyWalletAddress +}: { + tokenId: string; + side: 'BUY' | 'SELL'; + size: number; + price: number; + orderType?: string; + privateKey: string; + proxyWalletAddress?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any +}): Promise { + const { client } = await getClobClient(privateKey, proxyWalletAddress); + const order = await client.createOrder({ + tokenID: tokenId, + price, + size, + side, + feeRateBps: '0' + }); + return client.postOrder(order, orderType); +} + +export async function createAndPostMarketOrder({ + tokenId, + side, + amount, + orderType = 'FOK', + privateKey, + proxyWalletAddress +}: { + tokenId: string; + side: 'BUY' | 'SELL'; + amount: number; + orderType?: string; + privateKey: string; + proxyWalletAddress?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any +}): Promise { + const { client } = await getClobClient(privateKey, proxyWalletAddress); + const order = await client.createMarketOrder({ + tokenID: tokenId, + side, + amount, + orderType, + feeRateBps: '0' + }); + return client.postOrder(order, orderType); +} + +// ─── Data API — positions ──────────────────────────────────────────────────── + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export async function getPositions(address: string, limit = 20): Promise { + const res = await fetch(`${DATA_URL}/positions?user=${address}&limit=${limit}`); + if (!res.ok) throw new Error(`Data API error: ${res.status} ${await res.text()}`); + return res.json(); +} + +// ─── Helper: fetch with Cloudflare retry ───────────────────────────────────── + +export async function fetchWithRetry( + url: string, + init: RequestInit = {}, + retries = 5 +): Promise { + let lastErr: unknown; + for (let i = 0; i < retries; i++) { + try { + const res = await fetch(url, init); + if ((res.status === 403 || res.status === 503) && i < retries - 1) { + const text = await res.text(); + if (text.includes('Cloudflare') || text.includes('cf-ray')) { + await sleep(1000 * (i + 1)); + continue; + } + return new Response(text, { status: res.status, headers: res.headers }); + } + return res; + } catch (err) { + lastErr = err; + if (i < retries - 1) await sleep(500 * (i + 1)); + } + } + throw lastErr || new Error('fetch failed after retries'); +} + +function sleep(ms: number): Promise { + return new Promise((r) => setTimeout(r, ms)); +} diff --git a/packages/polygon-agent-cli/src/lib/storage.ts b/packages/polygon-agent-cli/src/lib/storage.ts index 6d4e692..8b38d26 100644 --- a/packages/polygon-agent-cli/src/lib/storage.ts +++ b/packages/polygon-agent-cli/src/lib/storage.ts @@ -193,3 +193,27 @@ export async function deleteWallet(name: string): Promise { return false; } + +export async function savePolymarketKey(privateKey: string): Promise { + ensureStorageDir(); + const configPath = path.join(STORAGE_DIR, 'builder.json'); + let data: Record = {}; + if (fs.existsSync(configPath)) { + data = JSON.parse(fs.readFileSync(configPath, 'utf8')); + } + data.polymarketPrivateKey = encrypt(privateKey); + fs.writeFileSync(configPath, JSON.stringify(data, null, 2), { mode: 0o600 }); +} + +export async function loadPolymarketKey(): Promise { + const configPath = path.join(STORAGE_DIR, 'builder.json'); + if (!fs.existsSync(configPath)) { + throw new Error('No builder config found. Run: polygon-agent setup'); + } + const data = JSON.parse(fs.readFileSync(configPath, 'utf8')); + if (data.polymarketPrivateKey) return decrypt(data.polymarketPrivateKey as CipherData); + if (data.privateKey) return decrypt(data.privateKey as CipherData); + throw new Error( + 'No EOA key found. Run: polygon-agent setup or polygon-agent polymarket set-key ' + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 703a599..c851ac9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,6 +141,12 @@ importers: '@0xtrails/api': specifier: ^0.10.4 version: 0.10.4 + '@polymarket/clob-client': + specifier: ^5.2.4 + version: 5.5.0(typescript@5.9.3)(zod@3.25.76) + '@polymarket/sdk': + specifier: ^6.0.1 + version: 6.0.1(@ethersproject/abi@5.8.0)(@ethersproject/address@5.8.0)(@ethersproject/bignumber@5.8.0)(@ethersproject/constants@5.8.0)(@ethersproject/contracts@5.8.0)(@ethersproject/keccak256@5.8.0)(@ethersproject/providers@5.8.0)(@ethersproject/solidity@5.8.0) '@x402/core': specifier: ^2.3.1 version: 2.5.0 @@ -156,6 +162,9 @@ importers: ethers: specifier: ^6.13.0 version: 6.16.0 + ethers5: + specifier: npm:ethers@^5.7.4 + version: ethers@5.8.0 tweetnacl: specifier: ^1.0.3 version: 1.0.3 @@ -810,6 +819,96 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ethersproject/abi@5.8.0': + resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==} + + '@ethersproject/abstract-provider@5.8.0': + resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==} + + '@ethersproject/abstract-signer@5.8.0': + resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==} + + '@ethersproject/address@5.8.0': + resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==} + + '@ethersproject/base64@5.8.0': + resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==} + + '@ethersproject/basex@5.8.0': + resolution: {integrity: sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==} + + '@ethersproject/bignumber@5.8.0': + resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==} + + '@ethersproject/bytes@5.8.0': + resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==} + + '@ethersproject/constants@5.8.0': + resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==} + + '@ethersproject/contracts@5.8.0': + resolution: {integrity: sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==} + + '@ethersproject/hash@5.8.0': + resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==} + + '@ethersproject/hdnode@5.8.0': + resolution: {integrity: sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==} + + '@ethersproject/json-wallets@5.8.0': + resolution: {integrity: sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==} + + '@ethersproject/keccak256@5.8.0': + resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==} + + '@ethersproject/logger@5.8.0': + resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==} + + '@ethersproject/networks@5.8.0': + resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==} + + '@ethersproject/pbkdf2@5.8.0': + resolution: {integrity: sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==} + + '@ethersproject/properties@5.8.0': + resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==} + + '@ethersproject/providers@5.8.0': + resolution: {integrity: sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==} + + '@ethersproject/random@5.8.0': + resolution: {integrity: sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==} + + '@ethersproject/rlp@5.8.0': + resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==} + + '@ethersproject/sha2@5.8.0': + resolution: {integrity: sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==} + + '@ethersproject/signing-key@5.8.0': + resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==} + + '@ethersproject/solidity@5.8.0': + resolution: {integrity: sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==} + + '@ethersproject/strings@5.8.0': + resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==} + + '@ethersproject/transactions@5.8.0': + resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==} + + '@ethersproject/units@5.8.0': + resolution: {integrity: sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==} + + '@ethersproject/wallet@5.8.0': + resolution: {integrity: sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==} + + '@ethersproject/web@5.8.0': + resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==} + + '@ethersproject/wordlists@5.8.0': + resolution: {integrity: sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==} + '@gar/promise-retry@1.0.2': resolution: {integrity: sha512-Lm/ZLhDZcBECta3TmCQSngiQykFdfw+QtI1/GYMsZd4l3nG+P8WLB16XuS7WaBGLQ+9E+cOcWQsth9cayuGt8g==} engines: {node: ^20.17.0 || >=22.9.0} @@ -1403,6 +1502,26 @@ packages: typescript: optional: true + '@polymarket/builder-signing-sdk@0.0.8': + resolution: {integrity: sha512-rZLCFxEdYahl5FiJmhe22RDXysS1ibFJlWz4NT0s3itJRYq3XJzXXHXEZkAQplU+nIS1IlbbKjA4zDQaeCyYtg==} + + '@polymarket/clob-client@5.5.0': + resolution: {integrity: sha512-ArESpXkq2Bapn3D/TQoXwxUWhz8UNPHGViU078ojQtuLvlB5IyhHipWBkUqkNNYvQ4gwAvxQEq1FTMgDTnWe6g==} + engines: {node: '>=20.10'} + + '@polymarket/sdk@6.0.1': + resolution: {integrity: sha512-CJSzGuT/Aavvc8ex2rDFgYm1zhwt8uu0h9NKcpTbVqKcsTjNre82/ZEaUK2Mpc8yAesMk5yHZ80aFZIMYtevpw==} + engines: {node: '>=8', npm: '>=5'} + peerDependencies: + '@ethersproject/abi': ^5.4.1 + '@ethersproject/address': ^5.0.8 + '@ethersproject/bignumber': ^5.0.8 + '@ethersproject/constants': ^5.0.8 + '@ethersproject/contracts': ^5.0.9 + '@ethersproject/keccak256': ^5.0.6 + '@ethersproject/providers': ^5.0.14 + '@ethersproject/solidity': ^5.0.7 + '@poppinss/colors@4.1.6': resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} @@ -1756,6 +1875,9 @@ packages: '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + '@types/node@22.19.13': resolution: {integrity: sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==} @@ -2015,6 +2137,9 @@ packages: add-stream@1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} + aes-js@3.0.0: + resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} + aes-js@4.0.0-beta.5: resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} @@ -2131,6 +2256,9 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + bech32@1.1.4: + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} @@ -2147,6 +2275,12 @@ packages: blakejs@1.2.1: resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} + + bn.js@5.2.3: + resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} + boxen@7.0.0: resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} engines: {node: '>=14.16'} @@ -2165,6 +2299,12 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browser-or-node@2.1.1: + resolution: {integrity: sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==} + browserslist@4.28.1: resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -2571,6 +2711,9 @@ packages: electron-to-chromium@1.5.302: resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -2752,6 +2895,9 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + ethers@5.8.0: + resolution: {integrity: sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==} + ethers@6.16.0: resolution: {integrity: sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==} engines: {node: '>=14.0.0'} @@ -2999,10 +3145,16 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -3240,6 +3392,9 @@ packages: js-base64@3.7.8: resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3588,6 +3743,12 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + minimatch@10.2.1: resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==} engines: {node: 20 || >=22} @@ -4247,6 +4408,9 @@ packages: scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -4586,6 +4750,9 @@ packages: engines: {node: '>=0.8.0'} hasBin: true + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} @@ -5552,6 +5719,261 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@ethersproject/abi@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/abstract-provider@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 + + '@ethersproject/abstract-signer@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + + '@ethersproject/address@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/rlp': 5.8.0 + + '@ethersproject/base64@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + + '@ethersproject/basex@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/properties': 5.8.0 + + '@ethersproject/bignumber@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + bn.js: 5.2.3 + + '@ethersproject/bytes@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/constants@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + + '@ethersproject/contracts@5.8.0': + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + + '@ethersproject/hash@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/hdnode@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + + '@ethersproject/json-wallets@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + aes-js: 3.0.0 + scrypt-js: 3.0.1 + + '@ethersproject/keccak256@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + js-sha3: 0.8.0 + + '@ethersproject/logger@5.8.0': {} + + '@ethersproject/networks@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/pbkdf2@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/sha2': 5.8.0 + + '@ethersproject/properties@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/providers@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 + bech32: 1.1.4 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@ethersproject/random@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/rlp@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/sha2@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + hash.js: 1.1.7 + + '@ethersproject/signing-key@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + bn.js: 5.2.3 + elliptic: 6.6.1 + hash.js: 1.1.7 + + '@ethersproject/solidity@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/strings@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/transactions@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + + '@ethersproject/units@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/wallet@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/json-wallets': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + + '@ethersproject/web@5.8.0': + dependencies: + '@ethersproject/base64': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/wordlists@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@gar/promise-retry@1.0.2': dependencies: retry: 0.13.1 @@ -6209,6 +6631,43 @@ snapshots: - eslint-plugin-import - supports-color + '@polymarket/builder-signing-sdk@0.0.8': + dependencies: + '@types/node': 18.19.130 + axios: 1.13.6 + tslib: 2.8.1 + transitivePeerDependencies: + - debug + + '@polymarket/clob-client@5.5.0(typescript@5.9.3)(zod@3.25.76)': + dependencies: + '@ethersproject/providers': 5.8.0 + '@ethersproject/units': 5.8.0 + '@ethersproject/wallet': 5.8.0 + '@polymarket/builder-signing-sdk': 0.0.8 + axios: 1.13.6 + browser-or-node: 2.1.1 + ethers: 5.8.0 + tslib: 2.8.1 + viem: 2.46.3(typescript@5.9.3)(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - debug + - typescript + - utf-8-validate + - zod + + '@polymarket/sdk@6.0.1(@ethersproject/abi@5.8.0)(@ethersproject/address@5.8.0)(@ethersproject/bignumber@5.8.0)(@ethersproject/constants@5.8.0)(@ethersproject/contracts@5.8.0)(@ethersproject/keccak256@5.8.0)(@ethersproject/providers@5.8.0)(@ethersproject/solidity@5.8.0)': + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/contracts': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/providers': 5.8.0 + '@ethersproject/solidity': 5.8.0 + '@poppinss/colors@4.1.6': dependencies: kleur: 4.1.5 @@ -6492,6 +6951,10 @@ snapshots: '@types/minimist@1.2.5': {} + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + '@types/node@22.19.13': dependencies: undici-types: 6.21.0 @@ -6762,6 +7225,8 @@ snapshots: add-stream@1.0.0: {} + aes-js@3.0.0: {} + aes-js@4.0.0-beta.5: {} agent-base@7.1.4: {} @@ -6864,6 +7329,8 @@ snapshots: baseline-browser-mapping@2.10.0: {} + bech32@1.1.4: {} + before-after-hook@2.2.3: {} bin-links@5.0.0: @@ -6884,6 +7351,10 @@ snapshots: blakejs@1.2.1: {} + bn.js@4.12.3: {} + + bn.js@5.2.3: {} + boxen@7.0.0: dependencies: ansi-align: 3.0.1 @@ -6912,6 +7383,10 @@ snapshots: dependencies: fill-range: 7.1.1 + brorand@1.1.0: {} + + browser-or-node@2.1.1: {} + browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.10.0 @@ -7285,6 +7760,16 @@ snapshots: electron-to-chromium@1.5.302: {} + elliptic@6.6.1: + dependencies: + bn.js: 4.12.3 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} @@ -7523,6 +8008,42 @@ snapshots: esutils@2.0.3: {} + ethers@5.8.0: + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/basex': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/contracts': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/hdnode': 5.8.0 + '@ethersproject/json-wallets': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/pbkdf2': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/providers': 5.8.0 + '@ethersproject/random': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/sha2': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + '@ethersproject/solidity': 5.8.0 + '@ethersproject/strings': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/units': 5.8.0 + '@ethersproject/wallet': 5.8.0 + '@ethersproject/web': 5.8.0 + '@ethersproject/wordlists': 5.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + ethers@6.16.0: dependencies: '@adraffy/ens-normalize': 1.10.1 @@ -7781,10 +8302,21 @@ snapshots: has-unicode@2.0.1: {} + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + hosted-git-info@2.8.9: {} hosted-git-info@4.1.0: @@ -7981,6 +8513,8 @@ snapshots: js-base64@3.7.8: {} + js-sha3@0.8.0: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -8403,6 +8937,10 @@ snapshots: - bufferutil - utf-8-validate + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + minimatch@10.2.1: dependencies: brace-expansion: 5.0.4 @@ -9177,6 +9715,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + scrypt-js@3.0.1: {} + semver@5.7.2: {} semver@6.3.1: {} @@ -9529,6 +10069,8 @@ snapshots: uglify-js@3.19.3: optional: true + undici-types@5.26.5: {} + undici-types@6.19.8: {} undici-types@6.21.0: {}