From 45fb37d51f3097dd8962a1c3db56234e066b61ae Mon Sep 17 00:00:00 2001 From: dev Date: Wed, 25 Mar 2026 22:20:56 +0800 Subject: [PATCH] support trenches & kol & smartmoney --- CLAUDE.md | 2 +- Readme.md | 4 +- Readme.zh.md | 4 +- docs/cli-usage.md | 121 +++++++++++++++++++++++++++++++++ package-lock.json | 4 +- package.json | 4 +- skills/gmgn-market/SKILL.md | 22 ++++-- skills/gmgn-portfolio/SKILL.md | 49 ++++++++++++- skills/gmgn-swap/SKILL.md | 28 +++++++- skills/gmgn-token/SKILL.md | 2 +- src/client/OpenApiClient.ts | 84 ++++++++++++++++++++++- src/commands/market.ts | 24 ++++++- src/commands/portfolio.ts | 61 ++++++++++++++++- src/commands/swap.ts | 23 +++++++ 14 files changed, 407 insertions(+), 25 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index df02245..00a3a3f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -53,7 +53,7 @@ EOF When creating or updating any file in `skills/`: - **Language**: English only — no bilingual content. SKILL.md files are read by AI, not humans. -- **Package runner**: Always use the pre-installed `gmgn-cli` binary (e.g. `gmgn-cli token info ...`). Never use `npx gmgn-cli` or `npx gmgn-cli@` — npx downloads the package at runtime alongside live credentials. The package must be installed once with `npm install -g gmgn-cli@1.0.2`. +- **Package runner**: Always use the pre-installed `gmgn-cli` binary (e.g. `gmgn-cli token info ...`). Never use `npx gmgn-cli` or `npx gmgn-cli@` — npx downloads the package at runtime alongside live credentials. The package must be installed once with `npm install -g gmgn-cli@1.1.0`. - **Section order**: Sub-commands → Supported Chains → Prerequisites → Parameters/Options (if needed) → Usage Examples → Notes - **`--raw` flag**: All commands support `--raw` for single-line JSON output. Always document it in the Notes section. - **YAML frontmatter**: Quote `argument-hint` values that contain `|` characters to avoid YAML parsing errors. diff --git a/Readme.md b/Readme.md index e3982f0..2407b60 100644 --- a/Readme.md +++ b/Readme.md @@ -80,7 +80,7 @@ npx skills add GMGNAI/gmgn-skills ### 1.2 npm Global Install ```bash -npm install -g gmgn-cli@1.0.2 +npm install -g gmgn-cli@1.1.0 ``` ### 1.3 Local Development @@ -321,7 +321,7 @@ npx gmgn-cli order get --chain sol --order-id - Restrict config file permissions: `chmod 600 ~/.config/gmgn/.env` - Never commit your `.env` file to version control — add it to `.gitignore` - Do not share `GMGN_API_KEY` or `GMGN_PRIVATE_KEY` in logs, screenshots, or chat messages -- Use a pinned install (`npm install -g gmgn-cli@1.0.2`) rather than `npx gmgn-cli` to avoid executing unintended package updates alongside your credentials +- Use a pinned install (`npm install -g gmgn-cli@1.1.0`) rather than `npx gmgn-cli` to avoid executing unintended package updates alongside your credentials **Disclaimer** diff --git a/Readme.zh.md b/Readme.zh.md index fb4c7a6..0138564 100644 --- a/Readme.zh.md +++ b/Readme.zh.md @@ -80,7 +80,7 @@ npx skills add GMGNAI/gmgn-skills ### 1.2 npm 全局安装 ```bash -npm install -g gmgn-cli@1.0.2 +npm install -g gmgn-cli@1.1.0 ``` ### 1.3 本地开发 @@ -321,7 +321,7 @@ npx gmgn-cli order get --chain sol --order-id - 限制配置文件权限:`chmod 600 ~/.config/gmgn/.env` - 不要将 `.env` 文件提交到版本控制系统,请将其加入 `.gitignore` - 不要在日志、截图或聊天中泄露 `GMGN_API_KEY` 或 `GMGN_PRIVATE_KEY` -- 使用固定版本安装(`npm install -g gmgn-cli@1.0.2`),而非 `npx gmgn-cli`,以避免在持有凭证的环境中执行未预期的包更新 +- 使用固定版本安装(`npm install -g gmgn-cli@1.1.0`),而非 `npx gmgn-cli`,以避免在持有凭证的环境中执行未预期的包更新 **免责声明** diff --git a/docs/cli-usage.md b/docs/cli-usage.md index f08bd34..87e8737 100644 --- a/docs/cli-usage.md +++ b/docs/cli-usage.md @@ -255,6 +255,127 @@ npx gmgn-cli portfolio token-balance \ --- +## market trenches + +Query Trenches token lists (new creation, near completion, completed). + +```bash +npx gmgn-cli market trenches --chain [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | + +**Response:** `data.new_creation`, `data.pump`, `data.completed` — each is an array of `RankItem` (same structure as `market trending` rank items). + +--- + +## portfolio follow-wallet + +Query follow-wallet trade records. + +```bash +npx gmgn-cli portfolio follow-wallet \ + --chain \ + [--wallet ] \ + [--base-token ] \ + [--page-token ] \ + [--limit ] \ + [--side ] \ + [--cost ] \ + [--filter ] \ + [--with-balance] \ + [--with-security] \ + [--min-amount-usd ] \ + [--max-amount-usd ] \ + [--is-gray] \ + [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` / `eth` | +| `--wallet` | No | Filter by wallet address | +| `--base-token` | No | Filter by base token address | +| `--page-token` | No | Pagination cursor | +| `--limit` | No | Page size (1–200, default 100) | +| `--side` | No | Trade direction filter | +| `--cost` | No | Cost filter | +| `--filter` | No | Filter conditions (repeatable) | +| `--with-balance` | No | Include balance in response | +| `--with-security` | No | Include security info in response | +| `--min-amount-usd` | No | Minimum trade amount (USD) | +| `--max-amount-usd` | No | Maximum trade amount (USD) | +| `--is-gray` | No | Gray mode filter | + +--- + +## portfolio kol + +Query KOL trade records (SOL chain). + +```bash +npx gmgn-cli portfolio kol [--limit ] [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--limit` | No | Page size (1–200, default 100) | + +--- + +## portfolio smartmoney + +Query Smart Money trade records (SOL chain). + +```bash +npx gmgn-cli portfolio smartmoney [--limit ] [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--limit` | No | Page size (1–200, default 100) | + +--- + +## order quote + +Get a swap quote without submitting a transaction. Uses normal auth — no private key required. + +```bash +npx gmgn-cli order quote \ + --chain \ + --from \ + --input-token \ + --output-token \ + --amount \ + --slippage \ + [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | +| `--from` | Yes | Wallet address (must match API Key binding) | +| `--input-token` | Yes | Input token contract address | +| `--output-token` | Yes | Output token contract address | +| `--amount` | Yes | Input amount (smallest unit) | +| `--slippage` | Yes | Slippage tolerance, e.g. `0.01` = 1% | + +**Response fields (data):** + +| Field | Type | Description | +|-------|------|-------------| +| `input_token` | string | Input token contract address | +| `output_token` | string | Output token contract address | +| `input_amount` | string | Input amount (smallest unit) | +| `output_amount` | string | Expected output amount (smallest unit) | +| `min_output_amount` | string | Minimum output after slippage | +| `slippage` | number | Actual slippage percentage | + +--- + ## swap Submit a token swap. **Requires `GMGN_PRIVATE_KEY` configured in `.env`.** diff --git a/package-lock.json b/package-lock.json index e04d6ea..665740b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gmgn-cli", - "version": "1.0.1", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gmgn-cli", - "version": "1.0.1", + "version": "1.1.0", "license": "MIT", "dependencies": { "commander": "^12.1.0", diff --git a/package.json b/package.json index a96515c..b68cbc5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gmgn-cli", - "version": "1.0.2", + "version": "1.1.0", "description": "GMGN OpenAPI CLI — call GMGN market, token, portfolio and swap APIs from the command line", "type": "module", "bin": { @@ -16,7 +16,7 @@ "scripts": { "build": "tsc", "dev": "tsx src/index.ts", -"prepublishOnly": "npm run build", + "prepublishOnly": "npm run build", "publish:provenance": "npm publish --provenance --access public" }, "dependencies": { diff --git a/skills/gmgn-market/SKILL.md b/skills/gmgn-market/SKILL.md index a294a48..8680a15 100644 --- a/skills/gmgn-market/SKILL.md +++ b/skills/gmgn-market/SKILL.md @@ -1,10 +1,10 @@ --- name: gmgn-market -description: Query GMGN market data — token K-line (candlestick) and trending token swap data. Supports sol / bsc / base. -argument-hint: "kline --chain --address --resolution <1m|5m|15m|1h|4h|1d> [--from ] [--to ] | trending --chain --interval <1m|5m|1h|6h|24h>" +description: Query GMGN market data — token K-line (candlestick), trending token swap data, and Trenches token lists. Supports sol / bsc / base. +argument-hint: "kline --chain --address --resolution <1m|5m|15m|1h|4h|1d> [--from ] [--to ] | trending --chain --interval <1m|5m|1h|6h|24h> | trenches --chain " --- -Use the `gmgn-cli` tool to query K-line data for a token or browse trending tokens. +Use the `gmgn-cli` tool to query K-line data for a token, browse trending tokens, or view Trenches token lists. ## Sub-commands @@ -12,6 +12,7 @@ Use the `gmgn-cli` tool to query K-line data for a token or browse trending toke |-------------|-------------| | `market kline` | Token candlestick data | | `market trending` | Trending token swap data | +| `market trenches` | Trenches token lists (new creation, near completion, completed) | ## Supported Chains @@ -21,7 +22,7 @@ Use the `gmgn-cli` tool to query K-line data for a token or browse trending toke - `.env` file with `GMGN_API_KEY` set - Run from the directory where your `.env` file is located, or set `GMGN_HOST` in your environment -- `gmgn-cli` installed globally: `npm install -g gmgn-cli@1.0.2` +- `gmgn-cli` installed globally: `npm install -g gmgn-cli@1.1.0` ## Kline Parameters @@ -135,6 +136,19 @@ For each token, offer: - **Deep dive**: `token info` + `token security` for full due diligence - **Swap**: execute directly if the user is satisfied with the trending data alone +## Trenches Parameters + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | + +Response fields: `data.new_creation`, `data.pump`, `data.completed` — each is an array of `RankItem` (same fields as `market trending` rank items). + +```bash +# Trenches token lists on SOL +gmgn-cli market trenches --chain sol --raw +``` + ## Notes - `market kline`: `--from` and `--to` are Unix timestamps in **seconds** — CLI converts to milliseconds automatically diff --git a/skills/gmgn-portfolio/SKILL.md b/skills/gmgn-portfolio/SKILL.md index 338a0e4..b17158e 100644 --- a/skills/gmgn-portfolio/SKILL.md +++ b/skills/gmgn-portfolio/SKILL.md @@ -1,7 +1,7 @@ --- name: gmgn-portfolio -description: Query GMGN wallet portfolio — API Key wallet info, holdings, transaction activity, trading stats, and token balance. Supports sol / bsc / base. -argument-hint: " [--chain ] [--wallet ]" +description: Query GMGN wallet portfolio — API Key wallet info, holdings, transaction activity, trading stats, token balance, follow-wallet trades, KOL trades, and Smart Money trades. Supports sol / bsc / base. +argument-hint: " [--chain ] [--wallet ]" --- Use the `gmgn-cli` tool to query wallet portfolio data based on the user's request. @@ -15,6 +15,9 @@ Use the `gmgn-cli` tool to query wallet portfolio data based on the user's reque | `portfolio activity` | Transaction history | | `portfolio stats` | Trading statistics (supports batch) | | `portfolio token-balance` | Token balance for a specific token | +| `portfolio follow-wallet` | Follow-wallet trade records | +| `portfolio kol` | KOL trade records (SOL chain) | +| `portfolio smartmoney` | Smart Money trade records (SOL chain) | ## Supported Chains @@ -24,7 +27,7 @@ Use the `gmgn-cli` tool to query wallet portfolio data based on the user's reque - `.env` file with `GMGN_API_KEY` set - Run from the directory where your `.env` file is located, or set `GMGN_HOST` in your environment -- `gmgn-cli` installed globally: `npm install -g gmgn-cli@1.0.2` +- `gmgn-cli` installed globally: `npm install -g gmgn-cli@1.1.0` ## Usage Examples @@ -101,6 +104,46 @@ The activity response includes a `next` field. Pass it to `--cursor` to fetch th |--------|-------------| | `--period ` | Stats period: `7d` / `30d` (default `7d`) | +## Follow-Wallet Options + +| Option | Description | +|--------|-------------| +| `--chain` | Required. `sol` / `bsc` / `base` / `eth` | +| `--wallet
` | Filter by wallet address | +| `--base-token
` | Filter by base token address | +| `--page-token ` | Pagination cursor | +| `--limit ` | Page size (1–200, default 100) | +| `--side ` | Trade direction filter | +| `--cost ` | Cost filter | +| `--filter ` | Repeatable filter conditions | +| `--with-balance` | Include balance in response | +| `--with-security` | Include security info in response | +| `--min-amount-usd ` | Minimum trade amount (USD) | +| `--max-amount-usd ` | Maximum trade amount (USD) | +| `--is-gray` | Gray mode filter | + +## KOL / Smart Money Options + +| Option | Description | +|--------|-------------| +| `--limit ` | Page size (1–200, default 100) | + +Both `kol` and `smartmoney` return SOL chain data only — no `--chain` flag needed. + +```bash +# Follow-wallet trades filtered by wallet +gmgn-cli portfolio follow-wallet --chain sol --wallet + +# Follow-wallet with balance info +gmgn-cli portfolio follow-wallet --chain sol --with-balance --limit 20 + +# KOL trade records +gmgn-cli portfolio kol --limit 10 --raw + +# Smart Money trade records +gmgn-cli portfolio smartmoney --limit 10 --raw +``` + ## Notes - All portfolio commands use normal auth (API Key only, no signature required) diff --git a/skills/gmgn-swap/SKILL.md b/skills/gmgn-swap/SKILL.md index e7d9044..695904b 100644 --- a/skills/gmgn-swap/SKILL.md +++ b/skills/gmgn-swap/SKILL.md @@ -20,6 +20,7 @@ Use the `gmgn-cli` tool to submit a token swap or query an existing order. **Req | Sub-command | Description | |-------------|-------------| | `swap` | Submit a token swap | +| `order quote` | Get a swap quote (no transaction submitted) | | `order get` | Query order status | ## Supported Chains @@ -45,7 +46,7 @@ Both `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` must be set in `.env`. The private ke `gmgn-cli` must be installed globally before use (one-time setup): ```bash -npm install -g gmgn-cli@1.0.2 +npm install -g gmgn-cli@1.1.0 ``` ### Credential Model @@ -92,6 +93,31 @@ gmgn-cli swap \ --percent 50 ``` +## Quote Usage + +Get an estimated output amount before submitting a swap. Uses normal auth — no private key required. + +```bash +gmgn-cli order quote \ + --chain sol \ + --from \ + --input-token \ + --output-token \ + --amount \ + --slippage 0.01 +``` + +### Quote Response Fields + +| Field | Type | Description | +|-------|------|-------------| +| `input_token` | string | Input token contract address | +| `output_token` | string | Output token contract address | +| `input_amount` | string | Input amount (smallest unit) | +| `output_amount` | string | Expected output amount (smallest unit) | +| `min_output_amount` | string | Minimum output after slippage | +| `slippage` | number | Actual slippage percentage | + ## Order Query ```bash diff --git a/skills/gmgn-token/SKILL.md b/skills/gmgn-token/SKILL.md index 911b098..6660229 100644 --- a/skills/gmgn-token/SKILL.md +++ b/skills/gmgn-token/SKILL.md @@ -24,7 +24,7 @@ Use the `gmgn-cli` tool to query token information based on the user's request. - `.env` file with `GMGN_API_KEY` set - Run from the directory where your `.env` file is located, or set `GMGN_HOST` in your environment -- `gmgn-cli` installed globally: `npm install -g gmgn-cli@1.0.2` +- `gmgn-cli` installed globally: `npm install -g gmgn-cli@1.1.0` ## Info / Security / Pool Options diff --git a/src/client/OpenApiClient.ts b/src/client/OpenApiClient.ts index 3158966..8a95b72 100644 --- a/src/client/OpenApiClient.ts +++ b/src/client/OpenApiClient.ts @@ -75,10 +75,13 @@ export class OpenApiClient { chain: string, address: string, resolution: string, - from: number, - to: number + from?: number, + to?: number ): Promise { - return this.normalRequest("GET", "/v1/market/token_kline", { chain, address, resolution, from, to }); + const query: Record = { chain, address, resolution }; + if (from != null) query["from"] = from; + if (to != null) query["to"] = to; + return this.normalRequest("GET", "/v1/market/token_kline", query); } // ---- Portfolio endpoints (normal auth) ---- @@ -123,6 +126,11 @@ export class OpenApiClient { return this.normalRequest("GET", "/v1/user/wallet_token_balance", { chain, wallet_address: walletAddress, token_address: tokenAddress }); } + async getTrenches(chain: string): Promise { + const body = buildTrenchesBody(chain); + return this.normalRequest("POST", "/v1/trenches", { chain }, body); + } + // ---- Market trending endpoints (normal auth) ---- async getTrendingSwaps( @@ -139,6 +147,35 @@ export class OpenApiClient { return this.normalRequest("GET", "/v1/user/info", {}); } + async getFollowWallet(chain: string, extra: Record = {}): Promise { + return this.normalRequest("GET", "/v1/trade/follow_wallet", { chain, ...extra }); + } + + async getKol(limit?: number): Promise { + const query: Record = {}; + if (limit != null) query["limit"] = limit; + return this.normalRequest("GET", "/v1/user/kol", query); + } + + async getSmartMoney(limit?: number): Promise { + const query: Record = {}; + if (limit != null) query["limit"] = limit; + return this.normalRequest("GET", "/v1/user/smartmoney", query); + } + + async quoteOrder( + chain: string, + from_address: string, + input_token: string, + output_token: string, + input_amount: string, + slippage: number + ): Promise { + return this.normalRequest("GET", "/v1/trade/quote", { + chain, from_address, input_token, output_token, input_amount, slippage, + }); + } + // ---- Swap endpoints (critical auth) ---- async swap(params: SwapParams): Promise { @@ -269,6 +306,47 @@ function formatCurl(method: string, url: string, headers: Record return `\n[curl]\ncurl -X ${method} '${url}' \\\n${headerArgs}${bodyArg}\n`; } +const TRENCHES_PLATFORMS: Record = { + sol: [ + "Pump.fun", "pump_mayhem", "pump_mayhem_agent", "pump_agent", + "letsbonk", "bonkers", "bags", "memoo", "liquid", "bankr", "zora", + "surge", "anoncoin", "moonshot_app", "wendotdev", "heaven", "sugar", + "token_mill", "believe", "trendsfun", "trends_fun", "jup_studio", + "Moonshot", "boop", "ray_launchpad", "meteora_virtual_curve", "xstocks", + ], + bsc: [ + "fourmeme", "fourmeme_agent", "bn_fourmeme", "four_xmode_agent", + "flap", "clanker", "lunafun", + ], + base: [ + "clanker", "bankr", "flaunch", "zora", "zora_creator", + "baseapp", "basememe", "virtuals_v2", "klik", + ], +}; + +const TRENCHES_QUOTE_ADDRESS_TYPES: Record = { + sol: [4, 5, 3, 1, 13, 0], + bsc: [6, 7, 1, 16, 8, 3, 9, 10, 2, 17, 18, 0], + base: [11, 3, 12, 13, 0], +}; + +function buildTrenchesBody(chain: string): Record { + const launchpad_platform = TRENCHES_PLATFORMS[chain] ?? []; + const quote_address_type = TRENCHES_QUOTE_ADDRESS_TYPES[chain] ?? []; + const section = { + filters: ["offchain", "onchain"], + launchpad_platform, + quote_address_type, + launchpad_platform_v2: true, + }; + return { + new_creation: { ...section, limit: 60 }, + near_completion: { ...section, limit: 120 }, + completed: { ...section, limit: 60 }, + version: "v2", + }; +} + function buildUrl(base: string, query: Record): string { const params = new URLSearchParams(); for (const [k, v] of Object.entries(query)) { diff --git a/src/commands/market.ts b/src/commands/market.ts index 37f0d4b..404b598 100644 --- a/src/commands/market.ts +++ b/src/commands/market.ts @@ -13,15 +13,21 @@ export function registerMarketCommands(program: Command): void { .requiredOption("--chain ", "Chain: sol / bsc / base") .requiredOption("--address
", "Token contract address") .requiredOption("--resolution ", "Candlestick resolution: 1m / 5m / 15m / 1h / 4h / 1d") - .requiredOption("--from ", "Start time (Unix seconds)", parseInt) - .requiredOption("--to ", "End time (Unix seconds)", parseInt) + .option("--from ", "Start time (Unix seconds)", parseInt) + .option("--to ", "End time (Unix seconds)", parseInt) .option("--raw", "Output raw JSON") .action(async (opts) => { validateChain(opts.chain); validateAddress(opts.address, opts.chain, "--address"); const client = new OpenApiClient(getConfig()); const data = await client - .getTokenKline(opts.chain, opts.address, opts.resolution, opts.from * 1000, opts.to * 1000) + .getTokenKline( + opts.chain, + opts.address, + opts.resolution, + opts.from != null ? opts.from * 1000 : undefined, + opts.to != null ? opts.to * 1000 : undefined + ) .catch(exitOnError); printResult(data, opts.raw); }); @@ -50,5 +56,17 @@ export function registerMarketCommands(program: Command): void { const data = await client.getTrendingSwaps(opts.chain, opts.interval, extra).catch(exitOnError); printResult(data, opts.raw); }); + + market + .command("trenches") + .description("Get Trenches token data (new creation, near completion, completed)") + .requiredOption("--chain ", "Chain: sol / bsc / base") + .option("--raw", "Output raw JSON") + .action(async (opts) => { + validateChain(opts.chain); + const client = new OpenApiClient(getConfig()); + const data = await client.getTrenches(opts.chain).catch(exitOnError); + printResult(data, opts.raw); + }); } diff --git a/src/commands/portfolio.ts b/src/commands/portfolio.ts index b140d06..44d24c4 100644 --- a/src/commands/portfolio.ts +++ b/src/commands/portfolio.ts @@ -62,7 +62,7 @@ export function registerPortfolioCommands(program: Command): void { validateAddress(opts.wallet, opts.chain, "--wallet"); if (opts.token) validateAddress(opts.token, opts.chain, "--token"); const extra: Record = {}; - if (opts.token) extra["token"] = opts.token; + if (opts.token) extra["token_address"] = opts.token; if (opts.limit != null) extra["limit"] = opts.limit; if (opts.cursor) extra["cursor"] = opts.cursor; if (opts.type?.length) extra["type"] = opts.type; @@ -112,5 +112,64 @@ export function registerPortfolioCommands(program: Command): void { const data = await client.getWalletTokenBalance(opts.chain, opts.wallet, opts.token).catch(exitOnError); printResult(data, opts.raw); }); + + portfolio + .command("follow-wallet") + .description("Get follow-wallet trade records") + .requiredOption("--chain ", "Chain: sol / bsc / base / eth") + .option("--wallet
", "Filter by wallet address") + .option("--base-token
", "Filter by base token address") + .option("--page-token ", "Pagination cursor") + .option("--limit ", "Page size (1–200, default 100)", parseInt) + .option("--side ", "Trade direction filter") + .option("--cost ", "Cost filter") + .option("--filter ", "Filter conditions, repeatable") + .option("--with-balance", "Include balance in response") + .option("--with-security", "Include security info in response") + .option("--min-amount-usd ", "Minimum trade amount (USD)", parseFloat) + .option("--max-amount-usd ", "Maximum trade amount (USD)", parseFloat) + .option("--is-gray", "Gray mode filter") + .option("--raw", "Output raw JSON") + .action(async (opts) => { + validateChain(opts.chain); + const extra: Record = {}; + if (opts.wallet) extra["wallet_address"] = opts.wallet; + if (opts.baseToken) extra["base_token"] = opts.baseToken; + if (opts.pageToken) extra["page_token"] = opts.pageToken; + if (opts.limit != null) extra["limit"] = opts.limit; + if (opts.side) extra["side"] = opts.side; + if (opts.cost) extra["cost"] = opts.cost; + if (opts.filter?.length) extra["filters"] = opts.filter; + if (opts.withBalance) extra["with_balance"] = "true"; + if (opts.withSecurity) extra["with_security"] = "true"; + if (opts.minAmountUsd != null) extra["min_amount_usd"] = opts.minAmountUsd; + if (opts.maxAmountUsd != null) extra["max_amount_usd"] = opts.maxAmountUsd; + if (opts.isGray) extra["is_gray"] = "true"; + const client = new OpenApiClient(getConfig()); + const data = await client.getFollowWallet(opts.chain, extra).catch(exitOnError); + printResult(data, opts.raw); + }); + + portfolio + .command("kol") + .description("Get KOL trade records (SOL chain)") + .option("--limit ", "Page size (1–200, default 100)", parseInt) + .option("--raw", "Output raw JSON") + .action(async (opts) => { + const client = new OpenApiClient(getConfig()); + const data = await client.getKol(opts.limit).catch(exitOnError); + printResult(data, opts.raw); + }); + + portfolio + .command("smartmoney") + .description("Get Smart Money trade records (SOL chain)") + .option("--limit ", "Page size (1–200, default 100)", parseInt) + .option("--raw", "Output raw JSON") + .action(async (opts) => { + const client = new OpenApiClient(getConfig()); + const data = await client.getSmartMoney(opts.limit).catch(exitOnError); + printResult(data, opts.raw); + }); } diff --git a/src/commands/swap.ts b/src/commands/swap.ts index 3930d60..6ad2674 100644 --- a/src/commands/swap.ts +++ b/src/commands/swap.ts @@ -60,6 +60,29 @@ export function registerSwapCommands(program: Command): void { const order = program.command("order").description("Order management commands"); + order + .command("quote") + .description("Get a swap quote without submitting a transaction") + .requiredOption("--chain ", "Chain: sol / bsc / base") + .requiredOption("--from
", "Wallet address (must match API Key binding)") + .requiredOption("--input-token
", "Input token contract address") + .requiredOption("--output-token
", "Output token contract address") + .requiredOption("--amount ", "Input amount (smallest unit)") + .requiredOption("--slippage ", "Slippage tolerance (e.g. 0.01 = 1%)", parseFloat) + .option("--raw", "Output raw JSON") + .action(async (opts) => { + validateChain(opts.chain); + validateAddress(opts.from, opts.chain, "--from"); + validateAddress(opts.inputToken, opts.chain, "--input-token"); + validateAddress(opts.outputToken, opts.chain, "--output-token"); + validatePositiveInt(opts.amount, "--amount"); + const client = new OpenApiClient(getConfig()); + const data = await client + .quoteOrder(opts.chain, opts.from, opts.inputToken, opts.outputToken, opts.amount, opts.slippage) + .catch(exitOnError); + printResult(data, opts.raw); + }); + order .command("get") .description("Query order status (requires private key)")