feat: add cooking command and update swap/docs

This commit is contained in:
deepfeature
2026-04-02 14:58:55 +08:00
parent 221bf120a8
commit 2e71f283f0
7 changed files with 660 additions and 1 deletions
+165
View File
@@ -457,6 +457,171 @@ npx gmgn-cli order get --chain <chain> --order-id <order_id> [--raw]
**Response fields (data):** Same structure as the `swap` response above. **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 <chain> \
--from <wallet_address> \
--base-token <base_token_address> \
--quote-token <quote_token_address> \
--side <buy|sell> \
--open-price <price> \
--check-price <price> \
[--amount-in <amount> | --amount-in-percent <pct>] \
[--slippage <n> | --auto-slippage] \
[--limit-price-mode <exact|slippage>] \
[--expire-in <seconds>] \
[--sell-ratio-type <buy_amount|hold_amount>] \
[--priority-fee <sol>] \
[--tip-fee <amount>] \
[--gas-price <amount>] \
[--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 <chain> [--type <open|history>] [--from <address>] [--base-token <address>] [--page-token <token>] [--limit <n>] [--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 <chain> --from <wallet_address> --order-id <id> [--close-sell-model <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 <chain> \
--dex <dex> \
--from <wallet_address> \
--name <name> \
--symbol <symbol> \
--buy-amt <amount> \
[--image <base64> | --image-url <url>] \
[--slippage <n> | --auto-slippage] \
[--website <url>] [--twitter <url>] [--telegram <url>] \
[--priority-fee <sol>] [--tip-fee <amount>] [--gas-price <amount>] \
[--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 ## Rate Limit Handling
All business routes are protected by GMGN's leaky-bucket limiter. Current production behavior is: All business routes are protected by GMGN's leaky-bucket limiter. Current production behavior is:
+123
View File
@@ -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 <chain> --dex <dex> --from <addr> --name <name> --symbol <sym> --buy-amt <n> (--image <base64> | --image-url <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 <chain> --order-id <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 <wallet_address> \
--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 <wallet_address> \
--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
+111
View File
@@ -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 | | `swap` | Submit a token swap |
| `order quote` | Get a swap quote (no transaction submitted) | | `order quote` | Get a swap quote (no transaction submitted) |
| `order get` | Query order status | | `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 ## 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. 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 <wallet_address> \
--base-token <token_address> \
--quote-token <sol_address> \
--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 <wallet_address> \
--base-token <token_address> \
--quote-token <sol_address> \
--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 <wallet_address> \
--order-id <order_id>
```
## Notes ## Notes
- Swap uses **critical auth** (API Key + signature) — CLI handles signing automatically, no manual processing needed - 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 - After submitting a swap, use `order get` to poll for confirmation
- `--amount` is in the **smallest unit** (e.g., lamports for SOL) - `--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 - Use `--raw` to get single-line JSON for further processing
## Input Validation ## Input Validation
+81
View File
@@ -87,6 +87,63 @@ export interface SwapParams {
max_priority_fee_per_gas?: string; 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 { export class OpenApiClient {
private readonly apiKey: string; private readonly apiKey: string;
private readonly privateKeyPem: string | undefined; 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); return this.criticalRequest("GET", "/v1/trade/query_order", { order_id: orderId, chain }, null);
} }
// ---- Strategy order endpoints ----
async createStrategyOrder(params: StrategyCreateParams): Promise<unknown> {
return this.criticalRequest("POST", "/v1/trade/strategy/create", {}, params);
}
async getStrategyOrders(chain: string, extra: Record<string, string | number> = {}): Promise<unknown> {
return this.normalRequest("GET", "/v1/trade/strategy/orders", { chain, ...extra });
}
async cancelStrategyOrder(params: StrategyCancelParams): Promise<unknown> {
return this.criticalRequest("POST", "/v1/trade/strategy/cancel", {}, params);
}
// ---- Cooking endpoints ----
async getCookingStatistics(): Promise<unknown> {
return this.normalRequest("GET", "/v1/cooking/statistics", {});
}
async createToken(params: CreateTokenParams): Promise<unknown> {
return this.criticalRequest("POST", "/v1/cooking/create_token", {}, params);
}
// ---- Internal methods ---- // ---- Internal methods ----
private async normalRequest( private async normalRequest(
+74
View File
@@ -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>", "Chain: sol / bsc / base / eth / ton")
.requiredOption("--dex <dex>", "Launchpad: pump / raydium / pancakeswap / flap / fourmeme / bonk / bags / ...")
.requiredOption("--from <address>", "Wallet address (must match API Key binding)")
.requiredOption("--name <name>", "Token name")
.requiredOption("--symbol <symbol>", "Token symbol")
.requiredOption("--buy-amt <amount>", "Initial buy amount in native token (e.g. 0.01 SOL)")
.option("--image <base64>", "Token logo as base64-encoded data (max 2MB decoded)")
.option("--image-url <url>", "Token logo URL")
.option("--website <url>", "Website URL")
.option("--twitter <url>", "Twitter link")
.option("--telegram <url>", "Telegram link")
.option("--slippage <n>", "Slippage tolerance (e.g. 0.01 = 1%)", parseFloat)
.option("--auto-slippage", "Enable automatic slippage")
.option("--priority-fee <sol>", "Priority fee in SOL (SOL only)")
.option("--tip-fee <amount>", "Tip fee")
.option("--gas-price <amount>", "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);
});
}
+104 -1
View File
@@ -1,5 +1,5 @@
import { Command } from "commander"; 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 { getConfig } from "../config.js";
import { exitOnError, printResult } from "../output.js"; import { exitOnError, printResult } from "../output.js";
import { validateAddress, validateChain, validatePercent, validatePositiveInt } from "../validate.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); const data = await client.queryOrder(opts.orderId, opts.chain).catch(exitOnError);
printResult(data, opts.raw); 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>", "Chain: sol / bsc / base")
.requiredOption("--from <address>", "Wallet address (must match API Key binding)")
.requiredOption("--base-token <address>", "Base token contract address")
.requiredOption("--quote-token <address>", "Quote token contract address")
.requiredOption("--side <side>", "Direction: buy / sell")
.requiredOption("--open-price <price>", "Open price")
.requiredOption("--check-price <price>", "Trigger check price")
.option("--amount-in <amount>", "Input amount (smallest unit)")
.option("--amount-in-percent <pct>", "Input amount as a percentage (e.g. 50 = 50%)")
.option("--limit-price-mode <mode>", "Price mode: exact / slippage (default: slippage)")
.option("--expire-in <seconds>", "Order expiry in seconds", parseInt)
.option("--sell-ratio-type <type>", "Sell ratio basis: buy_amount (default) / hold_amount")
.option("--slippage <n>", "Slippage tolerance (e.g. 0.01 = 1%)", parseFloat)
.option("--auto-slippage", "Enable automatic slippage")
.option("--priority-fee <sol>", "Priority fee in SOL (SOL only)")
.option("--tip-fee <amount>", "Tip fee")
.option("--gas-price <amount>", "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>", "Chain: sol / bsc / base")
.option("--type <type>", "open (default) / history")
.option("--from <address>", "Filter by wallet address")
.option("--base-token <address>", "Filter by token address")
.option("--page-token <token>", "Pagination cursor from previous response")
.option("--limit <n>", "Results per page", parseInt)
.option("--raw", "Output raw JSON")
.action(async (opts) => {
validateChain(opts.chain);
const extra: Record<string, string | number> = {};
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>", "Chain: sol / bsc / base")
.requiredOption("--from <address>", "Wallet address (must match API Key binding)")
.requiredOption("--order-id <id>", "Order ID to cancel")
.option("--close-sell-model <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);
});
} }
+2
View File
@@ -10,6 +10,7 @@ import { registerMarketCommands } from "./commands/market.js";
import { registerPortfolioCommands } from "./commands/portfolio.js"; import { registerPortfolioCommands } from "./commands/portfolio.js";
import { registerTrackCommands } from "./commands/track.js"; import { registerTrackCommands } from "./commands/track.js";
import { registerSwapCommands } from "./commands/swap.js"; import { registerSwapCommands } from "./commands/swap.js";
import { registerCookingCommands } from "./commands/cooking.js";
const proxy = process.env.HTTPS_PROXY ?? process.env.https_proxy const proxy = process.env.HTTPS_PROXY ?? process.env.https_proxy
?? process.env.HTTP_PROXY ?? process.env.http_proxy; ?? process.env.HTTP_PROXY ?? process.env.http_proxy;
@@ -58,6 +59,7 @@ registerMarketCommands(program);
registerPortfolioCommands(program); registerPortfolioCommands(program);
registerTrackCommands(program); registerTrackCommands(program);
registerSwapCommands(program); registerSwapCommands(program);
registerCookingCommands(program);
program.parseAsync().catch((err) => { program.parseAsync().catch((err) => {
console.error(`[gmgn-cli] ${err.message}`); console.error(`[gmgn-cli] ${err.message}`);