diff --git a/docs/cli-usage.md b/docs/cli-usage.md index 7b02aa1..6677dde 100644 --- a/docs/cli-usage.md +++ b/docs/cli-usage.md @@ -457,6 +457,171 @@ npx gmgn-cli order get --chain --order-id [--raw] **Response fields (data):** Same structure as the `swap` response above. +## order strategy create + +Create a limit/strategy order. **Requires `GMGN_PRIVATE_KEY` configured in `.env`.** + +```bash +gmgn-cli order strategy create \ + --chain \ + --from \ + --base-token \ + --quote-token \ + --side \ + --open-price \ + --check-price \ + [--amount-in | --amount-in-percent ] \ + [--slippage | --auto-slippage] \ + [--limit-price-mode ] \ + [--expire-in ] \ + [--sell-ratio-type ] \ + [--priority-fee ] \ + [--tip-fee ] \ + [--gas-price ] \ + [--anti-mev] \ + [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | +| `--from` | Yes | Wallet address (must match API Key binding) | +| `--base-token` | Yes | Base token contract address | +| `--quote-token` | Yes | Quote token contract address | +| `--side` | Yes | `buy` / `sell` | +| `--open-price` | Yes | Open price | +| `--check-price` | Yes | Trigger check price | +| `--amount-in` | No* | Input amount (smallest unit); required unless `--amount-in-percent` is used | +| `--amount-in-percent` | No* | Input as percentage (e.g. `50` = 50%); required unless `--amount-in` is used | +| `--limit-price-mode` | No | `exact` / `slippage` (default: `slippage`) | +| `--expire-in` | No | Order expiry in seconds | +| `--sell-ratio-type` | No | `buy_amount` (default) / `hold_amount` | +| `--slippage` | No | Slippage tolerance, e.g. `0.01` = 1% | +| `--auto-slippage` | No | Enable automatic slippage | +| `--priority-fee` | No | Priority fee in SOL (SOL only) | +| `--tip-fee` | No | Tip fee | +| `--gas-price` | No | Gas price in wei (EVM chains) | +| `--anti-mev` | No | Enable anti-MEV protection | + +**Response fields (data):** + +| Field | Type | Description | +|-------|------|-------------| +| `order_id` | string | Created strategy order ID | +| `is_update` | bool | `true` if an existing order was updated | + +--- + +## order strategy list + +List strategy orders. Uses normal auth. + +```bash +gmgn-cli order strategy list --chain [--type ] [--from
] [--base-token
] [--page-token ] [--limit ] [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | +| `--type` | No | `open` (default) / `history` | +| `--from` | No | Filter by wallet address | +| `--base-token` | No | Filter by token address | +| `--page-token` | No | Pagination cursor from previous response | +| `--limit` | No | Results per page | + +**Response fields (data):** + +| Field | Type | Description | +|-------|------|-------------| +| `next_page_token` | string | Cursor for next page; empty when no more data | +| `total` | int | Total count (only when `--type open`) | +| `list` | array | Strategy order list | + +--- + +## order strategy cancel + +Cancel a strategy order. **Requires `GMGN_PRIVATE_KEY` configured in `.env`.** + +```bash +gmgn-cli order strategy cancel --chain --from --order-id [--close-sell-model ] [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | +| `--from` | Yes | Wallet address (must match API Key binding) | +| `--order-id` | Yes | Order ID to cancel | +| `--close-sell-model` | No | Sell model when closing | + +--- + +## cooking stats + +Get token creation statistics grouped by launchpad. + +```bash +gmgn-cli cooking stats [--raw] +``` + +No additional options required. Returns an array of `{ launchpad, token_count }` entries. + +--- + +## cooking create + +Create a token on a launchpad platform. **Requires `GMGN_PRIVATE_KEY` configured in `.env`.** + +```bash +gmgn-cli cooking create \ + --chain \ + --dex \ + --from \ + --name \ + --symbol \ + --buy-amt \ + [--image | --image-url ] \ + [--slippage | --auto-slippage] \ + [--website ] [--twitter ] [--telegram ] \ + [--priority-fee ] [--tip-fee ] [--gas-price ] \ + [--anti-mev] \ + [--raw] +``` + +| Option | Required | Description | +|--------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` / `eth` / `ton` | +| `--dex` | Yes | Launchpad: `pump` / `raydium` / `pancakeswap` / `flap` / `fourmeme` / `bonk` / `bags` / ... | +| `--from` | Yes | Wallet address (must match API Key binding) | +| `--name` | Yes | Token name | +| `--symbol` | Yes | Token symbol | +| `--buy-amt` | Yes | Initial buy amount in native token (e.g. `0.01` SOL) | +| `--image` | No* | Token logo as base64-encoded data (max 2MB decoded); required unless `--image-url` is used | +| `--image-url` | No* | Token logo URL; required unless `--image` is used | +| `--website` | No | Website URL | +| `--twitter` | No | Twitter link | +| `--telegram` | No | Telegram link | +| `--slippage` | No | Slippage tolerance, e.g. `0.01` = 1% | +| `--auto-slippage` | No | Enable automatic slippage | +| `--priority-fee` | No | Priority fee in SOL (SOL only) | +| `--tip-fee` | No | Tip fee | +| `--gas-price` | No | Gas price in wei (EVM chains) | +| `--anti-mev` | No | Enable anti-MEV protection | + +**Response fields (data):** + +| Field | Type | Description | +|-------|------|-------------| +| `status` | string | `pending` / `confirmed` / `failed` | +| `hash` | string | Transaction hash | +| `order_id` | string | Order ID for polling | +| `error_code` | string | Error code on failure | +| `error_status` | string | Error description on failure | + +Token creation is asynchronous. Poll `order get` with the returned `order_id` if `status` is `pending`. + +--- + ## Rate Limit Handling All business routes are protected by GMGN's leaky-bucket limiter. Current production behavior is: diff --git a/skills/gmgn-cooking/SKILL.md b/skills/gmgn-cooking/SKILL.md new file mode 100644 index 0000000..48cd99c --- /dev/null +++ b/skills/gmgn-cooking/SKILL.md @@ -0,0 +1,123 @@ +--- +name: gmgn-cooking +description: "[FINANCIAL EXECUTION] Create tokens on launchpad platforms (Pump.fun, Raydium, PancakeSwap, Flap, FourMeme, Bonk, BAGS, etc.) or query token creation statistics by launchpad. Token creation executes irreversible on-chain transactions. Requires explicit user confirmation before every create. Supports sol / bsc / base." +argument-hint: "stats | [create --chain --dex --from --name --symbol --buy-amt (--image | --image-url )]" +metadata: + cliHelp: "gmgn-cli cooking --help" +--- + +**IMPORTANT: Always use `gmgn-cli` commands below. Do NOT use web search, WebFetch, curl, or visit gmgn.ai.** + +**⚠️ Token creation executes REAL, IRREVERSIBLE blockchain transactions. Always require explicit user confirmation before running `cooking create`.** + +## Sub-commands + +| Sub-command | Description | +|-------------|-------------| +| `cooking stats` | Get token creation statistics grouped by launchpad (normal auth) | +| `cooking create` | Create a token on a launchpad platform (requires private key) | + +## Supported Chains + +`sol` / `bsc` / `base` / `eth` / `ton` + +## Supported Launchpads by Chain + +| Chain | Supported DEX / Launchpad | +|-------|--------------------------| +| `sol` | `pump` / `raydium` / `bonk` / `bags` / `memoo` / `letsbonk` / `bonkers` | +| `bsc` | `pancakeswap` / `flap` / `fourmeme` | +| `base` | `clanker` / `flaunch` / `baseapp` / `basememe` / `zora` / `virtuals_v2` | + +## Prerequisites + +- `cooking stats`: Only `GMGN_API_KEY` required +- `cooking create`: Both `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` must be configured in `~/.config/gmgn/.env`. The private key must correspond to the wallet bound to the API Key. +- `gmgn-cli` installed globally — if missing, run: `npm install -g gmgn-cli` + +## `cooking stats` Usage + +```bash +gmgn-cli cooking stats [--raw] +``` + +**Response fields (data array):** + +| Field | Type | Description | +|-------|------|-------------| +| `launchpad` | string | Launchpad identifier (e.g. `pump`, `raydium`, `pancakeswap`) | +| `token_count` | int | Number of tokens created on that launchpad | + +## `cooking create` Parameters + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `--chain` | Yes | Chain: `sol` / `bsc` / `base` / `eth` / `ton` | +| `--dex` | Yes | Launchpad platform (see Supported Launchpads table) | +| `--from` | Yes | Wallet address (must match API Key binding) | +| `--name` | Yes | Token name | +| `--symbol` | Yes | Token symbol | +| `--buy-amt` | Yes | Initial buy amount in native token (e.g. `0.01` for 0.01 SOL) | +| `--image` | No* | Token logo as base64-encoded data (max 2MB decoded). One of `--image` or `--image-url` is required | +| `--image-url` | No* | Token logo URL. One of `--image` or `--image-url` is required | +| `--website` | No | Website URL | +| `--twitter` | No | Twitter link | +| `--telegram` | No | Telegram link | +| `--slippage` | No | Slippage tolerance, e.g. `0.01` = 1%. Mutually exclusive with `--auto-slippage` | +| `--auto-slippage` | No | Enable automatic slippage | +| `--priority-fee` | No | Priority fee in SOL (SOL only, ≥ 0.0001 SOL) | +| `--tip-fee` | No | Tip fee (SOL ≥ 0.00001 / BSC ≥ 0.000001 BNB; ignored on ETH/BASE) | +| `--gas-price` | No | Gas price in wei (EVM chains) | +| `--anti-mev` | No | Enable anti-MEV protection | + +## `cooking create` Response Fields + +| Field | Type | Description | +|-------|------|-------------| +| `status` | string | `pending` / `confirmed` / `failed` | +| `hash` | string | Transaction hash (may be empty while pending) | +| `order_id` | string | Order ID for polling via `order get` | +| `error_code` | string | Error code on failure | +| `error_status` | string | Error description on failure | + +Token creation is asynchronous. If `status` is `pending`, poll with `gmgn-cli order get --chain --order-id ` every 2 seconds (up to 30 seconds). The new token's mint address is available in the order detail's `output_token` field once confirmed. + +## Usage Examples + +```bash +# Get launchpad creation statistics +gmgn-cli cooking stats + +# Create a token on Pump.fun (SOL) +gmgn-cli cooking create \ + --chain sol \ + --dex pump \ + --from \ + --name "My Token" \ + --symbol MAT \ + --buy-amt 0.01 \ + --image-url https://example.com/logo.png \ + --slippage 0.01 \ + --priority-fee 0.001 + +# Create a token on PancakeSwap (BSC) +gmgn-cli cooking create \ + --chain bsc \ + --dex pancakeswap \ + --from \ + --name "BSC Token" \ + --symbol BSCT \ + --buy-amt 0.01 \ + --image-url https://example.com/logo.png \ + --slippage 0.02 \ + --gas-price 5000000000 \ + --website https://mytoken.io \ + --twitter https://twitter.com/mytoken +``` + +## Notes + +- `cooking create` uses **critical auth** (API Key + signature) — CLI handles signing automatically +- Either `--image` (base64) or `--image-url` is required; both `--slippage` and `--auto-slippage` cannot be omitted (provide one) +- After creation, poll `order get` to get `confirmed` status and the new token's mint address from `output_token` +- Use `--raw` to get single-line JSON for further processing diff --git a/skills/gmgn-swap/SKILL.md b/skills/gmgn-swap/SKILL.md index 18f4e0a..dea1f43 100644 --- a/skills/gmgn-swap/SKILL.md +++ b/skills/gmgn-swap/SKILL.md @@ -48,6 +48,9 @@ Use the `gmgn-cli` tool to submit a token swap or query an existing order. **Req | `swap` | Submit a token swap | | `order quote` | Get a swap quote (no transaction submitted) | | `order get` | Query order status | +| `order strategy create` | Create a limit/strategy order (requires private key) | +| `order strategy list` | List strategy orders (normal auth) | +| `order strategy cancel` | Cancel a strategy order (requires private key) | ## Supported Chains @@ -279,11 +282,119 @@ Order ID: {order_id} Convert `filled_input_amount` and `filled_output_amount` from smallest unit using token decimals before displaying. +## `order strategy create` Parameters + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | +| `--from` | Yes | Wallet address (must match API Key binding) | +| `--base-token` | Yes | Base token contract address | +| `--quote-token` | Yes | Quote token contract address | +| `--side` | Yes | Direction: `buy` / `sell` | +| `--open-price` | Yes | Open price; compared with `--check-price` to infer order type | +| `--check-price` | Yes | Trigger check price; compared with `--open-price` to infer order type | +| `--amount-in` | No* | Input amount (smallest unit). Mutually exclusive with `--amount-in-percent` | +| `--amount-in-percent` | No* | Input as percentage (e.g. `50` = 50%). Mutually exclusive with `--amount-in` | +| `--limit-price-mode` | No | `exact` / `slippage` (default: `slippage`) | +| `--expire-in` | No | Order expiry in seconds | +| `--sell-ratio-type` | No | `buy_amount` (default) / `hold_amount` | +| `--slippage` | No | Slippage tolerance, e.g. `0.01` = 1%. Mutually exclusive with `--auto-slippage` | +| `--auto-slippage` | No | Enable automatic slippage | +| `--priority-fee` | No | Priority fee in SOL (SOL only) | +| `--tip-fee` | No | Tip fee | +| `--gas-price` | No | Gas price in wei (EVM chains) | +| `--anti-mev` | No | Enable anti-MEV protection | + +Order direction is inferred automatically from `--side` and the comparison between `--open-price` and `--check-price`: + +| `--side` | open_price vs check_price | Inferred type | +|----------|--------------------------|---------------| +| `buy` | open_price > check_price | buy_low | +| `buy` | open_price < check_price | buy_high | +| `sell` | open_price > check_price | stop_loss | +| `sell` | open_price < check_price | take_profit | + +**`order strategy create` Response Fields:** + +| Field | Type | Description | +|-------|------|-------------| +| `order_id` | string | Created strategy order ID | +| `is_update` | bool | `true` if an existing order was updated, `false` if newly created | + +## `order strategy list` Parameters + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | +| `--type` | No | `open` (default) / `history` | +| `--from` | No | Filter by wallet address | +| `--base-token` | No | Filter by token address | +| `--page-token` | No | Pagination cursor from previous response | +| `--limit` | No | Results per page (default 10 for history) | + +**`order strategy list` Response Fields:** + +| Field | Type | Description | +|-------|------|-------------| +| `next_page_token` | string | Cursor for next page; empty when no more data | +| `total` | int | Total count (only returned when `--type open`) | +| `list` | array | Strategy order list | + +## `order strategy cancel` Parameters + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `--chain` | Yes | `sol` / `bsc` / `base` | +| `--from` | Yes | Wallet address (must match API Key binding) | +| `--order-id` | Yes | Order ID to cancel | +| `--close-sell-model` | No | Sell model when closing the order | + +## `order strategy` Usage Examples + +```bash +# Create a take-profit order: sell when price rises above open price +gmgn-cli order strategy create \ + --chain sol \ + --from \ + --base-token \ + --quote-token \ + --side sell \ + --open-price 0.001 \ + --check-price 0.002 \ + --amount-in 1000000 \ + --slippage 0.01 + +# Create a stop-loss order: sell when price drops below open price +gmgn-cli order strategy create \ + --chain sol \ + --from \ + --base-token \ + --quote-token \ + --side sell \ + --open-price 0.001 \ + --check-price 0.0005 \ + --amount-in-percent 100 \ + --slippage 0.01 + +# List open strategy orders +gmgn-cli order strategy list --chain sol + +# List history orders with pagination +gmgn-cli order strategy list --chain sol --type history --limit 20 + +# Cancel a strategy order +gmgn-cli order strategy cancel \ + --chain sol \ + --from \ + --order-id +``` + ## Notes - Swap uses **critical auth** (API Key + signature) — CLI handles signing automatically, no manual processing needed - After submitting a swap, use `order get` to poll for confirmation - `--amount` is in the **smallest unit** (e.g., lamports for SOL) +- `order strategy create` and `order strategy cancel` use critical auth (require `GMGN_PRIVATE_KEY`); `order strategy list` uses normal auth - Use `--raw` to get single-line JSON for further processing ## Input Validation diff --git a/src/client/OpenApiClient.ts b/src/client/OpenApiClient.ts index a03fef7..c9d2ce6 100644 --- a/src/client/OpenApiClient.ts +++ b/src/client/OpenApiClient.ts @@ -87,6 +87,63 @@ export interface SwapParams { max_priority_fee_per_gas?: string; } +export interface StrategyCreateParams { + chain: string; + from_address: string; + base_token: string; + quote_token: string; + side: string; + open_price: string; + check_price: string; + amount_in?: string; + amount_in_percent?: string; + limit_price_mode?: string; + price_gap_ratio?: string; + expire_in?: number; + sell_ratio_type?: string; + slippage?: number; + auto_slippage?: boolean; + fee?: string; + gas_price?: string; + max_fee_per_gas?: string; + max_priority_fee_per_gas?: string; + is_anti_mev?: boolean; + anti_mev_mode?: string; + priority_fee?: string; + tip_fee?: string; + custom_rpc?: string; +} + +export interface StrategyCancelParams { + chain: string; + from_address: string; + order_id: string; + close_sell_model?: string; +} + +export interface CreateTokenParams { + chain: string; + dex: string; + from_address: string; + name: string; + symbol: string; + buy_amt: string; + image?: string; + image_url?: string; + website?: string; + twitter?: string; + telegram?: string; + slippage?: number; + auto_slippage?: boolean; + priority_fee?: string; + tip_fee?: string; + gas_price?: string; + max_priority_fee_per_gas?: string; + max_fee_per_gas?: string; + is_anti_mev?: boolean; + anti_mev_mode?: string; +} + export class OpenApiClient { private readonly apiKey: string; private readonly privateKeyPem: string | undefined; @@ -239,6 +296,30 @@ export class OpenApiClient { return this.criticalRequest("GET", "/v1/trade/query_order", { order_id: orderId, chain }, null); } + // ---- Strategy order endpoints ---- + + async createStrategyOrder(params: StrategyCreateParams): Promise { + return this.criticalRequest("POST", "/v1/trade/strategy/create", {}, params); + } + + async getStrategyOrders(chain: string, extra: Record = {}): Promise { + return this.normalRequest("GET", "/v1/trade/strategy/orders", { chain, ...extra }); + } + + async cancelStrategyOrder(params: StrategyCancelParams): Promise { + return this.criticalRequest("POST", "/v1/trade/strategy/cancel", {}, params); + } + + // ---- Cooking endpoints ---- + + async getCookingStatistics(): Promise { + return this.normalRequest("GET", "/v1/cooking/statistics", {}); + } + + async createToken(params: CreateTokenParams): Promise { + return this.criticalRequest("POST", "/v1/cooking/create_token", {}, params); + } + // ---- Internal methods ---- private async normalRequest( diff --git a/src/commands/cooking.ts b/src/commands/cooking.ts new file mode 100644 index 0000000..df547bb --- /dev/null +++ b/src/commands/cooking.ts @@ -0,0 +1,74 @@ +import { Command } from "commander"; +import { OpenApiClient, CreateTokenParams } from "../client/OpenApiClient.js"; +import { getConfig } from "../config.js"; +import { exitOnError, printResult } from "../output.js"; +import { validateChain } from "../validate.js"; + +export function registerCookingCommands(program: Command): void { + const cooking = program.command("cooking").description("Token creation and launchpad commands"); + + cooking + .command("stats") + .description("Get token creation statistics by launchpad (normal auth)") + .option("--raw", "Output raw JSON") + .action(async (opts) => { + const client = new OpenApiClient(getConfig()); + const data = await client.getCookingStatistics().catch(exitOnError); + printResult(data, opts.raw); + }); + + cooking + .command("create") + .description("Create a token on a launchpad platform (requires private key)") + .requiredOption("--chain ", "Chain: sol / bsc / base / eth / ton") + .requiredOption("--dex ", "Launchpad: pump / raydium / pancakeswap / flap / fourmeme / bonk / bags / ...") + .requiredOption("--from
", "Wallet address (must match API Key binding)") + .requiredOption("--name ", "Token name") + .requiredOption("--symbol ", "Token symbol") + .requiredOption("--buy-amt ", "Initial buy amount in native token (e.g. 0.01 SOL)") + .option("--image ", "Token logo as base64-encoded data (max 2MB decoded)") + .option("--image-url ", "Token logo URL") + .option("--website ", "Website URL") + .option("--twitter ", "Twitter link") + .option("--telegram ", "Telegram link") + .option("--slippage ", "Slippage tolerance (e.g. 0.01 = 1%)", parseFloat) + .option("--auto-slippage", "Enable automatic slippage") + .option("--priority-fee ", "Priority fee in SOL (SOL only)") + .option("--tip-fee ", "Tip fee") + .option("--gas-price ", "Gas price in wei (EVM chains)") + .option("--anti-mev", "Enable anti-MEV protection") + .option("--raw", "Output raw JSON") + .action(async (opts) => { + if (!opts.image && !opts.imageUrl) { + console.error("[gmgn-cli] Either --image or --image-url must be provided"); + process.exit(1); + } + if (!opts.slippage && !opts.autoSlippage) { + console.error("[gmgn-cli] Either --slippage or --auto-slippage must be provided"); + process.exit(1); + } + validateChain(opts.chain); + const params: CreateTokenParams = { + chain: opts.chain, + dex: opts.dex, + from_address: opts.from, + name: opts.name, + symbol: opts.symbol, + buy_amt: opts.buyAmt, + }; + if (opts.image) params.image = opts.image; + if (opts.imageUrl) params.image_url = opts.imageUrl; + if (opts.website) params.website = opts.website; + if (opts.twitter) params.twitter = opts.twitter; + if (opts.telegram) params.telegram = opts.telegram; + if (opts.slippage != null) params.slippage = opts.slippage; + if (opts.autoSlippage) params.auto_slippage = true; + if (opts.priorityFee) params.priority_fee = opts.priorityFee; + if (opts.tipFee) params.tip_fee = opts.tipFee; + if (opts.gasPrice) params.gas_price = opts.gasPrice; + if (opts.antiMev) params.is_anti_mev = true; + const client = new OpenApiClient(getConfig(true)); + const data = await client.createToken(params).catch(exitOnError); + printResult(data, opts.raw); + }); +} diff --git a/src/commands/swap.ts b/src/commands/swap.ts index 35cabb1..d4d9f7d 100644 --- a/src/commands/swap.ts +++ b/src/commands/swap.ts @@ -1,5 +1,5 @@ import { Command } from "commander"; -import { OpenApiClient, SwapParams } from "../client/OpenApiClient.js"; +import { OpenApiClient, SwapParams, StrategyCreateParams, StrategyCancelParams } from "../client/OpenApiClient.js"; import { getConfig } from "../config.js"; import { exitOnError, printResult } from "../output.js"; import { validateAddress, validateChain, validatePercent, validatePositiveInt } from "../validate.js"; @@ -97,4 +97,107 @@ export function registerSwapCommands(program: Command): void { const data = await client.queryOrder(opts.orderId, opts.chain).catch(exitOnError); printResult(data, opts.raw); }); + + const strategy = order.command("strategy").description("Limit/strategy order management"); + + strategy + .command("create") + .description("Create a limit/strategy order (requires private key)") + .requiredOption("--chain ", "Chain: sol / bsc / base") + .requiredOption("--from
", "Wallet address (must match API Key binding)") + .requiredOption("--base-token
", "Base token contract address") + .requiredOption("--quote-token
", "Quote token contract address") + .requiredOption("--side ", "Direction: buy / sell") + .requiredOption("--open-price ", "Open price") + .requiredOption("--check-price ", "Trigger check price") + .option("--amount-in ", "Input amount (smallest unit)") + .option("--amount-in-percent ", "Input amount as a percentage (e.g. 50 = 50%)") + .option("--limit-price-mode ", "Price mode: exact / slippage (default: slippage)") + .option("--expire-in ", "Order expiry in seconds", parseInt) + .option("--sell-ratio-type ", "Sell ratio basis: buy_amount (default) / hold_amount") + .option("--slippage ", "Slippage tolerance (e.g. 0.01 = 1%)", parseFloat) + .option("--auto-slippage", "Enable automatic slippage") + .option("--priority-fee ", "Priority fee in SOL (SOL only)") + .option("--tip-fee ", "Tip fee") + .option("--gas-price ", "Gas price in wei (EVM chains)") + .option("--anti-mev", "Enable anti-MEV protection") + .option("--raw", "Output raw JSON") + .action(async (opts) => { + if (!opts.amountIn && !opts.amountInPercent) { + console.error("[gmgn-cli] Either --amount-in or --amount-in-percent must be provided"); + process.exit(1); + } + if (!opts.slippage && !opts.autoSlippage) { + console.error("[gmgn-cli] Either --slippage or --auto-slippage must be provided"); + process.exit(1); + } + validateChain(opts.chain); + const params: StrategyCreateParams = { + chain: opts.chain, + from_address: opts.from, + base_token: opts.baseToken, + quote_token: opts.quoteToken, + side: opts.side, + open_price: opts.openPrice, + check_price: opts.checkPrice, + }; + if (opts.amountIn) params.amount_in = opts.amountIn; + if (opts.amountInPercent) params.amount_in_percent = opts.amountInPercent; + if (opts.limitPriceMode) params.limit_price_mode = opts.limitPriceMode; + if (opts.expireIn != null) params.expire_in = opts.expireIn; + if (opts.sellRatioType) params.sell_ratio_type = opts.sellRatioType; + if (opts.slippage != null) params.slippage = opts.slippage; + if (opts.autoSlippage) params.auto_slippage = true; + if (opts.priorityFee) params.priority_fee = opts.priorityFee; + if (opts.tipFee) params.tip_fee = opts.tipFee; + if (opts.gasPrice) params.gas_price = opts.gasPrice; + if (opts.antiMev) params.is_anti_mev = true; + const client = new OpenApiClient(getConfig(true)); + const data = await client.createStrategyOrder(params).catch(exitOnError); + printResult(data, opts.raw); + }); + + strategy + .command("list") + .description("List strategy orders (normal auth)") + .requiredOption("--chain ", "Chain: sol / bsc / base") + .option("--type ", "open (default) / history") + .option("--from
", "Filter by wallet address") + .option("--base-token
", "Filter by token address") + .option("--page-token ", "Pagination cursor from previous response") + .option("--limit ", "Results per page", parseInt) + .option("--raw", "Output raw JSON") + .action(async (opts) => { + validateChain(opts.chain); + const extra: Record = {}; + if (opts.type) extra["type"] = opts.type; + if (opts.from) extra["from_address"] = opts.from; + if (opts.baseToken) extra["base_token"] = opts.baseToken; + if (opts.pageToken) extra["page_token"] = opts.pageToken; + if (opts.limit != null) extra["limit"] = opts.limit; + const client = new OpenApiClient(getConfig()); + const data = await client.getStrategyOrders(opts.chain, extra).catch(exitOnError); + printResult(data, opts.raw); + }); + + strategy + .command("cancel") + .description("Cancel a strategy order (requires private key)") + .requiredOption("--chain ", "Chain: sol / bsc / base") + .requiredOption("--from
", "Wallet address (must match API Key binding)") + .requiredOption("--order-id ", "Order ID to cancel") + .option("--close-sell-model ", "Sell model when closing") + .option("--raw", "Output raw JSON") + .action(async (opts) => { + validateChain(opts.chain); + const params: StrategyCancelParams = { + chain: opts.chain, + from_address: opts.from, + order_id: opts.orderId, + }; + if (opts.closeSellModel) params.close_sell_model = opts.closeSellModel; + const client = new OpenApiClient(getConfig(true)); + const data = await client.cancelStrategyOrder(params).catch(exitOnError); + printResult(data, opts.raw); + }); } diff --git a/src/index.ts b/src/index.ts index 21fdf6f..b3897f2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,6 +10,7 @@ import { registerMarketCommands } from "./commands/market.js"; import { registerPortfolioCommands } from "./commands/portfolio.js"; import { registerTrackCommands } from "./commands/track.js"; import { registerSwapCommands } from "./commands/swap.js"; +import { registerCookingCommands } from "./commands/cooking.js"; const proxy = process.env.HTTPS_PROXY ?? process.env.https_proxy ?? process.env.HTTP_PROXY ?? process.env.http_proxy; @@ -58,6 +59,7 @@ registerMarketCommands(program); registerPortfolioCommands(program); registerTrackCommands(program); registerSwapCommands(program); +registerCookingCommands(program); program.parseAsync().catch((err) => { console.error(`[gmgn-cli] ${err.message}`);