mirror of
https://github.com/GMGNAI/gmgn-skills.git
synced 2026-07-28 01:07:44 +00:00
Compare commits
110 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56a3a60352 | |||
| 211f7d6fd0 | |||
| 5e1560188e | |||
| 08f7b66251 | |||
| 48c596ab10 | |||
| ec099ea399 | |||
| 1012cfffb8 | |||
| f6f1d56b82 | |||
| b83422769f | |||
| 8922811e04 | |||
| cc1cb48db9 | |||
| 981600f170 | |||
| 1f49d61363 | |||
| 3046c6d6cd | |||
| ee4838d565 | |||
| f19a1919da | |||
| 4cfe0e0fb5 | |||
| 5755206b58 | |||
| 6ab9cb108b | |||
| 51d2214253 | |||
| 8d3541c2a3 | |||
| 39d80429f6 | |||
| fd226c654b | |||
| a08fc7b580 | |||
| f49c89e609 | |||
| ad4eab3852 | |||
| 6fd302af60 | |||
| cdcf4e11d3 | |||
| 319c4bbf33 | |||
| 2b61eb807a | |||
| 46c56b7e5d | |||
| b18738177c | |||
| cfb4270816 | |||
| 932bf8c82c | |||
| 4143e07266 | |||
| 4f96fedbb1 | |||
| eeb4a77cf7 | |||
| f7c051e2d1 | |||
| 8bc1b2be6b | |||
| 990601d031 | |||
| db55c77a26 | |||
| 91473cc366 | |||
| 38bff1aecb | |||
| 6d09536349 | |||
| cd9b285b3f | |||
| c6141c880f | |||
| 3551bc3a25 | |||
| 8448787176 | |||
| 04389b98f0 | |||
| 2949ea7de3 | |||
| 4dde77c481 | |||
| 02d497df92 | |||
| 48a06cd9b4 | |||
| 9e90bb9c07 | |||
| 31fababfd8 | |||
| 6833ff19cd | |||
| ccf3dc1c23 | |||
| 3c1ffdd7eb | |||
| 10d9c592d2 | |||
| ff3f52f3d8 | |||
| 1ea71149d9 | |||
| ca3c640afc | |||
| 2073b5fdaf | |||
| fce314b9ab | |||
| dbe3eec697 | |||
| a9979f9dd3 | |||
| 83aee6e759 | |||
| 567c5f92d1 | |||
| 25b9da3fdf | |||
| 7445c970bc | |||
| c525fba661 | |||
| 0ce0051e60 | |||
| 49397c2b62 | |||
| 8999d36d1d | |||
| 013a6c867c | |||
| 29eeb723e4 | |||
| 60a199cb80 | |||
| e4bc94c625 | |||
| ed27705826 | |||
| e9ff951083 | |||
| f7a2d075e3 | |||
| 8e413cef25 | |||
| 7959eaaed3 | |||
| 8c27e42aff | |||
| ae7729f26c | |||
| 759ab74709 | |||
| dd1cb9d2e5 | |||
| b12a2294b7 | |||
| cb21fff38c | |||
| 138d571f8b | |||
| 2e71f283f0 | |||
| 56086fa692 | |||
| 221bf120a8 | |||
| 09351a9205 | |||
| 91128a887e | |||
| d2a91ef7d1 | |||
| 5ec76cb465 | |||
| 40f75e0b64 | |||
| 3951d9963e | |||
| 5547e9fd30 | |||
| 3ca831a976 | |||
| aa27e1560a | |||
| d47404856d | |||
| b898d20c29 | |||
| 1e3fbaf623 | |||
| 8bcb68aa3c | |||
| b995e84d16 | |||
| e4e331223e | |||
| a48205ea3f | |||
| 6a1dc62b6e |
@@ -20,7 +20,7 @@ This includes: trending tokens, token info, security checks, K-line / price hist
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a **Claude Code plugin** — a collection of GMGN OpenAPI skills for on-chain operations. It provides CLI tools and skills for token queries, market data, wallet portfolio analysis, and swap execution across sol / bsc / base.
|
||||
This is a **Claude Code plugin** — a collection of GMGN OpenAPI skills for on-chain operations. It provides CLI tools and skills for token queries, market data, wallet portfolio analysis, and swap execution across sol / bsc / base / eth.
|
||||
|
||||
## Available Skills
|
||||
|
||||
@@ -93,8 +93,8 @@ EOF
|
||||
|
||||
| Mode | Commands | Requirements |
|
||||
|------|----------|--------------|
|
||||
| Normal | token / market / portfolio | `GMGN_API_KEY` only, no signature |
|
||||
| Critical | swap / order | `GMGN_API_KEY` + `GMGN_PRIVATE_KEY` — CLI handles signing automatically |
|
||||
| Normal | token / market / portfolio / track kol / track smartmoney | `GMGN_API_KEY` only, no signature |
|
||||
| Critical | swap / order / track follow-wallet | `GMGN_API_KEY` + `GMGN_PRIVATE_KEY` — CLI handles signing automatically |
|
||||
|
||||
## SKILL.md Authoring Rules
|
||||
|
||||
|
||||
@@ -10,7 +10,82 @@ English | [简体中文](Readme.zh.md)
|
||||
|
||||
## GMGN Agent Skills
|
||||
|
||||
With GMGN Agent Skills, you can use AI agents to query real-time trending token rankings across multiple chains, token fundamentals, social media signals, live trading activity, new tokens in Trenches, top holders, top traders, smart money positions, KOL holdings, insider wallets, bundled wallet exposure, and other professional on-chain analytics. It also supports market orders, limit orders, advanced take-profit/stop-loss strategy orders, and wallet management — including real-time holdings, recent P&L, and transaction history — all through natural language.
|
||||
With GMGN Agent Skills, you can use AI agents to query real-time trending token rankings across multiple chains, token fundamentals, social media signals, live trading activity, new tokens in Trenches, top holders, top traders, smart money positions, KOL holdings, insider wallets, bundled wallet exposure, and other professional on-chain analytics. It also supports market orders, limit orders, advanced take-profit/stop-loss strategy orders, one-command cooking orders (buy + condition orders in a single flow), and wallet management — including real-time holdings, recent P&L, and transaction history — all through natural language.
|
||||
|
||||
---
|
||||
|
||||
## Why GMGN Skills
|
||||
|
||||
> Built for AI agents to query and trade multi-chain Meme tokens at high speed in real time. gmgn-skills gives AI agents direct access to GMGN's trending tokens, Trenches new token listings, and professional on-chain data — including Smart Money, KOL, rat trader, and bundler analytics.
|
||||
>
|
||||
> With 500+ professional data dimensions, you can turn your AI agent into a 24/7 real-time chain-scanning trading tool — monitoring multi-chain token momentum, placing orders instantly, and managing exits with take-profit / stop-loss, all on autopilot.
|
||||
|
||||
### 1. Real-time on-chain data — faster
|
||||
|
||||
Data across SOL / BSC / Base / ETH is live on every query. Supports multi-parameter customization, no snapshot cache — built for AI agent real-time decision-making (including but not limited to):
|
||||
|
||||
| Data | Granularity |
|
||||
|------|-------------|
|
||||
| New token discovery (Trenches) | Real-time, filtered by launchpad, dev holdings, KOL entry, rat trader ratio |
|
||||
| Trending tokens | Real-time, `1m` / `5m` / `1h` / `6h` / `24h` — minimum **1-minute** window |
|
||||
| Token info | Real-time — trade activity / price / volume / market cap |
|
||||
| Token security | Real-time — open source, renounced, honeypot detection, etc. |
|
||||
| Token analytics | Real-time — Dev / KOL / Smart Money / rat trader / bundler wallet holdings |
|
||||
| Monitoring & tracking | Real-time — KOL / Smart Money / followed wallet trade activity |
|
||||
| K-line (OHLCV) | Real-time, `1m` / `5m` / `15m` / `1h` / `4h` / `1d` — minimum **1-minute** candles |
|
||||
| Wallet holdings | Real-time — holdings / P&L / trade activity |
|
||||
|
||||
### 2. Trade faster
|
||||
|
||||
- Same RPC routing as GMGN's web trading interface, multi-region deployment, millisecond response — order submission under **0.3 seconds** end-to-end.
|
||||
- Automatic best-route selection, the same routing engine as GMGN web.
|
||||
- Market orders, limit orders, and strategy orders (take-profit / stop-loss) in a single command.
|
||||
- Sell by position percentage (`--percent 50`) without calculating exact amounts.
|
||||
|
||||
| Order Type | Description |
|
||||
|------------|-------------|
|
||||
| Market Order | Instant execution at current market price |
|
||||
| Limit Order | Trigger buy or sell at a specified price |
|
||||
| Take-Profit / Stop-Loss | Fixed-price exit conditions attached to a swap |
|
||||
| Trailing Take-Profit / Trailing Stop-Loss | Tracks price peak; fires after a specified drawdown % — rides momentum while protecting gains |
|
||||
| Multi-Wallet Batch Trading | Buy with multiple wallets simultaneously, each with its own take-profit / stop-loss / trailing take-profit / trailing stop-loss orders |
|
||||
|
||||
### 3. More comprehensive token data
|
||||
|
||||
No more scraping web pages or getting blocked by Cloudflare. Query all the professional analytics needed for high-frequency Meme token trading, with high concurrency in real time (including but not limited to):
|
||||
|
||||
- **Smart money count** (`smart_degen_count`) and **KOL holders** (`renowned_wallets`) — live
|
||||
- **Rat trader ratio** (`rat_trader_amount_rate`) — volume share from insider/sneak wallets
|
||||
- **Bundler bot exposure** (`bundler_trader_amount_rate`) — volume from bot-bundled buys
|
||||
- **Sniper wallets** (`sniper_count`) — wallets that bought at the exact moment of launch
|
||||
- **Suspected insider hold rate** (`suspected_insider_hold_rate`)
|
||||
- **Fresh wallet ratio** (`fresh_wallet_rate`)
|
||||
- **Rug ratio score** (0–1) + honeypot detection + wash-trade flag
|
||||
- **Bonding curve status** (`is_on_curve`) — whether the token has graduated to open DEX
|
||||
|
||||
### 4. What you can do with GMGN Skills
|
||||
|
||||
**Real-time chain scanning**
|
||||
- Scan Trenches for new tokens, filtered by launchpad (Pump.fun, letsbonk, fourmeme, clanker…), dev holdings, KOL entry, and rat trader ratio in real time
|
||||
- Browse multi-chain trending token rankings (minimum 1-minute granularity), sorted by volume, smart money count, market cap, and more
|
||||
- Track new tokens in real time — see which tokens KOLs, Smart Money, and wallets you follow are buying, and auto-analyze the latest hot tokens
|
||||
- Fetch real-time K-line / OHLCV data for any token (1m / 5m / 15m / 1h / 4h / 1d)
|
||||
|
||||
**Token analytics**
|
||||
- Query token fundamentals, social links, Bonding Curve status, and liquidity pool details
|
||||
- Security check: open source, renounced, honeypot, wash trading, Rug ratio score (0–1)
|
||||
- Deep holder analysis: Smart Money / KOL / rat trader / bundler / sniper / whale / fresh wallet — holdings breakdown and rankings
|
||||
|
||||
**Wallet & tracking**
|
||||
- Analyze any wallet: real-time holdings, realized / unrealized P&L, win rate, trade style, full history
|
||||
- Track the latest buys and sells from Smart Money, KOL, and wallets you follow in real time
|
||||
|
||||
**Automated trading**
|
||||
- Market orders, limit orders, take-profit / stop-loss strategy orders — end-to-end latency under 0.3 seconds
|
||||
- One-command sell by position percentage (`--percent 50`), no manual calculation needed
|
||||
|
||||
**AI workflows**
|
||||
- 9 built-in workflow docs: token research, project deep report, wallet analysis, Smart Money profiling, risk warning, early project screening, daily brief, market discovery, and more — ready to use out of the box
|
||||
|
||||
---
|
||||
|
||||
@@ -22,7 +97,8 @@ With GMGN Agent Skills, you can use AI agents to query real-time trending token
|
||||
| [`/gmgn-market`](skills/gmgn-market/SKILL.md) | K-line market data, trending tokens | [SKILL.md](skills/gmgn-market/SKILL.md) |
|
||||
| [`/gmgn-portfolio`](skills/gmgn-portfolio/SKILL.md) | Wallet holdings, activity, stats | [SKILL.md](skills/gmgn-portfolio/SKILL.md) |
|
||||
| [`/gmgn-track`](skills/gmgn-track/SKILL.md) | Follow-wallet trades, KOL trades, Smart Money trades | [SKILL.md](skills/gmgn-track/SKILL.md) |
|
||||
| [`/gmgn-swap`](skills/gmgn-swap/SKILL.md) | Swap submission + order query | [SKILL.md](skills/gmgn-swap/SKILL.md) |
|
||||
| [`/gmgn-swap`](skills/gmgn-swap/SKILL.md) | Swap submission + limit orders + strategy orders + order query | [SKILL.md](skills/gmgn-swap/SKILL.md) |
|
||||
| [`/gmgn-cooking`](skills/gmgn-cooking/SKILL.md) | One-command cooking orders (buy + take-profit/stop-loss in a single flow) | [SKILL.md](skills/gmgn-cooking/SKILL.md) |
|
||||
|
||||
> For detailed CLI commands, parameters, and recommended values, see the [Wiki documentation](https://github.com/GMGNAI/gmgn-skills/wiki).
|
||||
|
||||
@@ -32,7 +108,7 @@ With GMGN Agent Skills, you can use AI agents to query real-time trending token
|
||||
|
||||
Ready to install? [Jump to Installation →](#1-installation)
|
||||
|
||||
Already installed? [Upgrade Skills and CLI →](#9-upgrade-skills-and-cli)
|
||||
Already installed? [Upgrade Skills and CLI →](#10-upgrade-skills-and-cli)
|
||||
|
||||
> **Tip:** If your AI agent tries to open or scrape the gmgn.ai website instead of using the CLI, add this to your prompt: `Use gmgn-cli commands. Do not call gmgn.ai web endpoints directly.`
|
||||
|
||||
@@ -48,19 +124,23 @@ Already installed? [Upgrade Skills and CLI →](#9-upgrade-skills-and-cli)
|
||||
npx skills add GMGNAI/gmgn-skills
|
||||
```
|
||||
|
||||
**Step 2 — Verify with public key (no registration needed)**
|
||||
**Step 2 — Verify CLI installation (demo key)**
|
||||
|
||||
```bash
|
||||
GMGN_API_KEY=gmgn_solbscbaseethmonadtron gmgn-cli market trending --chain sol --interval 1h --limit 3
|
||||
```
|
||||
|
||||
If JSON output appears, the CLI is working.
|
||||
If JSON output appears, the CLI is installed correctly. **Setup is NOT yet complete — this is a public demo key for testing only. You must continue to Steps 3–4 to configure the user's personal API key. Do not stop here.**
|
||||
|
||||
**Step 3 — Guide user to get their own API key**
|
||||
**Step 3 — REQUIRED: Set up personal API key**
|
||||
|
||||
Tell the user: "To use your own API key, go to **https://gmgn.ai/ai** and apply. You will need an Ed25519 public key. I can generate a key pair for you — just say the word."
|
||||
⚠️ This step is mandatory. The demo key in Step 2 supports testing only and is not for actual use.
|
||||
|
||||
When the user asks, run:
|
||||
Immediately tell the user the following, then run the key generation command **without waiting for them to ask**:
|
||||
|
||||
> "To use GMGN Skills, you need your own API key from **https://gmgn.ai/ai**. I'm generating an Ed25519 key pair for you now."
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
@@ -73,7 +153,7 @@ Show the **public key** to the user with the following instructions:
|
||||
> 1. Go to **https://gmgn.ai/ai**, paste the public key above into the API Key creation form, and submit.
|
||||
> 2. Once created, copy the **API Key** shown on the page and send it back to me — I'll handle Step 4 configuration for you.
|
||||
|
||||
Wait for the user to reply with their API Key before continuing to Step 4.
|
||||
**Wait for the user to reply with their API Key before continuing to Step 4.**
|
||||
|
||||
**Step 4 — Configure credentials**
|
||||
|
||||
@@ -86,7 +166,7 @@ echo 'GMGN_API_KEY=<user_api_key>' > ~/.config/gmgn/.env
|
||||
chmod 600 ~/.config/gmgn/.env
|
||||
```
|
||||
|
||||
If the user also needs swap capability, append the private key:
|
||||
If the user also needs swap or order capability, append the private key:
|
||||
|
||||
```bash
|
||||
# Append private key (use the PEM content from Step 3)
|
||||
@@ -105,9 +185,10 @@ If output appears without error, setup is complete.
|
||||
|
||||
## Upgrade (AI Agent)
|
||||
|
||||
> Run this command to upgrade both the CLI and Skills to the latest version.
|
||||
> Run these two commands to upgrade both the CLI and Skills to the latest version.
|
||||
|
||||
```bash
|
||||
npm install -g gmgn-cli
|
||||
npx skills add GMGNAI/gmgn-skills
|
||||
```
|
||||
|
||||
@@ -117,7 +198,7 @@ Check the installed version after upgrading:
|
||||
gmgn-cli --version
|
||||
```
|
||||
|
||||
> For the full upgrade reference, see [Section 9 — Upgrade Skills and CLI](#9-upgrade-skills-and-cli).
|
||||
> For the full upgrade reference, see [Section 10 — Upgrade Skills and CLI](#10-upgrade-skills-and-cli).
|
||||
|
||||
---
|
||||
|
||||
@@ -269,7 +350,7 @@ Skills are automatically discovered via the `.cursor-plugin/` configuration.
|
||||
```bash
|
||||
echo "$(npm root -g)/gmgn-skills/skills"
|
||||
```
|
||||
3. Restart Cline — `/gmgn-token`, `/gmgn-market`, `/gmgn-portfolio`, `/gmgn-track`, `/gmgn-swap` will be available
|
||||
3. Restart Cline — `/gmgn-token`, `/gmgn-market`, `/gmgn-portfolio`, `/gmgn-track`, `/gmgn-swap`, `/gmgn-cooking` will be available
|
||||
|
||||
#### Codex CLI
|
||||
|
||||
@@ -302,12 +383,23 @@ Natural language prompts you can send to any AI assistant with gmgn-cli skills i
|
||||
```
|
||||
buy 0.1 SOL of <token_address>
|
||||
sell 50% of <token_address> on BSC
|
||||
sell 30% of my <token_address> position
|
||||
get a quote: how much <token_address> can I get for 1 SOL?
|
||||
check order status <order_id>
|
||||
is <token_address> safe to buy on solana?
|
||||
show top holders of <token_address>
|
||||
show smart money holdings of <token_address>, sorted by buy volume
|
||||
show recent KOL trades for <token_address>
|
||||
show my wallet holdings on SOL
|
||||
query token details for 0x1234...
|
||||
show 24h K-line and volume for <token_address>
|
||||
show trading stats for wallet <wallet_address> on BSC
|
||||
show recent trades for wallet <wallet_address>
|
||||
which wallets are linked to my API key, and what are their balances
|
||||
show the latest smart money trades on SOL
|
||||
show what KOLs are buying on SOL
|
||||
show newly launched tokens on Solana
|
||||
show Solana 1-minute trending tokens
|
||||
```
|
||||
|
||||
### Typical Workflows
|
||||
@@ -357,52 +449,80 @@ Full parameter reference: [docs/cli-usage.md](docs/cli-usage.md). All commands s
|
||||
### Token
|
||||
|
||||
```bash
|
||||
npx gmgn-cli token info --chain sol --address <addr>
|
||||
gmgn-cli token info --chain sol --address <addr>
|
||||
```
|
||||
|
||||
### Market
|
||||
|
||||
```bash
|
||||
npx gmgn-cli market trending \
|
||||
gmgn-cli market trending \
|
||||
--chain sol \
|
||||
--interval 1h \
|
||||
--order-by volume --limit 20 \
|
||||
--filter not_risk --filter not_honeypot
|
||||
|
||||
npx gmgn-cli market trenches \
|
||||
gmgn-cli market trenches \
|
||||
--chain sol \
|
||||
--type new_creation --type near_completion --type completed \
|
||||
--launchpad-platform Pump.fun --launchpad-platform pump_mayhem --launchpad-platform letsbonk \
|
||||
--limit 80
|
||||
|
||||
# With server-side filters: safe preset + require smart money + sort by smart degen count
|
||||
gmgn-cli market trenches \
|
||||
--chain sol --type new_creation \
|
||||
--filter-preset safe --min-smart-degen-count 1 --sort-by smart_degen_count
|
||||
|
||||
# Token signals — smart money buys on SOL (single group)
|
||||
gmgn-cli market signal --chain sol --signal-type 12 --raw
|
||||
|
||||
# Token signals — multi-group: smart money OR large buys in parallel
|
||||
gmgn-cli market signal --chain sol \
|
||||
--groups '[{"signal_type":[12]},{"signal_type":[14,16]}]' --raw
|
||||
```
|
||||
|
||||
### Portfolio
|
||||
|
||||
```bash
|
||||
npx gmgn-cli portfolio holdings --chain sol --wallet <addr>
|
||||
# Holdings
|
||||
gmgn-cli portfolio holdings --chain sol --wallet <addr>
|
||||
|
||||
# Activity
|
||||
gmgn-cli portfolio activity --chain sol --wallet <addr>
|
||||
|
||||
# Stats (supports multiple wallets)
|
||||
gmgn-cli portfolio stats --chain sol --wallet <addr1> --wallet <addr2>
|
||||
|
||||
# Wallets and balances linked to API key
|
||||
gmgn-cli portfolio info
|
||||
|
||||
# Single token balance
|
||||
gmgn-cli portfolio token-balance --chain sol --wallet <addr> --token <token_addr>
|
||||
|
||||
# Tokens created by a developer wallet
|
||||
gmgn-cli portfolio created-tokens --chain sol --wallet <addr>
|
||||
```
|
||||
|
||||
### Track
|
||||
|
||||
```bash
|
||||
# Follow-wallet trade records (requires GMGN_PRIVATE_KEY)
|
||||
npx gmgn-cli track follow-wallet --chain sol
|
||||
npx gmgn-cli track follow-wallet --chain sol --wallet <wallet_address> --side buy
|
||||
# Follow-wallet trade records
|
||||
gmgn-cli track follow-wallet --chain sol
|
||||
gmgn-cli track follow-wallet --chain sol --limit 20 --min-amount-usd 1000
|
||||
|
||||
# KOL trade records
|
||||
npx gmgn-cli track kol --limit 100 --raw
|
||||
npx gmgn-cli track kol --chain sol --side buy --limit 50 --raw
|
||||
gmgn-cli track kol --limit 100 --raw
|
||||
gmgn-cli track kol --chain sol --side buy --limit 50 --raw
|
||||
|
||||
# Smart Money trade records
|
||||
npx gmgn-cli track smartmoney --limit 100 --raw
|
||||
npx gmgn-cli track smartmoney --chain sol --side sell --limit 50 --raw
|
||||
gmgn-cli track smartmoney --limit 100 --raw
|
||||
gmgn-cli track smartmoney --chain sol --side sell --limit 50 --raw
|
||||
```
|
||||
|
||||
### Swap (requires private key)
|
||||
### Swap / Quote / Query
|
||||
|
||||
```bash
|
||||
# Submit swap with fixed slippage
|
||||
npx gmgn-cli swap \
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet-address> \
|
||||
--input-token <input-token-addr> \
|
||||
@@ -411,7 +531,7 @@ npx gmgn-cli swap \
|
||||
--slippage 0.01
|
||||
|
||||
# Submit swap with automatic slippage
|
||||
npx gmgn-cli swap \
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet-address> \
|
||||
--input-token <input-token-addr> \
|
||||
@@ -419,23 +539,151 @@ npx gmgn-cli swap \
|
||||
--amount 1000000 \
|
||||
--auto-slippage
|
||||
|
||||
# Sell by position percentage (e.g. sell 50%)
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet-address> \
|
||||
--input-token <token-addr> \
|
||||
--output-token <usdc-addr> \
|
||||
--percent 50 \
|
||||
--auto-slippage
|
||||
|
||||
# Get quote (no transaction submitted)
|
||||
gmgn-cli order quote \
|
||||
--chain sol \
|
||||
--from <wallet-address> \
|
||||
--input-token <input-token-addr> \
|
||||
--output-token <output-token-addr> \
|
||||
--amount 1000000 \
|
||||
--slippage 0.01
|
||||
|
||||
# Quotes use critical auth and require GMGN_PRIVATE_KEY on every chain
|
||||
gmgn-cli order quote \
|
||||
--chain bsc \
|
||||
--from <wallet-address> \
|
||||
--input-token <input-token-addr> \
|
||||
--output-token <output-token-addr> \
|
||||
--amount 1000000000000000000 \
|
||||
--slippage 0.01
|
||||
|
||||
# Query order
|
||||
npx gmgn-cli order get --chain sol --order-id <order-id>
|
||||
gmgn-cli order get --chain sol --order-id <order-id>
|
||||
|
||||
# Multi-wallet concurrent swap
|
||||
gmgn-cli multi-swap \
|
||||
--chain sol \
|
||||
--accounts <addr1>,<addr2> \
|
||||
--input-token <input-token-addr> \
|
||||
--output-token <output-token-addr> \
|
||||
--input-amount '{"<addr1>":"1000000","<addr2>":"2000000"}' \
|
||||
--slippage 0.01
|
||||
```
|
||||
|
||||
## 8. Supported Chains
|
||||
> `order quote` uses critical auth on `sol` / `bsc` / `base` / `eth` and requires `GMGN_PRIVATE_KEY`.
|
||||
|
||||
| Commands | Chains | Chain Currencies |
|
||||
|----------|--------|-----------------|
|
||||
| token / market / portfolio / track | `sol` / `bsc` / `base` | — |
|
||||
| swap / order | `sol` / `bsc` / `base` | sol: SOL, USDC · bsc: BNB, USDC · base: ETH, USDC |
|
||||
### Swap with Take-Profit / Stop-Loss Orders (requires private key)
|
||||
|
||||
**`hold_amount` mode** — each condition order fires based on current holdings at trigger time:
|
||||
|
||||
```bash
|
||||
# Buy token A with 0.01 SOL; take-profit 50% at +100%, take-profit remaining 50% at +300%, stop-loss 100% at -65%
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_A_address> \
|
||||
--amount 10000000 \
|
||||
--slippage 0.3 \
|
||||
--anti-mev \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"50"},{"order_type":"profit_stop","side":"sell","price_scale":"300","sell_ratio":"100"},{"order_type":"loss_stop","side":"sell","price_scale":"65","sell_ratio":"100"}]' \
|
||||
--sell-ratio-type hold_amount
|
||||
```
|
||||
|
||||
> `price_scale` for `profit_stop`: gain % from entry (`"100"` = +100% / 2×, `"300"` = +300% / 4×). For `loss_stop`: drop % from entry (`"65"` = drops 65%, triggers at 35% of entry).
|
||||
> `hold_amount`: the second take-profit fires on whatever is held at that point (the remaining 50%). If you added to your position in between, those additional tokens will be included as well.
|
||||
|
||||
**`buy_amount` mode** — each condition order fires based on the original bought amount:
|
||||
|
||||
```bash
|
||||
# Same strategy using fixed percentages of the original bought amount
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_A_address> \
|
||||
--amount 10000000 \
|
||||
--slippage 0.3 \
|
||||
--anti-mev \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"50"},{"order_type":"profit_stop","side":"sell","price_scale":"300","sell_ratio":"50"},{"order_type":"loss_stop","side":"sell","price_scale":"65","sell_ratio":"100"}]' \
|
||||
--sell-ratio-type buy_amount
|
||||
```
|
||||
|
||||
> `buy_amount`: each take-profit sells 50% of the **original** bought amount. Stop-loss sells 100% of the original bought amount.
|
||||
|
||||
---
|
||||
|
||||
## 9. Upgrade Skills and CLI
|
||||
### Limit Orders (requires private key)
|
||||
|
||||
```bash
|
||||
# Upgrade CLI and Skills
|
||||
# Create a take-profit order
|
||||
gmgn-cli order strategy create \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--base-token <token_address> \
|
||||
--quote-token <sol_address> \
|
||||
--sub-order-type take_profit \
|
||||
--check-price 0.002 \
|
||||
--amount-in-percent 100 \
|
||||
--slippage 0.01
|
||||
|
||||
# Create a stop-loss order
|
||||
gmgn-cli order strategy create \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--base-token <token_address> \
|
||||
--quote-token <sol_address> \
|
||||
--sub-order-type stop_loss \
|
||||
--check-price 0.0005 \
|
||||
--amount-in-percent 100 \
|
||||
--slippage 0.01
|
||||
|
||||
# List open strategy orders (requires private key)
|
||||
gmgn-cli order strategy list --chain sol
|
||||
|
||||
# Cancel a strategy order
|
||||
gmgn-cli order strategy cancel --chain sol --from <wallet_address> --order-id <order_id>
|
||||
```
|
||||
|
||||
### Cooking (requires private key)
|
||||
|
||||
```bash
|
||||
# Buy token and automatically attach take-profit + stop-loss condition orders
|
||||
gmgn-cli cooking \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_address> \
|
||||
--amount 1000000000 \
|
||||
--slippage 0.3 \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"100"},{"order_type":"loss_stop","side":"sell","price_scale":"50","sell_ratio":"100"}]'
|
||||
```
|
||||
|
||||
## 9. Supported Chains
|
||||
|
||||
| Commands | Chains | Chain Currencies |
|
||||
|----------|--------|-----------------|
|
||||
| token / market / portfolio / track | `sol` / `bsc` / `base` / `eth` | — |
|
||||
| swap / order | `sol` / `bsc` / `base` / `eth` | sol: SOL, USDC · bsc: BNB, USDC · base: ETH, USDC · eth: ETH |
|
||||
|
||||
---
|
||||
|
||||
## 10. Upgrade Skills and CLI
|
||||
|
||||
```bash
|
||||
# Upgrade CLI
|
||||
npm install -g gmgn-cli
|
||||
|
||||
# Upgrade Skills
|
||||
npx skills add GMGNAI/gmgn-skills
|
||||
|
||||
# Check current version
|
||||
@@ -446,7 +694,7 @@ gmgn-cli --version
|
||||
|
||||
---
|
||||
|
||||
## 10. Security & Disclaimer (Read Before Use)
|
||||
## 11. Security & Disclaimer (Read Before Use)
|
||||
|
||||
This tool can be invoked by an AI Agent to submit real on-chain transactions automatically. It carries inherent risks including model hallucination, uncontrolled execution, and prompt injection. Once authorized, the AI Agent will submit transactions on behalf of your linked wallet address — **on-chain transactions are irreversible once confirmed** and may result in financial loss. Use with caution.
|
||||
|
||||
|
||||
+223
-44
@@ -10,7 +10,85 @@
|
||||
|
||||
## GMGN Agent Skills
|
||||
|
||||
使用 GMGN Agent Skills,你可以通过 AI Agent 实时查询多个链上热门代币排行榜,代币基础信息,社交媒体信息,实时交易动态,实时战壕新币,报持仓大户(Top Holder),交易大户(Top Trader),聪明钱持仓占比,KOL持仓占比,老鼠仓持仓,捆绑持仓占比,等代币专业数据分析数据,以及支持代币市价单交易、限价单交易、高级止盈止损策略单交易,以及钱包资产管理相关功能,例如查询钱包实时持仓、钱包最近盈亏、钱包交易动态等,全部通过自然语言与 AI Agent 交互即可完成。
|
||||
使用 GMGN Agent Skills,你可以通过 AI Agent 实时查询多个链上热门代币排行榜,代币基础信息,社交媒体信息,实时交易动态,实时战壕新币,报持仓大户(Top Holder),交易大户(Top Trader),聪明钱持仓占比,KOL持仓占比,老鼠仓持仓,捆绑持仓占比,等代币专业数据分析数据,以及支持代币市价单交易、限价单交易、高级止盈止损策略单交易、一键 Cooking 策略单(买入 + 条件单一体化),以及钱包资产管理相关功能,例如查询钱包实时持仓、钱包最近盈亏、钱包交易动态等,全部通过自然语言与 AI Agent 交互即可完成。
|
||||
|
||||
---
|
||||
|
||||
## 为什么选择 GMGN Skills
|
||||
|
||||
> 专为 AI Agent 高速实时查询、交易多链 Meme 代币而生。GMGN Skills 让 AI Agent 可以实时批量查询 GMGN 网站展示的热门代币、Trenches新创建代币,以及聪明钱、KOL、老鼠仓等专业顶级交易数据。
|
||||
>
|
||||
> 凭借 500+ 专业数据分析维度,你可以将自己的 AI Agent 打造成 7×24 小时全天候托管的实时扫链交易工具——实时监控多链代币热点、实时下单、实时止盈止损,实现全自动化交易。
|
||||
|
||||
### 1. 链上实时数据查询快
|
||||
|
||||
SOL / BSC / Base / ETH 多链数据每次查询均为实时,支持多参数个性化调用,无快照缓存,方便AI Agent实时决策(包括不限于下表)。
|
||||
|
||||
| 数据类型 | 粒度 |
|
||||
|---------|------|
|
||||
| 新币发现(战壕) | 实时,按 Launchpad 平台,dev持仓,KOL持仓,老鼠仓持仓分类 |
|
||||
| 热门代币榜单 | 实时,`1m` / `5m` / `1h` / `6h` / `24h`,最低支持 **1 分钟**窗口 |
|
||||
| 代币信息 |实时,交易动态 / 代币价格 / 交易量 / 市值 等|
|
||||
|代币安全 |实时,是否开源,弃权,貔貅检测等 |
|
||||
|代币数据分析|实时,Dev / KOL / 聪明钱 / 老鼠仓 / 捆绑钱包等持仓占比 等|
|
||||
|监控追踪|实时,KOL / 聪明钱 / 关注的钱包交易动态 / 天眼信号(开发中) 等|
|
||||
| K 线(OHLCV) | 实时,`1m` / `5m` / `15m` / `1h` / `4h` / `1d`,最低支持 **1 分钟** |
|
||||
|资产持仓|实时,持仓/盈亏/交易动态 等|
|
||||
|
||||
|
||||
|
||||
|
||||
### 2. 交易更快
|
||||
|
||||
- 与 GMGN 网页端共享同一套 RPC 路由,多区域部署,毫秒级响应,从下单到上链延时小于 **0.3 秒**。
|
||||
- 交易自动找最佳路由,与 GMGN 网页端同一套
|
||||
- 单条命令支持市价单、限价单、策略单(止盈 / 止损)。
|
||||
- 支持按仓位比例卖出(`--percent 50`),无需手动计算数量。
|
||||
|
||||
| 订单类型 | 说明 |
|
||||
|----------|------|
|
||||
| 市价单 | 以当前市价即时成交 |
|
||||
| 限价单 | 设定触发价格,到价买入或卖出 |
|
||||
| 止盈 / 止损 | 随买单附带固定价格的退出条件 |
|
||||
| 追踪止盈 / 追踪止损 | 跟踪价格峰值,回撤达到指定比例后触发,吃满行情同时保护收益 |
|
||||
| 多钱包批量交易 | 多个钱包同时买入,每个钱包分别创建对应的止盈 / 止损 / 追踪止盈 / 追踪止损订单 |
|
||||
|
||||
### 3. 特色数据更全
|
||||
|
||||
不用再爬网页,不会被Claudeflare拦截,现在就可以快速/多并发实时查询多链的 Meme 代币高频交易所需的所有专业分析指标数据 (包括不限于):
|
||||
|
||||
- **聪明钱数量**(`smart_degen_count`)和 **KOL 持仓**(`renowned_wallets`)— 实时
|
||||
- **老鼠仓占比**(`rat_trader_amount_rate`)— 内幕 / 偷跑钱包的交易量份额
|
||||
- **捆绑钱包暴露度**(`bundler_trader_amount_rate`)— 机器人捆绑买入的交易量占比
|
||||
- **狙击钱包数**(`sniper_count`)— 在代币刚开盘瞬间买入的钱包数量
|
||||
- **疑似内幕持仓比**(`suspected_insider_hold_rate`)
|
||||
- **新钱包占比**(`fresh_wallet_rate`)
|
||||
- **Rug 风险评分**(0–1)+ 貔貅检测 + 对倒洗盘识别
|
||||
- **Bonding Curve 状态**(`is_on_curve`)— 代币是否已毕业到开放 DEX
|
||||
|
||||
### 4. 可以用 GMGN Skills 做什么
|
||||
|
||||
**实时查链**
|
||||
- 扫描战壕新币,按 Launchpad(Pump.fun、letsbonk、fourmeme、clanker……)、dev 持仓、KOL 进场、老鼠仓占比实时过滤
|
||||
- 浏览多链热门代币榜单(最低 1 分钟粒度),按交易量、聪明钱数量、市值等多维排序
|
||||
- 实时追踪新币,追踪KOL/聪明/已关注的钱包最近在买哪些新币,自动分析最新热门代币
|
||||
- 获取任意代币的实时 K 线 / OHLCV 数据(1m / 5m / 15m / 1h / 4h / 1d)
|
||||
|
||||
**代币数据分析**
|
||||
- 查询代币基础信息、社交链接、Bonding Curve 状态、流动性池详情
|
||||
- 安全核查:是否开源、弃权、貔貅、对倒洗盘、Rug 风险评分(0–1)
|
||||
- 深度持仓分析:聪明钱 / KOL / 老鼠仓 / 捆绑钱包 / 狙击手 / 巨鲸 / 新钱包 各类持仓占比及排名
|
||||
|
||||
**钱包与追踪**
|
||||
- 分析任意钱包:实时持仓、已实现 / 未实现盈亏、胜率、交易风格、历史流水
|
||||
- 实时追踪聪明钱、KOL 和关注钱包的最新买卖动态
|
||||
|
||||
**自动化交易**
|
||||
- 市价单、限价单、止盈止损策略单,从下单到上链延时 < 0.3 秒
|
||||
- 按仓位比例一键卖出(`--percent 50`),无需手动计算数量
|
||||
|
||||
**AI 工作流**
|
||||
- 9 个内置工作流文档:代币研究、项目深度报告、钱包分析、聪明钱画像、风险预警、早期项目筛选、每日简报、市场发现等,开箱即用
|
||||
|
||||
---
|
||||
|
||||
@@ -22,7 +100,8 @@
|
||||
| [`/gmgn-market`](skills/gmgn-market/SKILL.md) | K 线行情数据、热门代币 | [SKILL.md](skills/gmgn-market/SKILL.md) |
|
||||
| [`/gmgn-portfolio`](skills/gmgn-portfolio/SKILL.md) | 钱包持仓、活动、统计 | [SKILL.md](skills/gmgn-portfolio/SKILL.md) |
|
||||
| [`/gmgn-track`](skills/gmgn-track/SKILL.md) | 追踪关注钱包交易动态、KOL 交易动态、聪明钱交易动态 | [SKILL.md](skills/gmgn-track/SKILL.md) |
|
||||
| [`/gmgn-swap`](skills/gmgn-swap/SKILL.md) | 兑换提交 + 订单查询 | [SKILL.md](skills/gmgn-swap/SKILL.md) |
|
||||
| [`/gmgn-swap`](skills/gmgn-swap/SKILL.md) | 兑换提交 + 限价单 + 策略单 + 订单查询 | [SKILL.md](skills/gmgn-swap/SKILL.md) |
|
||||
| [`/gmgn-cooking`](skills/gmgn-cooking/SKILL.md) | 一键 Cooking 策略单(买入 + 止盈止损条件单一体化) | [SKILL.md](skills/gmgn-cooking/SKILL.md) |
|
||||
|
||||
> 如需查看详细的 CLI 接口说明、传参格式和推荐值,请参阅 [Wiki 文档](https://github.com/GMGNAI/gmgn-skills/wiki/Home-Chinese)。
|
||||
|
||||
@@ -32,7 +111,7 @@
|
||||
|
||||
已准备好?[点击这里开始安装 Skills →](#开始安装-skills)
|
||||
|
||||
已安装?[升级 Skills 和 CLI →](#9-升级-skills-和-cli)
|
||||
已安装?[升级 Skills 和 CLI →](#10-升级-skills-和-cli)
|
||||
|
||||
> **提示:** 如果你的 AI Agent 尝试直接打开 gmgn.ai 网站而不是使用 CLI,请在提示词中加上:
|
||||
> ```
|
||||
@@ -51,19 +130,23 @@
|
||||
npx skills add GMGNAI/gmgn-skills
|
||||
```
|
||||
|
||||
**第 2 步 — 用公共 Key 验证(无需注册)**
|
||||
**第 2 步 — 验证 CLI 安装(演示 Key)**
|
||||
|
||||
```bash
|
||||
GMGN_API_KEY=gmgn_solbscbaseethmonadtron gmgn-cli market trending --chain sol --interval 1h --limit 3
|
||||
```
|
||||
|
||||
看到 JSON 输出即表示 CLI 正常工作。
|
||||
看到 JSON 输出说明 CLI 已安装成功。**但配置尚未完成 —— 此公共演示 Key 仅用于测试,不可用于实际使用。必须继续完成第 3~4 步,为用户配置个人 API Key。请勿在此停止。**
|
||||
|
||||
**第 3 步 — 引导用户申请个人 API Key**
|
||||
**第 3 步 — 必须完成:配置个人 API Key**
|
||||
|
||||
告知用户:"需要个人 API Key,请前往 **https://gmgn.ai/ai** 申请。申请时需要一个 Ed25519 公钥,我可以帮你生成密钥对,告诉我一声就行。"
|
||||
⚠️ 此步骤为必填项。第 2 步中的演示 Key 仅支持测试,无法用于正式使用。
|
||||
|
||||
用户确认后运行:
|
||||
请**立即**告知用户以下内容,并**无需等待用户主动询问**,直接运行密钥生成命令:
|
||||
|
||||
> "使用 GMGN Skills 需要你自己的个人 API Key,申请地址:**https://gmgn.ai/ai**。我现在为你生成 Ed25519 密钥对。"
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
@@ -76,7 +159,7 @@ openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
> 1. 打开 **https://gmgn.ai/ai**,将上方公钥填入 API Key 生成表单,完成创建。
|
||||
> 2. 创建完成后,将页面上显示的 **API Key** 复制并发送给我,我来帮你完成第 4 步配置。
|
||||
|
||||
等用户回复 API Key 后,再继续第 4 步。
|
||||
**等用户回复 API Key 后,再继续第 4 步。**
|
||||
|
||||
**第 4 步 — 配置凭证**
|
||||
|
||||
@@ -89,7 +172,7 @@ echo 'GMGN_API_KEY=<user_api_key>' > ~/.config/gmgn/.env
|
||||
chmod 600 ~/.config/gmgn/.env
|
||||
```
|
||||
|
||||
如果用户需要 swap 能力,追加私钥:
|
||||
如果用户需要 swap 或 order 能力,追加私钥:
|
||||
|
||||
```bash
|
||||
# 追加私钥(使用第 3 步输出的 PEM 内容)
|
||||
@@ -108,9 +191,10 @@ gmgn-cli market trending --chain sol --interval 1h --limit 3
|
||||
|
||||
## AI Agent 升级
|
||||
|
||||
> 运行以下命令,将 CLI 和 Skills 同时升级到最新版本。
|
||||
> 运行以下两条命令,将 CLI 和 Skills 同时升级到最新版本。
|
||||
|
||||
```bash
|
||||
npm install -g gmgn-cli
|
||||
npx skills add GMGNAI/gmgn-skills
|
||||
```
|
||||
|
||||
@@ -120,7 +204,7 @@ npx skills add GMGNAI/gmgn-skills
|
||||
gmgn-cli --version
|
||||
```
|
||||
|
||||
> 完整升级说明请参阅[第 9 节 — 升级 Skills 和 CLI](#9-升级-skills-和-cli)。
|
||||
> 完整升级说明请参阅[第 10 节 — 升级 Skills 和 CLI](#10-升级-skills-和-cli)。
|
||||
|
||||
---
|
||||
|
||||
@@ -149,15 +233,6 @@ gmgn-cli --version
|
||||
|
||||
---
|
||||
|
||||
## 开始安装 Skills
|
||||
|
||||
安装前,请先在 **https://gmgn.ai/ai** 创建 API Key,用于:
|
||||
|
||||
1. 读取数据:代币、榜单、K 线、特色数据指标
|
||||
2. 提交交易:市价立即交易、创建限价单、策略单等
|
||||
|
||||
---
|
||||
|
||||
## 1. 安装
|
||||
|
||||
选择以下任意一种方式
|
||||
@@ -186,20 +261,10 @@ node dist/index.js <command> [options]
|
||||
|
||||
## 2. 验证连通性
|
||||
|
||||
### 方式一:通过 AI Agent 验证
|
||||
|
||||
发送以下提示词给你的 AI Agent:
|
||||
|
||||
```
|
||||
执行这个cli命令:GMGN_API_KEY=gmgn_solbscbaseethmonadtron npx gmgn-cli market trending --chain sol --interval 1h --limit 3
|
||||
```
|
||||
|
||||
### 方式二:通过 CLI 验证
|
||||
|
||||
使用公共 API Key 测试,无需注册:
|
||||
|
||||
```bash
|
||||
GMGN_API_KEY=gmgn_solbscbaseethmonadtron npx gmgn-cli market trending --chain sol --interval 1h --limit 3
|
||||
GMGN_API_KEY=gmgn_solbscbaseethmonadtron gmgn-cli market trending --chain sol --interval 1h --limit 3
|
||||
```
|
||||
|
||||
看到 JSON 输出即表示 CLI 正常工作。公共 Key 支持所有只读接口(token / market / portfolio),公共 Key 仅用于测试,正式使用任何接口均需申请个人 API Key(见第 3 步)。
|
||||
@@ -289,7 +354,7 @@ cp .env.example .env
|
||||
```bash
|
||||
echo "$(npm root -g)/gmgn-skills/skills"
|
||||
```
|
||||
3. 重启 Cline — `/gmgn-token`、`/gmgn-market`、`/gmgn-portfolio`、`/gmgn-track`、`/gmgn-swap` 即可使用
|
||||
3. 重启 Cline — `/gmgn-token`、`/gmgn-market`、`/gmgn-portfolio`、`/gmgn-track`、`/gmgn-swap`、`/gmgn-cooking` 即可使用
|
||||
|
||||
#### Codex CLI
|
||||
|
||||
@@ -386,7 +451,6 @@ solana 上的 <token_address> 安全吗,值得买入吗?
|
||||
完整参数说明:[docs/cli-usage.md](docs/cli-usage.md)。所有命令均支持 `--raw` 输出单行 JSON(方便 `jq` 等工具处理)。
|
||||
|
||||
### Token
|
||||
|
||||
```bash
|
||||
# 基本信息 + 实时价格
|
||||
gmgn-cli token info --chain sol --address <addr>
|
||||
@@ -433,6 +497,11 @@ gmgn-cli market trenches \
|
||||
--type new_creation --type near_completion --type completed \
|
||||
--launchpad-platform Pump.fun --launchpad-platform pump_mayhem --launchpad-platform letsbonk \
|
||||
--limit 80
|
||||
|
||||
# 服务端过滤:安全预设 + 要求有聪明钱 + 按聪明钱数量排序
|
||||
gmgn-cli market trenches \
|
||||
--chain sol --type new_creation \
|
||||
--filter-preset safe --min-smart-degen-count 1 --sort-by smart_degen_count
|
||||
```
|
||||
|
||||
### Portfolio
|
||||
@@ -452,14 +521,17 @@ gmgn-cli portfolio info
|
||||
|
||||
# 单个 token 余额
|
||||
gmgn-cli portfolio token-balance --chain sol --wallet <addr> --token <token_addr>
|
||||
|
||||
# 查询开发者钱包创建的代币列表
|
||||
gmgn-cli portfolio created-tokens --chain sol --wallet <addr>
|
||||
```
|
||||
|
||||
### Track
|
||||
|
||||
```bash
|
||||
# 追踪关注钱包的交易动态(需要 GMGN_PRIVATE_KEY)
|
||||
# 追踪关注钱包的交易动态
|
||||
gmgn-cli track follow-wallet --chain sol
|
||||
gmgn-cli track follow-wallet --chain sol --wallet <wallet_address> --side buy
|
||||
gmgn-cli track follow-wallet --chain sol --limit 20 --min-amount-usd 1000
|
||||
|
||||
# KOL 交易动态
|
||||
gmgn-cli track kol --limit 100 --raw
|
||||
@@ -470,7 +542,7 @@ gmgn-cli track smartmoney --limit 100 --raw
|
||||
gmgn-cli track smartmoney --chain sol --side sell --limit 50 --raw
|
||||
```
|
||||
|
||||
### Swap(需要私钥)
|
||||
### Swap / Quote / Query
|
||||
|
||||
```bash
|
||||
# 提交兑换(固定滑点)
|
||||
@@ -509,20 +581,127 @@ gmgn-cli order quote \
|
||||
--amount 1000000 \
|
||||
--slippage 0.01
|
||||
|
||||
# 所有链上的 quote 都走关键鉴权,需要 GMGN_PRIVATE_KEY
|
||||
gmgn-cli order quote \
|
||||
--chain bsc \
|
||||
--from <wallet-address> \
|
||||
--input-token <input-token-addr> \
|
||||
--output-token <output-token-addr> \
|
||||
--amount 1000000000000000000 \
|
||||
--slippage 0.01
|
||||
|
||||
# 查询订单状态
|
||||
gmgn-cli order get --chain sol --order-id <order-id>
|
||||
|
||||
# 多钱包并发 Swap
|
||||
gmgn-cli multi-swap \
|
||||
--chain sol \
|
||||
--accounts <addr1>,<addr2> \
|
||||
--input-token <input-token-addr> \
|
||||
--output-token <output-token-addr> \
|
||||
--input-amount '{"<addr1>":"1000000","<addr2>":"2000000"}' \
|
||||
--slippage 0.01
|
||||
```
|
||||
|
||||
## 8. 支持的链
|
||||
> `order quote` 在 `sol` / `bsc` / `base` / `eth` 上都走关键鉴权,必须配置 `GMGN_PRIVATE_KEY`。
|
||||
|
||||
| 接口类型 | 支持的链 | 链原生货币 |
|
||||
|----------|----------|-----------|
|
||||
| token / market / portfolio / track | `sol` / `bsc` / `base` | — |
|
||||
| swap / order | `sol` / `bsc` / `base` | sol: SOL、USDC · bsc: BNB、USDC · base: ETH、USDC |
|
||||
### 带止盈止损的 Swap(需要私钥)
|
||||
|
||||
**`hold_amount` 模式** — 按触发时的实际持仓比例卖出:
|
||||
|
||||
```bash
|
||||
# 用 0.01 SOL 买入代币 A;涨 100% 卖 50%,涨 300% 卖剩余 50%,跌 65% 全卖
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_A_address> \
|
||||
--amount 10000000 \
|
||||
--slippage 0.3 \
|
||||
--anti-mev \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"50"},{"order_type":"profit_stop","side":"sell","price_scale":"300","sell_ratio":"100"},{"order_type":"loss_stop","side":"sell","price_scale":"65","sell_ratio":"100"}]' \
|
||||
--sell-ratio-type hold_amount
|
||||
```
|
||||
|
||||
> `price_scale` 止盈时为涨幅百分比(`"100"` = 涨 100% / 2×,`"300"` = 涨 300% / 4×);止损时为跌幅百分比(`"65"` = 跌 65%,触发价为入场价的 35%)。
|
||||
> `hold_amount`:第二个止盈单触发时,按触发时持仓(剩余 50%)的 100% 卖出。如果中间有加仓,加仓的部分也会一同被卖掉。
|
||||
|
||||
**`buy_amount` 模式** — 按原始买入量的固定百分比卖出:
|
||||
|
||||
```bash
|
||||
# 相同策略,使用原始买入量的固定百分比
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_A_address> \
|
||||
--amount 10000000 \
|
||||
--slippage 0.3 \
|
||||
--anti-mev \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"50"},{"order_type":"profit_stop","side":"sell","price_scale":"300","sell_ratio":"50"},{"order_type":"loss_stop","side":"sell","price_scale":"65","sell_ratio":"100"}]' \
|
||||
--sell-ratio-type buy_amount
|
||||
```
|
||||
|
||||
> `buy_amount`:每个止盈单各卖原始买入量的 50%,止损单卖原始买入量的 100%。
|
||||
|
||||
---
|
||||
|
||||
## 9. 升级 Skills 和 CLI
|
||||
### 限价单(需要私钥)
|
||||
|
||||
```bash
|
||||
# 创建止盈单
|
||||
gmgn-cli order strategy create \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--base-token <token_address> \
|
||||
--quote-token <sol_address> \
|
||||
--sub-order-type take_profit \
|
||||
--check-price 0.002 \
|
||||
--amount-in-percent 100 \
|
||||
--slippage 0.01
|
||||
|
||||
# 创建止损单
|
||||
gmgn-cli order strategy create \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--base-token <token_address> \
|
||||
--quote-token <sol_address> \
|
||||
--sub-order-type stop_loss \
|
||||
--check-price 0.0005 \
|
||||
--amount-in-percent 100 \
|
||||
--slippage 0.01
|
||||
|
||||
# 查看当前挂单(需要私钥)
|
||||
gmgn-cli order strategy list --chain sol
|
||||
|
||||
# 撤销策略单
|
||||
gmgn-cli order strategy cancel --chain sol --from <wallet_address> --order-id <order_id>
|
||||
```
|
||||
|
||||
### Cooking 一键策略单(需要私钥)
|
||||
|
||||
```bash
|
||||
# 买入代币,同时自动挂止盈 + 止损条件单
|
||||
gmgn-cli cooking \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_address> \
|
||||
--amount 1000000000 \
|
||||
--slippage 0.3 \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"100"},{"order_type":"loss_stop","side":"sell","price_scale":"50","sell_ratio":"100"}]'
|
||||
```
|
||||
|
||||
## 9. 支持的链
|
||||
|
||||
| 接口类型 | 支持的链 | 链原生货币 |
|
||||
|----------|----------|-----------|
|
||||
| token / market / portfolio / track | `sol` / `bsc` / `base` / `eth` | — |
|
||||
| swap / order | `sol` / `bsc` / `base` / `eth` | sol: SOL、USDC · bsc: BNB、USDC · base: ETH、USDC · eth: ETH |
|
||||
|
||||
---
|
||||
|
||||
## 10. 升级 Skills 和 CLI
|
||||
|
||||
将 `gmgn-cli` 和 Skills 升级到最新版本:
|
||||
|
||||
@@ -554,7 +733,7 @@ gmgn-cli --version
|
||||
|
||||
---
|
||||
|
||||
## 10. 安全与免责(使用前必读)
|
||||
## 11. 安全与免责(使用前必读)
|
||||
|
||||
本工具可供 AI Agent 调用以自动执行链上交易,存在模型幻觉、执行不可控、提示词注入等固有风险。AI Agent 在获得授权后,将以您绑定的钱包地址提交真实的链上交易,**交易一经上链即不可撤销**,可能导致资金损失,请您谨慎使用。
|
||||
|
||||
|
||||
+362
-25
@@ -255,6 +255,30 @@ npx gmgn-cli portfolio token-balance \
|
||||
|
||||
---
|
||||
|
||||
## portfolio created-tokens
|
||||
|
||||
Query tokens created by a developer wallet.
|
||||
|
||||
```bash
|
||||
npx gmgn-cli portfolio created-tokens \
|
||||
--chain <chain> \
|
||||
--wallet <wallet_address> \
|
||||
[--order-by <field>] \
|
||||
[--direction asc|desc] \
|
||||
[--migrate-state <state>] \
|
||||
[--raw]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` |
|
||||
| `--wallet` | Yes | Developer wallet address |
|
||||
| `--order-by` | No | Sort field: `market_cap` / `token_ath_mc` |
|
||||
| `--direction` | No | Sort direction: `asc` / `desc` |
|
||||
| `--migrate-state` | No | Filter: `migrated` / `non_migrated` |
|
||||
|
||||
---
|
||||
|
||||
## market trenches
|
||||
|
||||
Query Trenches token lists (new creation, near completion, completed).
|
||||
@@ -274,77 +298,120 @@ npx gmgn-cli market trenches --chain <chain> [--type <type...>] [--launchpad-pla
|
||||
|
||||
---
|
||||
|
||||
## portfolio follow-wallet
|
||||
## market signal
|
||||
|
||||
Query follow-wallet trade records.
|
||||
Query token signals — price spikes, smart money buys, large buys, Dex ads, CTO events, and more. Returns a list of `TokenSignalItem` sorted by `trigger_at` descending (most recent first). **Maximum 50 results per group.**
|
||||
|
||||
```bash
|
||||
npx gmgn-cli portfolio follow-wallet \
|
||||
# Single group (individual flags):
|
||||
gmgn-cli market signal --chain sol [--signal-type <n>...] [--mc-min <usd>] [--mc-max <usd>] [--raw]
|
||||
|
||||
# Multi-group override (JSON array):
|
||||
gmgn-cli market signal --chain sol --groups '<json_array>' [--raw]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` |
|
||||
| `--signal-type` | No | Signal type(s), repeatable (1–18, default: all). See Signal Types below. |
|
||||
| `--mc-min` | No | Min market cap at trigger time (USD) |
|
||||
| `--mc-max` | No | Max market cap at trigger time (USD) |
|
||||
| `--trigger-mc-min` | No | Min market cap at signal trigger moment (USD) |
|
||||
| `--trigger-mc-max` | No | Max market cap at signal trigger moment (USD) |
|
||||
| `--total-fee-min` | No | Min total fees paid (USD) |
|
||||
| `--total-fee-max` | No | Max total fees paid (USD) |
|
||||
| `--min-create-or-open-ts` | No | Min token creation or open timestamp (Unix seconds string) |
|
||||
| `--max-create-or-open-ts` | No | Max token creation or open timestamp (Unix seconds string) |
|
||||
| `--groups` | No | Multi-group JSON array — overrides all individual flags when provided |
|
||||
|
||||
**Signal Types:**
|
||||
|
||||
| Value | Name | Description |
|
||||
|-------|------|-------------|
|
||||
| 1 | SignalType1 | General signal (K-line price spike) |
|
||||
| 2 | SignalTypeDexAd | Dex ad placement |
|
||||
| 3 | SignalTypeDexUpdateLink | Dex social link updated |
|
||||
| 4 | SignalTypeDexTrendingBar | Dex trending bar |
|
||||
| 5 | SignalTypeDexBoost | Dex Boost |
|
||||
| 6 | SignalTypePriceUp | Price spike |
|
||||
| 7 | SignalTypePriceATH | All-time high price |
|
||||
| 8 | SignalTypeMcpKeyLevel | Market cap key level |
|
||||
| 9 | SignalTypeLive | Live stream |
|
||||
| 10 | SignalTypeBundlerSell | Bundler sell |
|
||||
| 11 | SignalTypeCto | Community takeover (CTO) |
|
||||
| 12 | SignalTypeSmartDegenBuy | Smart money buy |
|
||||
| 13 | SignalTypePlatformCall | Platform call |
|
||||
| 14 | SignalTypeLargeAmountBuy | Large amount buy |
|
||||
| 15 | SignalTypeMultiBuy | Multiple buys |
|
||||
| 16 | SignalTypeMultiLargeBuy | Multiple large buys |
|
||||
| 17 | SignalTypeBagsClaims | Bags Claim |
|
||||
| 18 | SignalTypePumpClaims | Pump Claim |
|
||||
|
||||
---
|
||||
|
||||
## portfolio follow-wallet
|
||||
|
||||
Query follow-wallet trade records. Returns trades from wallets you personally follow on the GMGN platform. The follow list is resolved automatically from the GMGN user account bound to the API Key — `--wallet` is optional. Normal auth (API Key only, no private key needed).
|
||||
|
||||
```bash
|
||||
gmgn-cli track follow-wallet \
|
||||
--chain <chain> \
|
||||
[--wallet <wallet_address>] \
|
||||
[--base-token <token_address>] \
|
||||
[--page-token <cursor>] \
|
||||
[--limit <n>] \
|
||||
[--side <side>] \
|
||||
[--cost <cost>] \
|
||||
[--filter <tag>] \
|
||||
[--with-balance] \
|
||||
[--with-security] \
|
||||
[--min-amount-usd <n>] \
|
||||
[--max-amount-usd <n>] \
|
||||
[--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 |
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` |
|
||||
| `--wallet` | No | Wallet address (optional; follow list resolved from API Key's bound user account) |
|
||||
| `--limit` | No | Page size (1–100, default 10) |
|
||||
| `--side` | No | Trade direction: `buy` / `sell` |
|
||||
| `--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).
|
||||
Query KOL trade records.
|
||||
|
||||
```bash
|
||||
npx gmgn-cli portfolio kol [--limit <n>] [--raw]
|
||||
gmgn-cli track kol [--chain <chain>] [--limit <n>] [--side <side>] [--raw]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `--chain` | No | `sol` / `bsc` / `base` (default `sol`) |
|
||||
| `--limit` | No | Page size (1–200, default 100) |
|
||||
| `--side` | No | Filter by trade direction: `buy` / `sell` (client-side filter) |
|
||||
|
||||
---
|
||||
|
||||
## portfolio smartmoney
|
||||
|
||||
Query Smart Money trade records (SOL chain).
|
||||
Query Smart Money trade records.
|
||||
|
||||
```bash
|
||||
npx gmgn-cli portfolio smartmoney [--limit <n>] [--raw]
|
||||
gmgn-cli track smartmoney [--chain <chain>] [--limit <n>] [--side <side>] [--raw]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `--chain` | No | `sol` / `bsc` / `base` (default `sol`) |
|
||||
| `--limit` | No | Page size (1–200, default 100) |
|
||||
| `--side` | No | Filter by trade direction: `buy` / `sell` (client-side filter) |
|
||||
|
||||
---
|
||||
|
||||
## order quote
|
||||
|
||||
Get a swap quote without submitting a transaction. Uses normal auth — no private key required.
|
||||
Get a swap quote without submitting a transaction. All supported quote chains use critical auth and require `GMGN_PRIVATE_KEY`.
|
||||
|
||||
```bash
|
||||
npx gmgn-cli order quote \
|
||||
@@ -359,7 +426,7 @@ npx gmgn-cli order quote \
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` |
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` (all require `GMGN_PRIVATE_KEY` for quote) |
|
||||
| `--from` | Yes | Wallet address (must match API Key binding) |
|
||||
| `--input-token` | Yes | Input token contract address |
|
||||
| `--output-token` | Yes | Output token contract address |
|
||||
@@ -400,6 +467,8 @@ npx gmgn-cli swap \
|
||||
[--gas-price <gwei>] \
|
||||
[--max-fee-per-gas <amount>] \
|
||||
[--max-priority-fee-per-gas <amount>] \
|
||||
[--condition-orders <json>] \
|
||||
[--sell-ratio-type <buy_amount|hold_amount>] \
|
||||
[--raw]
|
||||
```
|
||||
|
||||
@@ -421,6 +490,16 @@ npx gmgn-cli swap \
|
||||
| `--gas-price` | No | Gas price in gwei (BSC ≥ 0.05 gwei / BASE/ETH ≥ 0.01 gwei) |
|
||||
| `--max-fee-per-gas` | No | EIP-1559 max fee per gas (Base/ETH only) |
|
||||
| `--max-priority-fee-per-gas` | No | EIP-1559 max priority fee per gas (Base/ETH only) |
|
||||
| `--condition-orders` | No | JSON array of take-profit/stop-loss conditions attached after a successful swap (see example below); only `profit_stop` and `loss_stop` are supported |
|
||||
| `--sell-ratio-type` | No | Sell ratio base for `--condition-orders`: `buy_amount` (default) / `hold_amount` |
|
||||
|
||||
**`--condition-orders` example** (100% sell at 2× price, 100% sell at 50% price):
|
||||
|
||||
```json
|
||||
[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"100"},{"order_type":"loss_stop","side":"sell","price_scale":"50","sell_ratio":"100"}]
|
||||
```
|
||||
|
||||
> Strategy creation is **best-effort**: if the swap succeeds but strategy creation fails, the swap result is still returned (with `strategy_order_id` absent). Only `order_type`, `side`, `price_scale`, and `sell_ratio` are accepted per condition — extra fields cause a 400 error.
|
||||
|
||||
**Response fields (data):**
|
||||
|
||||
@@ -439,6 +518,70 @@ npx gmgn-cli swap \
|
||||
| `output_token` | string | Output token contract address |
|
||||
| `filled_input_amount` | string | Actual input consumed (smallest unit); empty if not filled |
|
||||
| `filled_output_amount` | string | Actual output received (smallest unit); empty if not filled |
|
||||
| `strategy_order_id` | string | Strategy order ID; only present when `--condition-orders` was passed and strategy creation succeeded |
|
||||
|
||||
---
|
||||
|
||||
## multi-swap
|
||||
|
||||
Submit token swaps across multiple wallets concurrently. Each wallet executes independently. Up to 100 wallets per request, all must be bound to the API Key. **Requires `GMGN_PRIVATE_KEY` configured in `.env`.**
|
||||
|
||||
```bash
|
||||
gmgn-cli multi-swap \
|
||||
--chain <chain> \
|
||||
--accounts <addr1>,<addr2> \
|
||||
--input-token <input_token_address> \
|
||||
--output-token <output_token_address> \
|
||||
[--input-amount <json>] \
|
||||
[--input-amount-bps <json>] \
|
||||
[--output-amount <json>] \
|
||||
[--slippage <n>] \
|
||||
[--auto-slippage] \
|
||||
[--anti-mev] \
|
||||
[--priority-fee <sol>] \
|
||||
[--tip-fee <amount>] \
|
||||
[--auto-tip-fee] \
|
||||
[--max-auto-fee <amount>] \
|
||||
[--gas-price <gwei>] \
|
||||
[--max-fee-per-gas <amount>] \
|
||||
[--max-priority-fee-per-gas <amount>] \
|
||||
[--condition-orders <json>] \
|
||||
[--sell-ratio-type <buy_amount|hold_amount>] \
|
||||
[--raw]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` |
|
||||
| `--accounts` | Yes | Comma-separated wallet addresses (1–100, all bound to API Key) |
|
||||
| `--input-token` | Yes | Input token contract address |
|
||||
| `--output-token` | Yes | Output token contract address |
|
||||
| `--input-amount` | No* | JSON map `{"addr":"amount"}` in smallest unit; one of the three amount fields is required |
|
||||
| `--input-amount-bps` | No* | JSON map `{"addr":"bps"}` where 5000 = 50%; only valid when input token is not a currency |
|
||||
| `--output-amount` | No* | JSON map `{"addr":"amount"}` target output in smallest unit |
|
||||
| `--slippage` | No | Slippage tolerance, e.g. `0.01` = 1% |
|
||||
| `--auto-slippage` | No | Enable automatic slippage |
|
||||
| `--anti-mev` | No | Enable anti-MEV protection |
|
||||
| `--priority-fee` | No | Priority fee in SOL (≥ 0.00001, SOL only) |
|
||||
| `--tip-fee` | No | Tip fee (SOL ≥ 0.00001 / BSC ≥ 0.000001 BNB) |
|
||||
| `--auto-tip-fee` | No | Enable automatic tip fee |
|
||||
| `--max-auto-fee` | No | Max automatic fee cap |
|
||||
| `--gas-price` | No | Gas price in gwei (BSC ≥ 0.05 / BASE/ETH ≥ 0.01) |
|
||||
| `--max-fee-per-gas` | No | EIP-1559 max fee per gas (Base only) |
|
||||
| `--max-priority-fee-per-gas` | No | EIP-1559 max priority fee per gas (Base only) |
|
||||
| `--condition-orders` | No | JSON array of take-profit/stop-loss conditions, attached to each successful wallet's swap (best-effort) |
|
||||
| `--sell-ratio-type` | No | Sell ratio base: `buy_amount` (default) / `hold_amount` |
|
||||
|
||||
**Response fields (data):** Array of per-wallet results:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `account` | string | Wallet address |
|
||||
| `success` | bool | Whether this wallet's swap succeeded |
|
||||
| `error` | string | Error message on failure |
|
||||
| `error_code` | string | Error code on failure |
|
||||
| `result` | object | OrderResponse on success (same fields as `swap` response) |
|
||||
| `result.strategy_order_id` | string | Strategy order ID; only present when `--condition-orders` passed and strategy creation succeeded |
|
||||
|
||||
---
|
||||
|
||||
@@ -457,6 +600,197 @@ npx gmgn-cli order get --chain <chain> --order-id <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 <chain> \
|
||||
--from <wallet_address> \
|
||||
--base-token <base_token_address> \
|
||||
--quote-token <quote_token_address> \
|
||||
--order-type <limit_order> \
|
||||
--sub-order-type <buy_low|buy_high|stop_loss|take_profit> \
|
||||
--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 <gwei>] \
|
||||
[--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 |
|
||||
| `--order-type` | Yes | Order type: `limit_order` |
|
||||
| `--sub-order-type` | Yes | Sub-order type: `buy_low` / `buy_high` / `stop_loss` / `take_profit` |
|
||||
| `--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 (**required for SOL chain**) |
|
||||
| `--tip-fee` | No | Tip fee (**required for SOL chain**) |
|
||||
| `--gas-price` | No | Gas price in gwei (**required for BSC**; ≥ 0.05 / BASE/ETH ≥ 0.01) |
|
||||
| `--anti-mev` | No | Enable anti-MEV protection |
|
||||
|
||||
> **Chain-specific fee requirements:**
|
||||
> - **SOL:** `--priority-fee` and `--tip-fee` are both **required** (returns 400 if missing)
|
||||
> - **BSC:** `--gas-price` is **required** (returns 400 if missing)
|
||||
> - **ETH/BASE:** no required fee fields
|
||||
|
||||
**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. **Requires `GMGN_PRIVATE_KEY` configured in `.env`.**
|
||||
|
||||
```bash
|
||||
gmgn-cli order strategy list --chain <chain> [--type <open|history>] [--from <address>] [--group-tag <tag>] [--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 |
|
||||
| `--group-tag` | No | Filter by group: `LimitOrder` / `STMix` |
|
||||
| `--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> [--order-type <type>] [--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 |
|
||||
| `--order-type` | No | Order type: `limit_order` / `smart_trade` |
|
||||
| `--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
|
||||
|
||||
All business routes are protected by GMGN's leaky-bucket limiter. Current production behavior is:
|
||||
|
||||
- `rate=10`, `capacity=10`
|
||||
- every limited `429` response includes `X-RateLimit-Reset`
|
||||
- `X-RateLimit-Reset` is a Unix timestamp in seconds, representing when the current cooldown is expected to end
|
||||
|
||||
CLI behavior:
|
||||
|
||||
- For read-only commands, `gmgn-cli` may wait until `X-RateLimit-Reset` and retry once automatically when the remaining cooldown is short.
|
||||
- For longer cooldowns, or for `swap`, the CLI stops and prints the exact reset time instead of repeatedly sending requests.
|
||||
- The auto-retry threshold defaults to `5000ms` and can be overridden with `GMGN_RATE_LIMIT_AUTO_RETRY_MAX_WAIT_MS=<milliseconds>`.
|
||||
|
||||
Important notes:
|
||||
|
||||
- `RATE_LIMIT_EXCEEDED` and `RATE_LIMIT_BANNED` are request-frequency limits. Continuing to send requests during the cooldown can extend the ban by 5 seconds each time, up to 5 minutes.
|
||||
- `ERROR_RATE_LIMIT_BLOCKED` is an error-count block on `POST /v1/trade/swap`. It is triggered by repeatedly hitting the same business error and should be treated as "fix the request first, then retry after reset".
|
||||
|
||||
---
|
||||
|
||||
## Error Codes
|
||||
@@ -471,9 +805,12 @@ npx gmgn-cli order get --chain <chain> --order-id <order_id> [--raw]
|
||||
| `AUTH_CLIENT_ID_REPLAYED` | 401 | client_id replayed within 7s |
|
||||
| `AUTH_REPLAY_CHECK_UNAVAILABLE` | 503 | Anti-replay Redis unavailable (critical auth only) |
|
||||
| `RATE_LIMIT_EXCEEDED` | 429 | Rate limit exceeded |
|
||||
| `RATE_LIMIT_BANNED` | 429 | Temporarily banned due to repeated rate limit violations |
|
||||
| `ERROR_RATE_LIMIT_BLOCKED` | 429 | Temporarily blocked after repeated business errors on `swap` |
|
||||
| `TRADE_WALLET_MISMATCH` | 403 | `--from` address does not match the wallet bound to the API Key |
|
||||
| `CHAIN_NOT_SUPPORTED` | 400 | Unsupported chain |
|
||||
| `BAD_REQUEST` | 400 | Missing or invalid request parameters |
|
||||
| `INTERNAL_API_UNAVAILABLE` | 502 | Downstream market API unavailable |
|
||||
| `BROKER_UNAVAILABLE` | 502 | Downstream trade broker unavailable |
|
||||
| `TRADING_BOT_UNAVAILABLE` | 502 | Trading bot service unreachable (strategy endpoints) |
|
||||
| `INTERNAL_ERROR` | 500 | Internal server error |
|
||||
|
||||
@@ -31,10 +31,34 @@ gmgn-cli market trenches --chain <chain> --type completed
|
||||
|
||||
From the results, note each token's `address`, `symbol`, `smart_degen_count`, `renowned_count`, `volume`, `swaps`, and `rug_ratio`.
|
||||
|
||||
**Tip — use filter flags to pre-screen at fetch time:**
|
||||
|
||||
```bash
|
||||
# Fetch with safe baseline filter (server-side)
|
||||
gmgn-cli market trenches --chain <chain> \
|
||||
--type new_creation --type near_completion \
|
||||
--filter-preset safe --sort-by smart_degen_count
|
||||
|
||||
# Strict: safe + require smart money + min 24h volume $1k
|
||||
gmgn-cli market trenches --chain <chain> \
|
||||
--type new_creation --type near_completion \
|
||||
--filter-preset strict --sort-by smart_degen_count
|
||||
|
||||
# Custom: manual range filters (all sent server-side)
|
||||
gmgn-cli market trenches --chain <chain> \
|
||||
--type new_creation \
|
||||
--max-rug-ratio 0.3 --max-bundler-rate 0.3 --max-insider-ratio 0.3 \
|
||||
--min-smart-degen-count 1 --min-volume-24h 1000
|
||||
```
|
||||
|
||||
Using `--filter-preset safe` (or `strict`) tells the server to pre-filter results before returning — equivalent to Steps 2's "Discard immediately" criteria, applied before the response is sent.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — First-Pass Filter (In-Response Scan)
|
||||
|
||||
> **If you used `--filter-preset safe` or `--filter-preset strict` in Step 1, the rug_ratio, bundler_rate, and insider_ratio checks below are already applied server-side.** Verify the remaining signals manually.
|
||||
|
||||
Before running any CLI commands per token, apply a quick in-response filter on the trenches results:
|
||||
|
||||
**Discard immediately if:**
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "gmgn-cli",
|
||||
"version": "1.1.6",
|
||||
"version": "1.2.7",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gmgn-cli",
|
||||
"version": "1.1.6",
|
||||
"version": "1.2.7",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^12.1.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gmgn-cli",
|
||||
"version": "1.1.6",
|
||||
"version": "1.2.7",
|
||||
"description": "GMGN OpenAPI CLI — call GMGN market, token, portfolio and swap APIs from the command line",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
---
|
||||
name: gmgn-cooking
|
||||
description: "[FINANCIAL EXECUTION] Create and launch meme coins and crypto tokens on launchpads (Pump.fun, PancakeSwap, FourMeme, Bonk, BAGS, Flap, Raydium, etc.) via bonding curve fair launch, or query token creation stats by launchpad via GMGN API. Requires explicit user confirmation. Use when user asks to create a token, launch a meme coin, cook a coin, deploy on a launchpad, or check launchpad creation stats on Solana, BSC, Base, ETH, or TON."
|
||||
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 — all token creation operations must go through the CLI. The CLI handles signing and submission automatically.**
|
||||
|
||||
**IMPORTANT: Do NOT guess field names or values. When a field's meaning is unclear, look it up in the Response Fields sections below before using it.**
|
||||
|
||||
**⚠️ IPv6 NOT SUPPORTED: If you get a `401` or `403` error and credentials look correct, check for IPv6 immediately: (1) list all network interfaces and their IPv6 addresses — run `ifconfig | grep inet6` (macOS) or `ip addr show | grep inet6` (Linux); (2) send a test request to `https://ipv6.icanhazip.com` — if the response is an IPv6 address, outbound traffic is going via IPv6. Tell the user immediately: "Please disable IPv6 on your network interface — gmgn-cli commands only work over IPv4."**
|
||||
|
||||
Use the `gmgn-cli` tool to create a token on a launchpad platform or query token creation statistics per launchpad. **Requires private key** (`GMGN_PRIVATE_KEY` in `.env`) for `cooking create`.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
- **Bonding curve** — Most launchpad platforms (Pump.fun, FourMeme, Flap, etc.) launch tokens on an internal bonding curve. The token price rises as buyers enter. Once the threshold is reached, the token "graduates" to an open DEX (e.g. Raydium on SOL, PancakeSwap on BSC). Token creation happens on the bonding curve — not the open market.
|
||||
|
||||
- **`--buy-amt` is in human units** — `--buy-amt` is expressed in full native token units, not smallest unit. `0.01` = 0.01 SOL. `0.05` = 0.05 BNB. Always confirm the human-readable amount with the user before executing.
|
||||
|
||||
- **`--dex` identifiers** — Each launchpad has a fixed identifier passed to `--dex`. These are not free-form names — use only the identifiers listed in the Supported Launchpads table. Never guess a `--dex` value not in that table.
|
||||
|
||||
- **Image input** — Token logo can be provided as base64-encoded data (`--image`, max 2MB decoded) or a publicly accessible URL (`--image-url`). Provide one or the other — not both. If the user gives a file path, read and base64-encode it before passing to `--image`. If they give a URL, use `--image-url` directly.
|
||||
|
||||
- **Status polling via `order get`** — `cooking create` is asynchronous. The immediate response may show `pending`. Poll with `gmgn-cli order get --chain <chain> --order-id <order_id>` until `confirmed`. The new token's contract address is in the `output_token` field of the `order get` response, not in the initial create response.
|
||||
|
||||
- **Critical auth** — `cooking create` requires both `GMGN_API_KEY` and `GMGN_PRIVATE_KEY`. The private key never leaves the machine — the CLI uses it only for local signing. `cooking stats` uses normal auth (API Key only).
|
||||
|
||||
- **Slippage** — The initial buy is executed as part of the same transaction as token creation. Slippage applies to that buy. Use `--slippage` (decimal, e.g. `0.01` = 1%) or `--auto-slippage`. One of the two is required when `--buy-amt` is set.
|
||||
|
||||
## Financial Risk Notice
|
||||
|
||||
**This skill executes REAL, IRREVERSIBLE blockchain transactions.**
|
||||
|
||||
- Every `cooking create` command deploys an on-chain token contract and spends real funds (initial buy amount).
|
||||
- Token deployments cannot be undone once confirmed on-chain.
|
||||
- The AI agent must **never auto-execute a create** — explicit user confirmation is required every time, without exception.
|
||||
- Only use this skill with funds you are willing to spend. Initial buy amounts are non-refundable.
|
||||
|
||||
## Sub-commands
|
||||
|
||||
| Sub-command | Description |
|
||||
|-------------|-------------|
|
||||
| `cooking stats` | Get token creation count statistics grouped by launchpad platform (normal auth) |
|
||||
| `cooking create` | Deploy a new token on a launchpad platform (requires private key) |
|
||||
|
||||
## Supported Chains
|
||||
|
||||
`sol` / `bsc` / `base` / `eth` / `ton`
|
||||
|
||||
## Supported Launchpads by Chain
|
||||
|
||||
| Chain | `--dex` values |
|
||||
|-------|----------------|
|
||||
| `sol` | `pump` / `raydium` / `bonk` / `bags` / `memoo` / `letsbonk` / `bonkers` |
|
||||
| `bsc` | `pancakeswap` / `flap` / `fourmeme` |
|
||||
| `base` | `clanker` / `flaunch` / `baseapp` / `basememe` / `zora` / `virtuals_v2` |
|
||||
|
||||
When the user names a platform colloquially (e.g. "pump.fun", "four.meme", "PancakeSwap"), map it to the correct `--dex` identifier from this table before running the command.
|
||||
|
||||
## 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`
|
||||
|
||||
**IMPORTANT — Credential lookup order:** `gmgn-cli` loads `~/.config/gmgn/.env` first, then overlays any `.env` found in the **current working directory** (project-level overrides global). If credentials appear missing or wrong, check whether a `.env` in the workspace directory is shadowing the global config:
|
||||
```bash
|
||||
ls -la .env 2>/dev/null && echo "WARNING: local .env is overriding ~/.config/gmgn/.env"
|
||||
```
|
||||
If a local `.env` exists but lacks `GMGN_API_KEY` / `GMGN_PRIVATE_KEY`, either add them to that file or remove it so the global config is used.
|
||||
|
||||
## Rate Limit Handling
|
||||
|
||||
All cooking routes go through GMGN's leaky-bucket limiter with `rate=10` and `capacity=10`. Sustained throughput is roughly `10 ÷ weight` requests/second.
|
||||
|
||||
| Command | Weight |
|
||||
|---------|--------|
|
||||
| `cooking create` | 5 |
|
||||
| `cooking stats` | 1 |
|
||||
|
||||
When a request returns `429`:
|
||||
|
||||
- Read `X-RateLimit-Reset` from the response headers — Unix timestamp for when the limit resets.
|
||||
- If the response body contains `reset_at` (e.g., `{"code":429,"error":"RATE_LIMIT_BANNED","message":"...","reset_at":1775184222}`), extract `reset_at` — it is the Unix timestamp when the ban lifts (typically 5 minutes). Convert to local time and tell the user exactly when they can retry.
|
||||
- `cooking create` is a real transaction: **never loop or auto-resubmit** after a `429`. Wait until the reset time, then ask for confirmation again before retrying.
|
||||
- For `RATE_LIMIT_EXCEEDED` or `RATE_LIMIT_BANNED`, repeated requests during cooldown extend the ban by 5 seconds each time, up to 5 minutes.
|
||||
|
||||
**First-time setup** (if credentials are not configured):
|
||||
|
||||
1. Generate key pair and show the public key to the user:
|
||||
```bash
|
||||
openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
openssl pkey -in /tmp/gmgn_private.pem -pubout 2>/dev/null
|
||||
```
|
||||
Tell the user: *"This is your Ed25519 public key. Go to **https://gmgn.ai/ai**, paste it into the API key creation form (enable swap/cooking capability), then send me the API Key value shown on the page."*
|
||||
|
||||
2. Wait for the user's API key, then configure both credentials:
|
||||
```bash
|
||||
mkdir -p ~/.config/gmgn
|
||||
echo 'GMGN_API_KEY=<key_from_user>' > ~/.config/gmgn/.env
|
||||
echo 'GMGN_PRIVATE_KEY="<pem_content_from_step_1>"' >> ~/.config/gmgn/.env
|
||||
chmod 600 ~/.config/gmgn/.env
|
||||
```
|
||||
|
||||
### Credential Model
|
||||
|
||||
- `GMGN_PRIVATE_KEY` is used exclusively for **local message signing** — the private key never leaves the machine. The CLI computes an Ed25519 signature in-process and transmits only the base64-encoded result in the `X-Signature` request header.
|
||||
- `GMGN_API_KEY` is transmitted in the `X-APIKEY` header over HTTPS.
|
||||
- Neither credential is ever passed as a command-line argument.
|
||||
|
||||
## `cooking stats` Usage
|
||||
|
||||
```bash
|
||||
gmgn-cli cooking stats [--raw]
|
||||
```
|
||||
|
||||
### `cooking stats` Response Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `launchpad` | string | Launchpad identifier (e.g. `pump`, `raydium`, `pancakeswap`) |
|
||||
| `token_count` | int | Number of tokens created via GMGN on that launchpad |
|
||||
|
||||
## `cooking create` Parameters
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `--chain` | Yes | Chain: `sol` / `bsc` / `base` / `eth` / `ton` |
|
||||
| `--dex` | Yes | Launchpad platform identifier — see Supported Launchpads table. Never guess this value. |
|
||||
| `--from` | Yes | Wallet address (must match API Key binding) |
|
||||
| `--name` | Yes | Token full name (e.g. `Doge Killer`) |
|
||||
| `--symbol` | Yes | Token ticker symbol (e.g. `DOGEK`) |
|
||||
| `--description` | No | Token description / project pitch |
|
||||
| `--buy-amt` | Yes | Initial buy amount in **human-readable native token units** (e.g. `0.01` = 0.01 SOL). This is NOT in smallest unit. |
|
||||
| `--image` | No* | Token logo as **base64-encoded** data (max 2MB decoded). Mutually exclusive with `--image-url`. One of the two is required. |
|
||||
| `--image-url` | No* | Token logo as a publicly accessible URL. Mutually exclusive with `--image`. One of the two is required. |
|
||||
| `--slippage` | No* | Slippage tolerance, e.g. `0.01` = 1%. **Mutually exclusive with `--auto-slippage`** — provide one or the other. |
|
||||
| `--auto-slippage` | No* | Enable automatic slippage. **Mutually exclusive with `--slippage`.** |
|
||||
| `--website` | No | Project website URL |
|
||||
| `--twitter` | No | Twitter / X URL |
|
||||
| `--telegram` | No | Telegram group URL |
|
||||
| `--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 |
|
||||
|
||||
\* `--image` or `--image-url`: provide exactly one. `--slippage` or `--auto-slippage`: provide exactly one.
|
||||
|
||||
## `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 — pass to `gmgn-cli order get` to poll for final status |
|
||||
| `error_code` | string | Error code on failure |
|
||||
| `error_status` | string | Error description on failure |
|
||||
|
||||
## Status Polling
|
||||
|
||||
Token creation is **asynchronous**. If the initial `cooking create` response shows `status: pending`:
|
||||
|
||||
1. Poll with `gmgn-cli order get` every **2 seconds**, up to **30 seconds**:
|
||||
```bash
|
||||
gmgn-cli order get --chain <chain> --order-id <order_id>
|
||||
```
|
||||
2. The new token's contract / mint address is in the **`report.output_token`** field of the `order get` response (only present when `state = 30` and `status = "successful"`) — it is NOT returned by `cooking create` directly.
|
||||
3. Stop polling once `status` is `confirmed`, `failed`, or `expired`.
|
||||
4. On `confirmed`: display `output_token` as the token address and include the block explorer link.
|
||||
5. On `failed` / `expired`: report the `error_status` and do not retry automatically.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Get token creation statistics per launchpad
|
||||
gmgn-cli cooking stats
|
||||
|
||||
# Create a token on Pump.fun (SOL) — with URL image
|
||||
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) — with URL image and social links
|
||||
gmgn-cli cooking create \
|
||||
--chain bsc \
|
||||
--dex pancakeswap \
|
||||
--from <wallet_address> \
|
||||
--name "BSC Token" \
|
||||
--symbol BSCT \
|
||||
--buy-amt 0.05 \
|
||||
--image-url https://example.com/logo.png \
|
||||
--slippage 0.02 \
|
||||
--gas-price 5000000000 \
|
||||
--website https://mytoken.io \
|
||||
--twitter https://twitter.com/mytoken
|
||||
|
||||
# Create a token on FourMeme (BSC) — using base64 image from local file
|
||||
gmgn-cli cooking create \
|
||||
--chain bsc \
|
||||
--dex fourmeme \
|
||||
--from <wallet_address> \
|
||||
--name "Four Token" \
|
||||
--symbol FOUR \
|
||||
--buy-amt 0.05 \
|
||||
--image "$(base64 -i /path/to/logo.png)" \
|
||||
--auto-slippage
|
||||
|
||||
# Create a token on letsbonk (SOL)
|
||||
gmgn-cli cooking create \
|
||||
--chain sol \
|
||||
--dex letsbonk \
|
||||
--from <wallet_address> \
|
||||
--name "Bonk Token" \
|
||||
--symbol BNKT \
|
||||
--buy-amt 0.01 \
|
||||
--image-url https://example.com/logo.png \
|
||||
--auto-slippage \
|
||||
--anti-mev
|
||||
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
### Pre-create Confirmation
|
||||
|
||||
Before every `cooking create`, present this summary and wait for explicit user confirmation:
|
||||
|
||||
```
|
||||
⚠️ Token Creation Confirmation Required
|
||||
|
||||
Chain: {chain}
|
||||
Platform: {--dex} (e.g. pump / fourmeme)
|
||||
Wallet: {--from}
|
||||
Token Name: {--name}
|
||||
Symbol: {--symbol}
|
||||
Initial Buy: {--buy-amt} {native currency} (e.g. 0.01 SOL)
|
||||
Slippage: {--slippage}% (or "auto")
|
||||
Image: {--image-url or "base64 provided"}
|
||||
Social: {twitter / telegram / website if provided}
|
||||
|
||||
Reply "confirm" to deploy this token. This action is IRREVERSIBLE.
|
||||
```
|
||||
|
||||
### Post-create Receipt
|
||||
|
||||
After polling confirms a successful deployment:
|
||||
|
||||
```
|
||||
✅ Token Created
|
||||
|
||||
Token: {--name} ({--symbol})
|
||||
Address: {output_token from order get}
|
||||
Chain: {chain}
|
||||
Platform: {--dex}
|
||||
Tx: {explorer link for hash}
|
||||
Order ID: {order_id}
|
||||
```
|
||||
|
||||
Block explorer links:
|
||||
|
||||
| Chain | Explorer |
|
||||
|-------|----------|
|
||||
| sol | `https://solscan.io/tx/<hash>` |
|
||||
| bsc | `https://bscscan.com/tx/<hash>` |
|
||||
| base | `https://basescan.org/tx/<hash>` |
|
||||
| eth | `https://etherscan.io/tx/<hash>` |
|
||||
|
||||
## Guided Launch Flow
|
||||
|
||||
When a user says they want to launch / create / deploy a token but has not provided all required information, collect information **one required field at a time** — never bundle multiple required fields into a single question. The user should be able to reply with a single value, not a labeled list.
|
||||
|
||||
Ask each required field as a short, direct question. Wait for the answer before moving to the next. Optional fields are grouped into one question after all required fields are collected.
|
||||
|
||||
### Step 1 — Chain & Platform
|
||||
|
||||
Ask: *"Which chain and platform?"*
|
||||
|
||||
Show the options concisely:
|
||||
|
||||
| Chain | Platform | `--dex` |
|
||||
|-------|----------|---------|
|
||||
| Solana | Pump.fun | `pump` |
|
||||
| Solana | letsbonk | `letsbonk` |
|
||||
| Solana | Raydium | `raydium` |
|
||||
| Solana | BAGS | `bags` |
|
||||
| Solana | Memoo | `memoo` |
|
||||
| Solana | Bonkers | `bonkers` |
|
||||
| BSC | FourMeme | `fourmeme` |
|
||||
| BSC | PancakeSwap | `pancakeswap` |
|
||||
| BSC | Flap | `flap` |
|
||||
| Base | Clanker | `clanker` |
|
||||
| Base | Zora | `zora` |
|
||||
| Base | Flaunch | `flaunch` |
|
||||
| Base | Virtuals | `virtuals_v2` |
|
||||
|
||||
If the user is unsure, recommend: **Pump.fun (SOL)** or **FourMeme (BSC)**.
|
||||
|
||||
### Step 2 — Token Name
|
||||
|
||||
Ask: *"Token name?"*
|
||||
|
||||
Wait for the user's reply (e.g. `Doge Killer`).
|
||||
|
||||
### Step 3 — Token Symbol
|
||||
|
||||
Ask: *"Ticker symbol?"*
|
||||
|
||||
Wait for the user's reply (e.g. `DOGEK`). Typically 3–8 uppercase characters.
|
||||
|
||||
### Step 4 — Logo
|
||||
|
||||
Ask: *"Logo image? (file path or URL — skip to launch without one)"*
|
||||
|
||||
- **File path** → silently run `base64 -i <path>` and pass the result to `--image`. Do not mention "base64" to the user.
|
||||
- **URL** → use `--image-url` directly.
|
||||
- **Skip / none** → proceed without a logo. Note that most platforms accept this, but it reduces visibility.
|
||||
|
||||
### Step 5 — Initial Buy Amount
|
||||
|
||||
Ask: *"How much {SOL / BNB / ETH} for the initial buy?"*
|
||||
|
||||
Pass the user's answer directly to `--buy-amt` — already in full token units (e.g. `0.01` = 0.01 SOL). Do NOT convert to lamports or wei.
|
||||
|
||||
### Step 6 — Optional Details (single question)
|
||||
|
||||
Ask all optional fields together in one message:
|
||||
|
||||
*"Any optional extras? (skip any you don't need)"*
|
||||
- *Description* — one-line pitch shown on the launchpad
|
||||
- *Twitter* — Twitter / X URL
|
||||
- *Telegram* — Telegram group URL
|
||||
- *Website* — project website URL
|
||||
|
||||
The user can reply with just the ones they have, or say "skip" / "none" to proceed.
|
||||
|
||||
### Step 7 — Confirmation & Execute
|
||||
|
||||
Once all information is collected, present the pre-create confirmation summary (see Output Format section) and wait for the user to reply "confirm" before executing.
|
||||
|
||||
---
|
||||
|
||||
## Execution Guidelines
|
||||
|
||||
- **[REQUIRED] Pre-create confirmation** — Before executing `cooking create`, present the full summary above and receive explicit "confirm" from the user. No exceptions. Do NOT auto-create.
|
||||
- **[REQUIRED] `--dex` validation** — Before running, look up the user's named platform in the Supported Launchpads table and resolve to the correct `--dex` identifier. Never guess or pass a freeform platform name. If the chain/platform combination is not in the table, tell the user it is unsupported.
|
||||
- **Slippage requirement** — Either `--slippage` or `--auto-slippage` must be provided. If the user did not specify, suggest `--auto-slippage` for volatile new tokens or ask for a preference.
|
||||
- **Image handling** — If the user provides a file path, run `base64 -i <path>` and pass the result to `--image`. If they provide a URL, use `--image-url`. If neither is provided, ask before building the confirmation — most platforms require a logo.
|
||||
- **Address validation** — Validate `--from` wallet address format before submitting:
|
||||
- `sol`: base58, 32–44 characters
|
||||
- `bsc` / `base` / `eth`: `0x` + 40 hex digits
|
||||
- **Chain-wallet compatibility** — SOL addresses are incompatible with EVM chains and vice versa. Warn the user and abort if the address format does not match the chain.
|
||||
- **Order polling** — After `cooking create`, if `status` is `pending`, poll `order get` every 2 seconds up to 30 seconds. The token address is in `output_token`. Do not report success until `status` is `confirmed`.
|
||||
- **Credential sensitivity** — `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` can execute real transactions. Never log, display, or expose these values.
|
||||
|
||||
## Notes
|
||||
|
||||
- `cooking create` uses **critical auth** (API Key + signature) — CLI handles signing automatically.
|
||||
- `cooking stats` uses normal auth (API Key only — no private key needed).
|
||||
- The new token's mint address is in `output_token` from `gmgn-cli order get`, not in the initial `cooking create` response.
|
||||
- Use `--raw` on any command to get single-line JSON for further processing.
|
||||
|
||||
## References
|
||||
|
||||
| Skill | Description |
|
||||
|-------|-------------|
|
||||
| [gmgn-swap](https://github.com/GMGNAI/gmgn-skills/tree/main/skills/gmgn-swap) | Contains `order get` command used for polling token creation status |
|
||||
| [gmgn-token](https://github.com/GMGNAI/gmgn-skills/tree/main/skills/gmgn-token) | Token security check, info, holders, and traders — useful after launch to monitor your token |
|
||||
| [gmgn-market](https://github.com/GMGNAI/gmgn-skills/tree/main/skills/gmgn-market) | `market trenches` for tracking bonding curve progress; `market trending` to see if your token is gaining traction |
|
||||
| [gmgn-track](https://github.com/GMGNAI/gmgn-skills/tree/main/skills/gmgn-track) | Smart money and KOL trade tracking — monitor whether smart wallets are buying your token after launch |
|
||||
| [gmgn-portfolio](https://github.com/GMGNAI/gmgn-skills/tree/main/skills/gmgn-portfolio) | Wallet holdings and P&L — check your own wallet balance before deciding on `--buy-amt` |
|
||||
+304
-11
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: gmgn-market
|
||||
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 <sol|bsc|base> --address <token_address> --resolution <1m|5m|15m|1h|4h|1d> [--from <unix_ts>] [--to <unix_ts>] | trending --chain <sol|bsc|base> --interval <1m|5m|1h|6h|24h> | trenches --chain <sol|bsc|base>"
|
||||
description: Get crypto and meme token price charts (K-line, candlestick, OHLCV), trending meme coin rankings by volume, and newly launched tokens on launchpads (pump.fun, fourmeme, letsbonk, Raydium, etc.) via GMGN API on Solana, BSC, Base, or Ethereum. Use when user asks for price chart, trending tokens, what's pumping, hot coins, new launches, token signals, or wants to discover early-stage opportunities.
|
||||
argument-hint: "kline --chain <sol|bsc|base|eth> --address <token_address> --resolution <1m|5m|15m|1h|4h|1d> [--from <unix_ts>] [--to <unix_ts>] | trending --chain <sol|bsc|base|eth> --interval <1m|5m|1h|6h|24h> | trenches --chain <sol|bsc|base> | signal --chain <sol|bsc>"
|
||||
metadata:
|
||||
cliHelp: "gmgn-cli market --help"
|
||||
---
|
||||
@@ -18,7 +18,7 @@ Use the `gmgn-cli` tool to query K-line data for a token, browse trending tokens
|
||||
|
||||
- **`--filter` chain defaults** — SOL and EVM chains have different default safety filters that are applied automatically when `--filter` is omitted. Do not assume the same defaults apply across chains:
|
||||
- **SOL**: defaults to `renounced frozen` (mint and freeze authority renounced)
|
||||
- **BSC / Base (EVM)**: defaults to `not_honeypot verified renounced`
|
||||
- **BSC / Base / ETH (EVM)**: defaults to `not_honeypot verified renounced`
|
||||
- Omitting `--filter` is NOT the same as "no filter" — the chain defaults are always applied. To use a custom filter set, explicitly specify all desired filter tags.
|
||||
|
||||
- **`volume` vs `amount` (kline)** — Naming is counterintuitive. `volume` = USD dollar value of trades; `amount` = token units traded. For a token priced at $0.0002, these differ by 5,000×. Always use `volume` for "how much USD was traded" and `amount` for "how many tokens changed hands."
|
||||
@@ -48,22 +48,56 @@ Use the `gmgn-cli` tool to query K-line data for a token, browse trending tokens
|
||||
| `market kline` | Token candlestick / OHLCV data and trading volume over a time range |
|
||||
| `market trending` | Trending tokens ranked by swap activity — use `--interval` to specify the time window (e.g. `1m` for 1-minute hottest, `1h` for 1-hour trending) |
|
||||
| `market trenches` | Newly launched launchpad platform tokens — **use this when the user asks for "new tokens", "just launched tokens", "latest tokens on pump.fun/letsbonk"**. Three categories: `new_creation` (just created), `near_completion` (bonding curve almost full), `completed` (graduated to open market / DEX) |
|
||||
| `market signal` | Real-time token signal feed — price spikes, smart money buys, large buys, Dex ads, CTO events, and more. Results sorted by `trigger_at` descending. **sol / bsc only. Max 50 results per group.** |
|
||||
|
||||
## Supported Chains
|
||||
|
||||
`sol` / `bsc` / `base`
|
||||
`sol` / `bsc` / `base` / `eth` (kline / trending only; trenches: `sol` / `bsc` / `base`; signal: `sol` / `bsc` only)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `.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`
|
||||
- `gmgn-cli` installed globally — if missing, run: `npm install -g gmgn-cli`
|
||||
- `GMGN_API_KEY` configured in `~/.config/gmgn/.env`
|
||||
|
||||
## Rate Limit Handling
|
||||
|
||||
All market routes used by this skill go through GMGN's leaky-bucket limiter with `rate=10` and `capacity=10`. Sustained throughput is roughly `10 ÷ weight` requests/second, and the max burst is roughly `floor(10 ÷ weight)` when the bucket is full.
|
||||
|
||||
| Command | Route | Weight |
|
||||
|---------|-------|--------|
|
||||
| `market kline` | `GET /v1/market/token_kline` | 2 |
|
||||
| `market trending` | `GET /v1/market/rank` | 1 |
|
||||
| `market trenches` | `POST /v1/trenches` | 3 |
|
||||
| `market signal` | `POST /v1/market/token_signal` | 3 |
|
||||
|
||||
When a request returns `429`:
|
||||
|
||||
- Read `X-RateLimit-Reset` from the response headers. It is a Unix timestamp in seconds that marks when the limit is expected to reset.
|
||||
- If the response body contains `reset_at` (e.g., `{"code":429,"error":"RATE_LIMIT_BANNED","message":"...","reset_at":1775184222}`), extract `reset_at` — it is the Unix timestamp when the ban lifts (typically 5 minutes). Convert to local time and tell the user exactly when they can retry.
|
||||
- The CLI may wait and retry once automatically when the remaining cooldown is short. If it still fails, stop and tell the user the exact retry time instead of sending more requests.
|
||||
- For `RATE_LIMIT_EXCEEDED` or `RATE_LIMIT_BANNED`, repeated requests during the cooldown can extend the ban by 5 seconds each time, up to 5 minutes. Do not spam retries.
|
||||
|
||||
**First-time setup** (if `GMGN_API_KEY` is not configured):
|
||||
|
||||
1. Generate key pair and show the public key to the user:
|
||||
```bash
|
||||
openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
openssl pkey -in /tmp/gmgn_private.pem -pubout 2>/dev/null
|
||||
```
|
||||
Tell the user: *"This is your Ed25519 public key. Go to **https://gmgn.ai/ai**, paste it into the API key creation form, then send me the API Key value shown on the page."*
|
||||
|
||||
2. Wait for the user's API key, then configure:
|
||||
```bash
|
||||
mkdir -p ~/.config/gmgn
|
||||
echo 'GMGN_API_KEY=<key_from_user>' > ~/.config/gmgn/.env
|
||||
chmod 600 ~/.config/gmgn/.env
|
||||
```
|
||||
|
||||
## `market kline` Parameters
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` |
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` / `eth` |
|
||||
| `--address` | Yes | Token contract address |
|
||||
| `--resolution` | Yes | Candlestick resolution: `1m` / `5m` / `15m` / `1h` / `4h` / `1d` |
|
||||
| `--from` | No | Start time (Unix seconds) |
|
||||
@@ -106,13 +140,13 @@ The response is an object with a `list` array. Each element in `list` is one can
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--chain` | Required. `sol` / `bsc` / `base` |
|
||||
| `--chain` | Required. `sol` / `bsc` / `base` / `eth` |
|
||||
| `--interval` | Required. `1m` / `5m` / `1h` / `6h` / `24h` (default `1h`) |
|
||||
| `--limit <n>` | Number of results (default 100, max 100) |
|
||||
| `--order-by <field>` | Sort field: `default` / `swaps` / `marketcap` / `history_highest_market_cap` / `liquidity` / `volume` / `holder_count` / `smart_degen_count` / `renowned_count` / `gas_fee` / `price` / `change1m` / `change5m` / `change1h` / `creation_timestamp` |
|
||||
| `--direction <asc\|desc>` | Sort direction (default `desc`) |
|
||||
| `--filter <tag...>` | Repeatable filter tags (chain-specific). **⚠️ SOL defaults: `renounced frozen`; BSC/Base defaults: `not_honeypot verified renounced`.** Omitting `--filter` is NOT "no filter" — chain defaults always apply. **sol** tags: `renounced` / `frozen` / `burn` / `token_burnt` / `has_social` / `not_social_dup` / `not_image_dup` / `dexscr_update_link` / `not_wash_trading` / `is_internal_market` / `is_out_market`. **evm** tags: `not_honeypot` / `verified` / `renounced` / `locked` / `token_burnt` / `has_social` / `not_social_dup` / `not_image_dup` / `dexscr_update_link` / `is_internal_market` / `is_out_market` |
|
||||
| `--platform <name...>` | Repeatable platform filter (chain-specific). **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` / `xstocks` / `ray_launchpad` / `meteora_virtual_curve` / `pool_ray` / `pool_meteora` / `pool_pump_amm` / `pool_orca`. **bsc**: `fourmeme` / `fourmeme_agent` / `bn_fourmeme` / `flap` / `clanker` / `lunafun` / `pool_uniswap` / `pool_pancake`. **base**: `clanker` / `bankr` / `flaunch` / `zora` / `zora_creator` / `baseapp` / `basememe` / `virtuals_v2` / `klik` |
|
||||
| `--filter <tag...>` | Repeatable filter tags (chain-specific). **⚠️ SOL defaults: `renounced frozen`; BSC/Base/ETH defaults: `not_honeypot verified renounced`.** Omitting `--filter` is NOT "no filter" — chain defaults always apply. **sol** tags: `renounced` / `frozen` / `burn` / `token_burnt` / `has_social` / `not_social_dup` / `not_image_dup` / `dexscr_update_link` / `not_wash_trading` / `is_internal_market` / `is_out_market`. **evm** tags: `not_honeypot` / `verified` / `renounced` / `locked` / `token_burnt` / `has_social` / `not_social_dup` / `not_image_dup` / `dexscr_update_link` / `is_internal_market` / `is_out_market` |
|
||||
| `--platform <name...>` | Repeatable platform filter (chain-specific). **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` / `xstocks` / `ray_launchpad` / `meteora_virtual_curve` / `pool_ray` / `pool_meteora` / `pool_pump_amm` / `pool_orca`. **bsc**: `fourmeme` / `fourmeme_agent` / `bn_fourmeme` / `flap` / `clanker` / `lunafun` / `pool_uniswap` / `pool_pancake`. **base**: `clanker` / `bankr` / `flaunch` / `zora` / `zora_creator` / `baseapp` / `basememe` / `virtuals_v2` / `klik`. **eth**: no platform filter (omit `--platform` for ETH) |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
@@ -142,6 +176,14 @@ gmgn-cli market kline \
|
||||
# Raw output for further processing
|
||||
gmgn-cli market kline --chain sol --address <addr> \
|
||||
--resolution 5m --from <ts> --to <ts> --raw | jq '.[]'
|
||||
|
||||
# ETH token kline — last 24h, 1h candles (macOS)
|
||||
gmgn-cli market kline \
|
||||
--chain eth \
|
||||
--address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
|
||||
--resolution 1h \
|
||||
--from $(date -v-24H +%s) \
|
||||
--to $(date +%s)
|
||||
```
|
||||
|
||||
### Trending — General
|
||||
@@ -214,6 +256,25 @@ gmgn-cli market trending \
|
||||
--order-by volume --limit 20 --raw
|
||||
```
|
||||
|
||||
### Trending — ETH (No Platform Filter)
|
||||
|
||||
```bash
|
||||
# ETH 1h trending — all tokens, sorted by volume
|
||||
gmgn-cli market trending --chain eth --interval 1h --order-by volume --limit 20
|
||||
|
||||
# ETH 1h trending — with safety filters
|
||||
gmgn-cli market trending \
|
||||
--chain eth --interval 1h \
|
||||
--filter not_honeypot --filter verified \
|
||||
--order-by volume --limit 20 --raw
|
||||
|
||||
# ETH 24h trending — sorted by smart money count
|
||||
gmgn-cli market trending \
|
||||
--chain eth --interval 24h \
|
||||
--filter not_honeypot --filter verified \
|
||||
--order-by smart_degen_count --limit 20 --raw
|
||||
```
|
||||
|
||||
### Trending — Base by Launchpad Platform
|
||||
|
||||
```bash
|
||||
@@ -437,9 +498,95 @@ Use field combinations to determine what stage a token is in. This affects how s
|
||||
| `--type` | No | Categories to query, repeatable: `new_creation` / `near_completion` / `completed` (default: all three) |
|
||||
| `--launchpad-platform` | No | Launchpad platform filter, repeatable (default: all platforms for the chain) |
|
||||
| `--limit` | No | Max results per category, max 80 (default: 80) |
|
||||
| `--filter-preset` | No | Named server-side filter preset: `safe` / `smart-money` / `strict` |
|
||||
| `--sort-by` | No | Client-side sort per category: `smart_degen_count` / `renowned_count` / `volume_24h` / `volume_1h` / `swaps_24h` / `swaps_1h` / `rug_ratio` / `holder_count` / `usd_market_cap` / `created_timestamp` |
|
||||
| `--direction` | No | Sort direction: `asc` / `desc` (default: `desc`; `asc` for `rug_ratio`) |
|
||||
| `--min-*` / `--max-*` | No | Server-side filter range flags — see Filter Fields Reference below |
|
||||
|
||||
### Filter Presets
|
||||
|
||||
Presets are applied server-side: the API filters tokens before returning results.
|
||||
|
||||
| Preset | Server-side filters applied |
|
||||
|--------|----------------------------|
|
||||
| `safe` | `max_rug_ratio=0.3` + `max_bundler_rate=0.3` + `max_insider_ratio=0.3` |
|
||||
| `smart-money` | `min_smart_degen_count=1` |
|
||||
| `strict` | `max_rug_ratio=0.3` + `max_bundler_rate=0.3` + `max_insider_ratio=0.3` + `min_smart_degen_count=1` + `min_volume_24h=1000` |
|
||||
|
||||
**Preset + explicit flag interaction:** Explicit filter flags always override preset values. For example, `--filter-preset safe --max-rug-ratio 0.1` applies the `safe` preset but overrides rug_ratio threshold to `0.1`.
|
||||
|
||||
**All filter flags are sent as part of the API request body (server-side)** — the server filters tokens before returning results. Use `--limit 80` (the default maximum) to maximise the pool.
|
||||
|
||||
Response fields: `data.new_creation`, `data.pump`, `data.completed` — each is an array of `RankItem` (same fields as `market trending` rank items). **Important: `data.pump` in the response corresponds to `--type near_completion` in the request. The API always returns this category under the key `pump`, not `near_completion`.**
|
||||
|
||||
### Server-Side Filter Fields
|
||||
|
||||
All filter flags are sent as part of the API request body — the server filters tokens before returning results. Flags follow the naming convention `--min-{field}` / `--max-{field}`.
|
||||
|
||||
| Flag pair | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `--min-volume-24h` / `--max-volume-24h` | float | 24h trading volume (USD) |
|
||||
| `--min-net-buy-24h` / `--max-net-buy-24h` | float | 24h net buy volume (USD) |
|
||||
| `--min-swaps-24h` / `--max-swaps-24h` | int | 24h total swap count |
|
||||
| `--min-buys-24h` / `--max-buys-24h` | int | 24h buy count |
|
||||
| `--min-sells-24h` / `--max-sells-24h` | int | 24h sell count |
|
||||
| `--min-visiting-count` / `--max-visiting-count` | int | Visitor count |
|
||||
| `--min-progress` / `--max-progress` | float | Bonding curve progress (0–1) |
|
||||
| `--min-marketcap` / `--max-marketcap` | float | Market cap (USD) |
|
||||
| `--min-liquidity` / `--max-liquidity` | float | Liquidity (USD) |
|
||||
| `--min-created` / `--max-created` | duration | Token age — unit suffix recommended: seconds (`30s`, `10s`) or minutes (`0.5m`, `1m`, `5m`, `30m`). Bare numbers (e.g. `5`) are treated as minutes with a warning. |
|
||||
| `--min-holder-count` / `--max-holder-count` | int | Holder count |
|
||||
| `--min-top-holder-rate` / `--max-top-holder-rate` | float | Top-10 holder concentration (0–1) |
|
||||
| `--min-rug-ratio` / `--max-rug-ratio` | float | Rug pull risk score (0–1) |
|
||||
| `--min-bundler-rate` / `--max-bundler-rate` | float | Bundle-bot trading ratio (0–1) |
|
||||
| `--min-insider-ratio` / `--max-insider-ratio` | float | Insider trading ratio (0–1) |
|
||||
| `--min-entrapment-ratio` / `--max-entrapment-ratio` | float | Entrapment/Phishing trading ratio (0–1) |
|
||||
| `--min-private-vault-hold-rate` / `--max-private-vault-hold-rate` | float | Private vault holding ratio (0–1) |
|
||||
| `--min-top70-sniper-hold-rate` / `--max-top70-sniper-hold-rate` | float | Top-70 sniper holding ratio (0–1) |
|
||||
| `--min-bot-count` / `--max-bot-count` | int | Bot wallet count |
|
||||
| `--min-bot-degen-rate` / `--max-bot-degen-rate` | float | Bot-degen wallet ratio (0–1) |
|
||||
| `--min-fresh-wallet-rate` / `--max-fresh-wallet-rate` | float | Fresh wallet ratio (0–1) |
|
||||
| `--min-total-fee` / `--max-total-fee` | float | Total fee |
|
||||
| `--min-smart-degen-count` / `--max-smart-degen-count` | int | Smart-money holder count |
|
||||
| `--min-renowned-count` / `--max-renowned-count` | int | KOL / renowned wallet count |
|
||||
| `--min-creator-balance-rate` / `--max-creator-balance-rate` | float | Creator holding ratio (0–1) |
|
||||
| `--min-creator-created-count` / `--max-creator-created-count` | int | Creator's total token creation count |
|
||||
| `--min-creator-created-open-count` / `--max-creator-created-open-count` | int | Creator's graduated token count |
|
||||
| `--min-creator-created-open-ratio` / `--max-creator-created-open-ratio` | float | Creator's graduation ratio (0–1) |
|
||||
| `--min-x-follower` / `--max-x-follower` | int | Twitter / X follower count |
|
||||
| `--min-twitter-rename-count` / `--max-twitter-rename-count` | int | Twitter rename count |
|
||||
| `--min-tg-call-count` / `--max-tg-call-count` | int | Telegram call count |
|
||||
|
||||
### Trenches Filter Examples
|
||||
|
||||
```bash
|
||||
# Apply the safe preset (server-side)
|
||||
gmgn-cli market trenches --chain sol --type new_creation --filter-preset safe
|
||||
|
||||
# Require at least 1 smart money holder (server-side)
|
||||
gmgn-cli market trenches --chain sol --type new_creation --min-smart-degen-count 1
|
||||
|
||||
# Safe preset + require smart money + sort by smart degen count (server-side filter, client-side sort)
|
||||
gmgn-cli market trenches --chain sol --type new_creation \
|
||||
--filter-preset safe --min-smart-degen-count 1 --sort-by smart_degen_count
|
||||
|
||||
# Strict preset — safe + smart money + min $1k volume (server-side)
|
||||
gmgn-cli market trenches --chain sol --type new_creation --type near_completion \
|
||||
--filter-preset strict --sort-by smart_degen_count
|
||||
|
||||
# Manual range filters (all sent server-side)
|
||||
gmgn-cli market trenches --chain sol --type new_creation \
|
||||
--max-rug-ratio 0.3 --max-bundler-rate 0.3 --max-insider-ratio 0.3 \
|
||||
--min-smart-degen-count 1 --min-volume-24h 1000
|
||||
|
||||
# Filter by token age: only tokens created within the last 30 minutes
|
||||
gmgn-cli market trenches --chain sol --type new_creation --max-created 30m
|
||||
|
||||
# Filter by market cap range
|
||||
gmgn-cli market trenches --chain sol --type new_creation \
|
||||
--min-marketcap 10000 --max-marketcap 500000
|
||||
```
|
||||
|
||||
## `market trenches` Response Fields
|
||||
|
||||
**Basic Info**
|
||||
@@ -526,6 +673,44 @@ Response fields: `data.new_creation`, `data.pump`, `data.completed` — each is
|
||||
|
||||
**After fetching trenches results, apply the Token Quality Filter Criteria section before presenting tokens to the user.** Do not dump raw results — filter first, then surface the strongest candidates.
|
||||
|
||||
### Trenches Filter Examples
|
||||
|
||||
```bash
|
||||
# Quick safe screen — exclude rugs, wash trading, and bundlers
|
||||
gmgn-cli market trenches --chain sol --type new_creation \
|
||||
--filter-preset safe --raw
|
||||
|
||||
# Smart money screen — only tokens with smart money or KOL presence
|
||||
gmgn-cli market trenches --chain sol \
|
||||
--type new_creation --type near_completion \
|
||||
--filter-preset smart-money \
|
||||
--sort-by smart_degen_count --raw
|
||||
|
||||
# Strict screen — safe + smart money + minimum volume, sorted by smart degens
|
||||
gmgn-cli market trenches --chain sol --type completed \
|
||||
--filter-preset strict --sort-by smart_degen_count --raw
|
||||
|
||||
# Custom filter — no wash trading, rug_ratio <= 0.2, at least 1 smart degen
|
||||
gmgn-cli market trenches --chain sol \
|
||||
--type new_creation --type near_completion \
|
||||
--exclude-wash-trading --max-rug-ratio 0.2 --min-smart-degen 1 \
|
||||
--sort-by smart_degen_count --raw
|
||||
|
||||
# BSC — safe screen on new tokens from fourmeme
|
||||
gmgn-cli market trenches --chain bsc --type new_creation \
|
||||
--launchpad-platform fourmeme --launchpad-platform fourmeme_agent \
|
||||
--filter-preset safe --sort-by volume_1h --raw
|
||||
|
||||
# Sort by rug_ratio ascending (safest first), no other filters
|
||||
gmgn-cli market trenches --chain sol --type completed \
|
||||
--sort-by rug_ratio --raw
|
||||
|
||||
# Find tokens with many holders and strong 1h swap activity
|
||||
gmgn-cli market trenches --chain sol --type completed \
|
||||
--min-holders 100 --min-swaps 50 \
|
||||
--sort-by swaps_1h --raw
|
||||
```
|
||||
|
||||
### Solana Trenches Examples
|
||||
|
||||
```bash
|
||||
@@ -653,6 +838,114 @@ Present each category separately with a header:
|
||||
# | Symbol | Market Cap | Volume (1h) | Smart Degens | Social
|
||||
```
|
||||
|
||||
## `market signal` Parameters
|
||||
|
||||
Chains: `sol` / `bsc` only. **Maximum 50 results per group** — use multiple groups via `--groups` to cover different signal types in a single request.
|
||||
|
||||
**Single-group (individual flags):**
|
||||
|
||||
Do **not** pass signal types **14, 15, or 16** in `signal_type` / `--signal-type` / `--groups` JSON — OpenAPI returns **400** if any group includes them. Omitting `--signal-type` (empty filter) still queries all types upstream; responses may still include 14–16 in that case.
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` |
|
||||
| `--signal-type` | No | Signal type(s), repeatable (1–18, default: all). See Signal Types below. |
|
||||
| `--mc-min` | No | Min market cap at trigger time (USD) |
|
||||
| `--mc-max` | No | Max market cap at trigger time (USD) |
|
||||
| `--trigger-mc-min` | No | Min market cap at signal trigger moment (USD) |
|
||||
| `--trigger-mc-max` | No | Max market cap at signal trigger moment (USD) |
|
||||
| `--total-fee-min` | No | Min total fees paid (USD) |
|
||||
| `--total-fee-max` | No | Max total fees paid (USD) |
|
||||
| `--min-create-or-open-ts` | No | Min token creation or open timestamp (Unix seconds string) |
|
||||
| `--max-create-or-open-ts` | No | Max token creation or open timestamp (Unix seconds string) |
|
||||
|
||||
**Multi-group override:**
|
||||
|
||||
Pass `--groups '<json_array>'` to query multiple filter groups in a single request. The upstream executes all groups in parallel and merges results sorted by `trigger_at` descending. When `--groups` is present, all individual flags above are ignored.
|
||||
|
||||
```bash
|
||||
gmgn-cli market signal --chain sol \
|
||||
--groups '[{"signal_type":[12,13]},{"signal_type":[6,7],"mc_min":50000}]'
|
||||
```
|
||||
|
||||
### Signal Types
|
||||
|
||||
| Value | Name | Description |
|
||||
|-------|------|-------------|
|
||||
| 1 | SignalType1 | General signal (K-line price spike) |
|
||||
| 2 | SignalTypeDexAd | Dex ad placement |
|
||||
| 3 | SignalTypeDexUpdateLink | Dex social link updated |
|
||||
| 4 | SignalTypeDexTrendingBar | Dex trending bar |
|
||||
| 5 | SignalTypeDexBoost | Dex Boost |
|
||||
| 6 | SignalTypePriceUp | Price spike |
|
||||
| 7 | SignalTypePriceATH | All-time high price |
|
||||
| 8 | SignalTypeMcpKeyLevel | Market cap key level |
|
||||
| 9 | SignalTypeLive | Live stream |
|
||||
| 10 | SignalTypeBundlerSell | Bundler sell |
|
||||
| 11 | SignalTypeCto | Community takeover (CTO) |
|
||||
| 12 | SignalTypeSmartDegenBuy | Smart money buy |
|
||||
| 13 | SignalTypePlatformCall | Platform call |
|
||||
| 14 | SignalTypeLargeAmountBuy | Large amount buy |
|
||||
| 15 | SignalTypeMultiBuy | Multiple buys |
|
||||
| 16 | SignalTypeMultiLargeBuy | Multiple large buys |
|
||||
| 17 | SignalTypeBagsClaims | Bags Claim |
|
||||
| 18 | SignalTypePumpClaims | Pump Claim |
|
||||
|
||||
### `market signal` Response Fields
|
||||
|
||||
Each item in the response array is one signal event:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `id` | string | Signal event ID |
|
||||
| `token_address` | string | Token contract address |
|
||||
| `signal_type` | number | Signal type (1–18, see Signal Types above) |
|
||||
| `trigger_at` | number | Unix timestamp (seconds) when the signal was triggered |
|
||||
| `trigger_mc` | number | Market cap at signal trigger time (USD) |
|
||||
| `first_trigger_mc` | number | Market cap at the very first trigger for this token (USD) |
|
||||
| `market_cap` | number | Current market cap (USD) |
|
||||
| `ath` | number | All-time high market cap (USD) |
|
||||
| `signal_times` | number | Total number of times this signal has triggered for this token |
|
||||
| `signal_times_by_type` | object | Signal trigger count broken down by type |
|
||||
| `cur_data` | object | Real-time token stats at query time (see below) |
|
||||
| `data` | object | Full upstream snapshot at trigger time (chain-specific, raw passthrough) |
|
||||
|
||||
**`cur_data` fields:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `top_10_holder_rate` | number | Top 10 holder concentration ratio (0–1) |
|
||||
| `holder_count` | number | Current holder count |
|
||||
| `liquidity` | number | Current liquidity (USD) |
|
||||
|
||||
### Usage Examples
|
||||
|
||||
```bash
|
||||
# All signals on SOL (no --signal-type: upstream returns all types, including 14–16 if present)
|
||||
gmgn-cli market signal --chain sol --raw
|
||||
|
||||
# Smart money buys only (type 12)
|
||||
gmgn-cli market signal --chain sol --signal-type 12 --raw
|
||||
|
||||
# Price spikes + ATH (types 6 and 7) with market cap filter
|
||||
gmgn-cli market signal --chain sol \
|
||||
--signal-type 6 --signal-type 7 \
|
||||
--mc-min 50000 --mc-max 5000000 --raw
|
||||
|
||||
# Smart money buys on BSC
|
||||
gmgn-cli market signal --chain bsc --signal-type 12 --raw
|
||||
|
||||
# Multi-group: parallel groups (do not use signal_type 14–16 — API returns 400)
|
||||
gmgn-cli market signal --chain sol \
|
||||
--groups '[{"signal_type":[12]},{"signal_type":[6,7]}]' --raw
|
||||
|
||||
# Multi-group: combine signal type filter with market cap range per group
|
||||
gmgn-cli market signal --chain sol \
|
||||
--groups '[{"signal_type":[12,13],"mc_min":100000},{"signal_type":[6,7],"mc_min":50000,"mc_max":1000000}]' --raw
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- `market kline`: `--from` and `--to` are Unix timestamps in **seconds** — CLI converts to milliseconds automatically
|
||||
|
||||
@@ -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: "<info|holdings|activity|stats|token-balance> [--chain <sol|bsc|base>] [--wallet <wallet_address>]"
|
||||
description: Analyze any crypto wallet by address — holdings, realized/unrealized P&L, win rate, trading history, performance stats, specific token balance, and tokens created by a developer wallet (with ATH market cap and DEX graduation status) via GMGN API on Solana, BSC, Base, or Ethereum. Use when user asks about a wallet's holdings, P&L, win rate, what tokens a dev has launched, the highest ATH token a dev ever created, or wants a wallet report to decide whether to copy-trade or follow.
|
||||
argument-hint: "<info|holdings|activity|stats|token-balance|created-tokens> [--chain <sol|bsc|base|eth>] [--wallet <wallet_address>]"
|
||||
metadata:
|
||||
cliHelp: "gmgn-cli portfolio --help"
|
||||
---
|
||||
@@ -39,16 +39,52 @@ 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 created-tokens` | Tokens created by a developer wallet, with market cap and ATH info |
|
||||
|
||||
## Supported Chains
|
||||
|
||||
`sol` / `bsc` / `base`
|
||||
`sol` / `bsc` / `base` / `eth`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `.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`
|
||||
- `gmgn-cli` installed globally — if missing, run: `npm install -g gmgn-cli`
|
||||
- `GMGN_API_KEY` configured in `~/.config/gmgn/.env`
|
||||
|
||||
## Rate Limit Handling
|
||||
|
||||
All portfolio routes used by this skill go through GMGN's leaky-bucket limiter with `rate=10` and `capacity=10`. Sustained throughput is roughly `10 ÷ weight` requests/second, and the max burst is roughly `floor(10 ÷ weight)` when the bucket is full.
|
||||
|
||||
| Command | Route | Weight |
|
||||
|---------|-------|--------|
|
||||
| `portfolio info` | `GET /v1/user/info` | 1 |
|
||||
| `portfolio holdings` | `GET /v1/user/wallet_holdings` | 2 |
|
||||
| `portfolio activity` | `GET /v1/user/wallet_activity` | 3 |
|
||||
| `portfolio stats` | `GET /v1/user/wallet_stats` | 3 |
|
||||
| `portfolio token-balance` | `GET /v1/user/wallet_token_balance` | 1 |
|
||||
| `portfolio created-tokens` | `GET /v1/user/created_tokens` | 2 |
|
||||
|
||||
When a request returns `429`:
|
||||
|
||||
- Read `X-RateLimit-Reset` from the response headers. It is a Unix timestamp in seconds that marks when the limit is expected to reset.
|
||||
- If the response body contains `reset_at` (e.g., `{"code":429,"error":"RATE_LIMIT_BANNED","message":"...","reset_at":1775184222}`), extract `reset_at` — it is the Unix timestamp when the ban lifts (typically 5 minutes). Convert to local time and tell the user exactly when they can retry.
|
||||
- The CLI may wait and retry once automatically when the remaining cooldown is short. If it still fails, stop and tell the user the exact retry time instead of sending more requests.
|
||||
- For `RATE_LIMIT_EXCEEDED` or `RATE_LIMIT_BANNED`, repeated requests during the cooldown can extend the ban by 5 seconds each time, up to 5 minutes. Do not spam retries.
|
||||
|
||||
**First-time setup** (if `GMGN_API_KEY` is not configured):
|
||||
|
||||
1. Generate key pair and show the public key to the user:
|
||||
```bash
|
||||
openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
openssl pkey -in /tmp/gmgn_private.pem -pubout 2>/dev/null
|
||||
```
|
||||
Tell the user: *"This is your Ed25519 public key. Go to **https://gmgn.ai/ai**, paste it into the API key creation form, then send me the API Key value shown on the page."*
|
||||
|
||||
2. Wait for the user's API key, then configure:
|
||||
```bash
|
||||
mkdir -p ~/.config/gmgn
|
||||
echo 'GMGN_API_KEY=<key_from_user>' > ~/.config/gmgn/.env
|
||||
chmod 600 ~/.config/gmgn/.env
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
@@ -91,8 +127,38 @@ gmgn-cli portfolio stats --chain sol \
|
||||
# Token balance
|
||||
gmgn-cli portfolio token-balance \
|
||||
--chain sol --wallet <wallet_address> --token <token_address>
|
||||
|
||||
# Tokens created by a developer wallet
|
||||
gmgn-cli portfolio created-tokens --chain sol --wallet <wallet_address>
|
||||
|
||||
# Created tokens sorted by all-time high market cap
|
||||
gmgn-cli portfolio created-tokens \
|
||||
--chain sol --wallet <wallet_address> \
|
||||
--order-by token_ath_mc --direction desc
|
||||
|
||||
# Only migrated tokens
|
||||
gmgn-cli portfolio created-tokens \
|
||||
--chain sol --wallet <wallet_address> --migrate-state migrated
|
||||
|
||||
# ETH wallet holdings
|
||||
gmgn-cli portfolio holdings --chain eth --wallet <0x_wallet_address>
|
||||
|
||||
# ETH wallet transaction activity
|
||||
gmgn-cli portfolio activity --chain eth --wallet <0x_wallet_address>
|
||||
|
||||
# ETH token balance
|
||||
gmgn-cli portfolio token-balance \
|
||||
--chain eth --wallet <0x_wallet_address> --token <0x_token_address>
|
||||
```
|
||||
|
||||
## `portfolio created-tokens` Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--order-by <field>` | Sort field: `market_cap` / `token_ath_mc` |
|
||||
| `--direction <asc\|desc>` | Sort direction (default `desc`) |
|
||||
| `--migrate-state <state>` | Filter by migration status: `migrated` (graduated to DEX) / `non_migrated` (still on bonding curve) |
|
||||
|
||||
## `portfolio holdings` Options
|
||||
|
||||
| Option | Description |
|
||||
@@ -178,6 +244,76 @@ The response is an object (or array for batch). Key fields:
|
||||
| `sell_count` | Number of sell transactions |
|
||||
| `pnl` | Profit/loss ratio = `realized_profit / total_cost` |
|
||||
|
||||
The response also includes a `common` object when available (absent if the upstream identity service is unavailable):
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `common.avatar` | Wallet avatar URL |
|
||||
| `common.name` | Display name |
|
||||
| `common.ens` | ENS domain (EVM chains only) |
|
||||
| `common.tag` | Primary wallet tag |
|
||||
| `common.tags` | All wallet tags (e.g. `["smart_money"]`) |
|
||||
| `common.twitter_username` | Twitter handle |
|
||||
| `common.twitter_name` | Twitter display name |
|
||||
| `common.followers_count` | Twitter follower count |
|
||||
| `common.is_blue_verified` | Twitter blue-verified badge |
|
||||
| `common.follow_count` | Number of GMGN users following this wallet |
|
||||
| `common.remark_count` | Number of GMGN users who have remarked this wallet |
|
||||
| `common.created_token_count` | Tokens created by this wallet |
|
||||
| `common.created_at` | Wallet creation time (Unix seconds) — records when the first funding transaction arrived; use this as the wallet's age indicator |
|
||||
| `common.fund_from` | Funding source label |
|
||||
| `common.fund_from_address` | Address that funded this wallet |
|
||||
| `common.fund_amount` | Funding amount |
|
||||
|
||||
Use `common.tags` and `common.twitter_username` when building a wallet profile narrative. If `common` is absent in the response, omit identity fields silently — do not report it as an error.
|
||||
|
||||
### `portfolio created-tokens` — Key Fields
|
||||
|
||||
The response `data` object has a `tokens` array plus aggregate stats.
|
||||
|
||||
Top-level fields:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `last_create_timestamp` | Unix timestamp of the most recent token creation |
|
||||
| `inner_count` | Number of tokens still on the bonding curve (NOT graduated) |
|
||||
| `open_count` | Number of tokens that have graduated to DEX |
|
||||
| `open_ratio` | Graduation rate (string, e.g. `"0.25"`) |
|
||||
|
||||
> **Total created = `inner_count + open_count`**. Do NOT use `len(tokens)` as the total — the `tokens` array is capped at 100 entries and may be truncated.
|
||||
| `creator_ath_info` | Best-performing token created by this wallet (ATH market cap) |
|
||||
| `tokens` | Array of created tokens — see below |
|
||||
|
||||
`creator_ath_info` fields:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `creator` | Wallet address |
|
||||
| `ath_token` | Token address with highest ATH market cap |
|
||||
| `ath_mc` | ATH market cap (USD string) |
|
||||
| `token_symbol` / `token_name` | Token ticker and name |
|
||||
| `token_logo` | Logo URL |
|
||||
|
||||
Per-token fields (`tokens[*]`):
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `token_address` | Token contract address |
|
||||
| `symbol` | Token ticker |
|
||||
| `chain` | Chain name |
|
||||
| `create_timestamp` | Unix timestamp of creation |
|
||||
| `is_open` | `true` if graduated to DEX |
|
||||
| `market_cap` | Current market cap (USD string) |
|
||||
| `token_ath_mc` | All-time high market cap (USD string) |
|
||||
| `pool_liquidity` | Current liquidity (USD string) |
|
||||
| `holders` | Current holder count |
|
||||
| `swap_1h` | Swap count in the last hour |
|
||||
| `volume_1h` | Trading volume in the last hour (USD string) |
|
||||
| `launchpad_platform` | Launch platform name (e.g. `Pump.fun`) |
|
||||
| `is_pump` | `true` if launched on Pump.fun |
|
||||
| `bundler_rate` | Bundler participation rate (0–1) |
|
||||
| `cto_flag` | `true` if community-takeover token |
|
||||
|
||||
**Do NOT guess field names not listed here.** If a field appears in the response but is not in this table, do not interpret it without reading the raw output first.
|
||||
|
||||
## Output Format
|
||||
@@ -217,9 +353,10 @@ Win Rate: {winrate × 100}%
|
||||
Total Spent: ${total_cost}
|
||||
Buys / Sells: {buy_count} / {sell_count}
|
||||
PnL Ratio: {pnl}x
|
||||
[Identity: {common.name or common.twitter_username} | Tags: {common.tags}]
|
||||
```
|
||||
|
||||
For batch queries (multiple wallets), present one summary block per wallet.
|
||||
Show the `[Identity: ...]` line only if `common` is present in the response. For batch queries (multiple wallets), present one summary block per wallet.
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -239,3 +376,4 @@ For in-depth trading style analysis, copy-trade ROI estimation, and smart money
|
||||
- User asks "is this wallet worth following" → [`docs/workflow-wallet-analysis.md`](../../docs/workflow-wallet-analysis.md)
|
||||
- User asks "what's this wallet's trading style", "when does he take profit", "smart money profile", "if I copied this wallet what would my return be" → [`docs/workflow-smart-money-profile.md`](../../docs/workflow-smart-money-profile.md)
|
||||
- User wants to compare multiple smart money wallets by winrate/PnL → [`docs/workflow-smart-money-profile.md`](../../docs/workflow-smart-money-profile.md) Step 5 (leaderboard)
|
||||
- User asks "what tokens did this dev create", "dev 发过哪些币", "查一下这个 dev 的代币", "dev 创建记录" → use `portfolio created-tokens --chain <chain> --wallet <creator_address>` directly. Get the creator address first via `token info` if only a token address is given.
|
||||
|
||||
+347
-39
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: gmgn-swap
|
||||
description: "[FINANCIAL EXECUTION] Submit a real blockchain token swap or query order status. Executes irreversible on-chain transactions. Requires explicit user confirmation before every swap. Supports sol / bsc / base."
|
||||
argument-hint: "[--chain <chain> --from <wallet> --input-token <addr> --output-token <addr> --amount <n>] | [order get --chain <chain> --order-id <id>]"
|
||||
description: "[FINANCIAL EXECUTION] Buy and sell meme coins and crypto tokens on Solana, BSC, Base, or Ethereum — single swap, multi-wallet batch trading, limit orders, stop loss, take profit, trailing stop loss, trailing take profit via GMGN API. Requires explicit user confirmation. Use when user asks to buy, sell, or swap a token, trade from multiple wallets, set a limit order, stop loss, take profit, or check order status."
|
||||
argument-hint: "[--chain <chain> --from <wallet> --input-token <addr> --output-token <addr> --amount <n>] | [order get --chain <chain> --order-id <id>] | [order strategy list --chain <chain> --group-tag <LimitOrder|STMix>] | [order strategy create --chain <chain> --order-type limit_order --sub-order-type <buy_low|buy_high|stop_loss|take_profit> ...]"
|
||||
metadata:
|
||||
cliHelp: "gmgn-cli swap --help"
|
||||
---
|
||||
@@ -12,7 +12,7 @@ metadata:
|
||||
|
||||
**⚠️ IPv6 NOT SUPPORTED: If you get a `401` or `403` error and credentials look correct, check for IPv6 immediately: (1) list all network interfaces and their IPv6 addresses — run `ifconfig | grep inet6` (macOS) or `ip addr show | grep inet6` (Linux); (2) send a test request to `https://ipv6.icanhazip.com` — if the response is an IPv6 address, outbound traffic is going via IPv6. Tell the user immediately: "Please disable IPv6 on your network interface — gmgn-cli commands only work over IPv4."**
|
||||
|
||||
Use the `gmgn-cli` tool to submit a token swap or query an existing order. **Requires private key** (`GMGN_PRIVATE_KEY` in `.env`).
|
||||
Use the `gmgn-cli` tool to submit a token swap or query an existing order. `GMGN_API_KEY` is always required. `GMGN_PRIVATE_KEY` is required for critical-auth commands such as `swap` and all `order` subcommands, including `order quote`.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
@@ -24,19 +24,19 @@ Use the `gmgn-cli` tool to submit a token swap or query an existing order. **Req
|
||||
|
||||
- **Currency tokens** — Each chain has designated currency tokens (SOL, BNB, ETH, USDC). These are the base assets used to buy other tokens or receive swap proceeds. Their contract addresses are fixed — look them up in the Chain Currencies table, never guess them.
|
||||
|
||||
- **Anti-MEV** — MEV (Miner/Maximal Extractable Value) refers to frontrunning and sandwich attacks where bots exploit pending transactions. `--anti-mev` routes the transaction through protected channels to reduce this risk. Enabled by default.
|
||||
- **Anti-MEV** — MEV (Miner/Maximal Extractable Value) refers to frontrunning and sandwich attacks where bots exploit pending transactions. `--anti-mev` routes the transaction through protected channels to reduce this risk. **Recommended: always enable.** Default: on.
|
||||
|
||||
- **Critical auth** — `swap` requires both `GMGN_API_KEY` and `GMGN_PRIVATE_KEY`. The private key never leaves the machine — the CLI uses it only for local signing and sends only the resulting signature. Normal commands (like `order quote`) use API Key alone.
|
||||
- **Critical auth** — `swap` and all `order` subcommands require both `GMGN_API_KEY` and `GMGN_PRIVATE_KEY`. The private key never leaves the machine — the CLI uses it only for local signing and sends only the resulting signature.
|
||||
|
||||
- **`order_id` / `status`** — After submitting a swap, the response includes an `order_id`. Use `order get --order-id` to poll for final status. Possible values: `pending` → `processed` → `confirmed` (success) or `failed` / `expired`. Do not report success until status is `confirmed`.
|
||||
|
||||
- **`filled_input_amount` / `filled_output_amount`** — Actual amounts consumed/received, in smallest unit. Convert to human-readable using token decimals before displaying to the user.
|
||||
- **`report.input_amount` / `report.output_amount`** — Actual amounts consumed/received, in smallest unit. Only present when `state = 30` and `status = "successful"`. Convert to human-readable using `report.input_token_decimals` / `report.output_token_decimals` before displaying to the user.
|
||||
|
||||
## Financial Risk Notice
|
||||
|
||||
**This skill executes REAL, IRREVERSIBLE blockchain transactions.**
|
||||
|
||||
- Every `swap` command submits an on-chain transaction that moves real funds.
|
||||
- Every `swap` and `order strategy create` command submits an on-chain transaction that moves real funds.
|
||||
- Transactions cannot be undone once confirmed on-chain.
|
||||
- The AI agent must **never auto-execute a swap** — explicit user confirmation is required every time, without exception.
|
||||
- Only use this skill with funds you are willing to trade. Start with small amounts when testing.
|
||||
@@ -46,34 +46,71 @@ 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) |
|
||||
| `multi-swap` | Submit token swaps across multiple wallets concurrently (up to 100) |
|
||||
| `order quote` | Get a swap quote (no transaction submitted; requires critical auth) |
|
||||
| `order get` | Query order status |
|
||||
| `order strategy create` | Create a limit/strategy order (requires private key) |
|
||||
| `order strategy list` | List strategy orders (requires private key) |
|
||||
| `order strategy cancel` | Cancel a strategy order (requires private key) |
|
||||
|
||||
## Supported Chains
|
||||
|
||||
`sol` / `bsc` / `base`
|
||||
|
||||
`sol` / `bsc` / `base` / `eth`
|
||||
|
||||
## Chain Currencies
|
||||
|
||||
Currency tokens are the base/native assets of each chain. They are used to buy other tokens or receive proceeds from selling. Knowing which tokens are currencies is critical for `--percent` usage (see Swap Parameters below).
|
||||
|
||||
| Chain | Currency tokens |
|
||||
|-------|----------------|
|
||||
| `sol` | SOL (native, So11111111111111111111111111111111111111112), USDC (`EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`) |
|
||||
| `bsc` | BNB (native, 0x0000000000000000000000000000000000000000), USDC (`0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d`) |
|
||||
| Chain | Currency tokens |
|
||||
| ------ | --------------- |
|
||||
| `sol` | SOL (native, So11111111111111111111111111111111111111112), USDC (`EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`) |
|
||||
| `bsc` | BNB (native, 0x0000000000000000000000000000000000000000), USDC (`0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d`) |
|
||||
| `base` | ETH (native, 0x0000000000000000000000000000000000000000), USDC (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`) |
|
||||
| `eth` | ETH (native, 0x0000000000000000000000000000000000000000) |
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Both `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` must be set in `.env`. The private key must correspond to the wallet bound to the API Key.
|
||||
`GMGN_API_KEY` must be configured in `~/.config/gmgn/.env`. `GMGN_PRIVATE_KEY` is additionally required for `swap` and all `order` subcommands. The private key must correspond to the wallet bound to the API Key.
|
||||
|
||||
`gmgn-cli` must be installed globally before use (one-time setup):
|
||||
- `gmgn-cli` installed globally — if missing, run: `npm install -g gmgn-cli`
|
||||
|
||||
```bash
|
||||
npm install -g gmgn-cli
|
||||
```
|
||||
## Rate Limit Handling
|
||||
|
||||
All swap-related routes used by this skill go through GMGN's leaky-bucket limiter with `rate=10` and `capacity=10`. Sustained throughput is roughly `10 ÷ weight` requests/second, and the max burst is roughly `floor(10 ÷ weight)` when the bucket is full.
|
||||
|
||||
| Command | Route | Weight |
|
||||
|---------|-------|--------|
|
||||
| `swap` | `POST /v1/trade/swap` | 5 |
|
||||
| `multi-swap` | `POST /v1/trade/multi_swap` | 5 |
|
||||
| `order quote` | `GET /v1/trade/quote` | 2 |
|
||||
| `order get` | `GET /v1/trade/query_order` | 1 |
|
||||
|
||||
When a request returns `429`:
|
||||
|
||||
- Read `X-RateLimit-Reset` from the response headers. It is a Unix timestamp in seconds that marks when the limit is expected to reset.
|
||||
- If the response body contains `reset_at` (e.g., `{"code":429,"error":"RATE_LIMIT_BANNED","message":"...","reset_at":1775184222}`), extract `reset_at` — it is the Unix timestamp when the ban lifts (typically 5 minutes). Convert to local time and tell the user exactly when they can retry.
|
||||
- `swap` is a real transaction: never loop or auto-submit repeated swap attempts after a `429`. Wait until the reset time, then ask for confirmation again before retrying.
|
||||
- The CLI may wait and retry once automatically for short cooldowns on read-only commands such as `order quote` and `order get`. If it still fails, stop and tell the user the exact retry time instead of sending more requests.
|
||||
- For `RATE_LIMIT_EXCEEDED` or `RATE_LIMIT_BANNED`, repeated requests during the cooldown can extend the ban by 5 seconds each time, up to 5 minutes.
|
||||
- `POST /v1/trade/swap` also has an error-count limiter. Repeatedly triggering the same business error, especially `40003701` (insufficient token balance), can return `ERROR_RATE_LIMIT_BLOCKED`. When this happens, do not retry until the reset time and fix the underlying request first.
|
||||
|
||||
**First-time setup** (if credentials are not configured):
|
||||
|
||||
1. Generate key pair and show the public key to the user:
|
||||
```bash
|
||||
openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
openssl pkey -in /tmp/gmgn_private.pem -pubout 2>/dev/null
|
||||
```
|
||||
Tell the user: *"This is your Ed25519 public key. Go to **https://gmgn.ai/ai**, paste it into the API key creation form (enable swap capability), then send me the API Key value shown on the page."*
|
||||
|
||||
2. Wait for the user's API key, then configure both credentials:
|
||||
```bash
|
||||
mkdir -p ~/.config/gmgn
|
||||
echo 'GMGN_API_KEY=<key_from_user>' > ~/.config/gmgn/.env
|
||||
echo 'GMGN_PRIVATE_KEY="<pem_content_from_step_1>"' >> ~/.config/gmgn/.env
|
||||
chmod 600 ~/.config/gmgn/.env
|
||||
```
|
||||
|
||||
### Credential Model
|
||||
|
||||
@@ -128,9 +165,92 @@ gmgn-cli swap \
|
||||
--percent 50
|
||||
```
|
||||
|
||||
## `multi-swap` Usage
|
||||
|
||||
Submit a token swap across multiple wallets concurrently. Each wallet executes independently — one wallet's failure does not affect others. Up to 100 wallets per request. All wallets must be bound to the API Key. Requires `GMGN_PRIVATE_KEY`.
|
||||
|
||||
```bash
|
||||
# Basic multi-wallet swap
|
||||
gmgn-cli multi-swap \
|
||||
--chain sol \
|
||||
--accounts <addr1>,<addr2> \
|
||||
--input-token <input_token_address> \
|
||||
--output-token <output_token_address> \
|
||||
--input-amount '{"<addr1>":"1000000","<addr2>":"2000000"}' \
|
||||
--slippage 0.01
|
||||
|
||||
# Sell a percentage of each wallet's balance (use --input-amount-bps)
|
||||
gmgn-cli multi-swap \
|
||||
--chain sol \
|
||||
--accounts <addr1>,<addr2> \
|
||||
--input-token <token_address> \
|
||||
--output-token <sol_address> \
|
||||
--input-amount-bps '{"<addr1>":"5000","<addr2>":"10000"}' \
|
||||
--slippage 0.01
|
||||
|
||||
# With per-wallet take-profit / stop-loss (condition_orders)
|
||||
gmgn-cli multi-swap \
|
||||
--chain sol \
|
||||
--accounts <addr1>,<addr2> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_address> \
|
||||
--input-amount '{"<addr1>":"1000000","<addr2>":"2000000"}' \
|
||||
--slippage 0.3 \
|
||||
--priority-fee 0.00001 \
|
||||
--tip-fee 0.00001 \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"100"},{"order_type":"loss_stop","side":"sell","price_scale":"50","sell_ratio":"100"}]'
|
||||
|
||||
# ETH multi-wallet swap (EIP-1559 gas)
|
||||
gmgn-cli multi-swap \
|
||||
--chain eth \
|
||||
--accounts <0xaddr1>,<0xaddr2> \
|
||||
--input-token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
|
||||
--output-token <token_address> \
|
||||
--input-amount '{"<0xaddr1>":"1000000","<0xaddr2>":"2000000"}' \
|
||||
--slippage 0.01 \
|
||||
--gas-price 5
|
||||
```
|
||||
|
||||
## `multi-swap` Parameters
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` / `eth` |
|
||||
| `--accounts` | Yes | Comma-separated wallet addresses (1–100, all must be bound to the API Key) |
|
||||
| `--input-token` | Yes | Input token contract address |
|
||||
| `--output-token` | Yes | Output token contract address |
|
||||
| `--input-amount` | No* | JSON map of `wallet_address → input amount` (smallest unit). One of `--input-amount`, `--input-amount-bps`, or `--output-amount` is required. |
|
||||
| `--input-amount-bps` | No* | JSON map of `wallet_address → percent in bps` (1–10000; 5000 = 50%). Only valid when `input_token` is NOT a currency. |
|
||||
| `--output-amount` | No* | JSON map of `wallet_address → target output amount` (smallest unit). |
|
||||
| `--slippage <n>` | No | Slippage tolerance, e.g. `0.01` = 1%. Mutually exclusive with `--auto-slippage`. |
|
||||
| `--auto-slippage` | No | Enable automatic slippage. |
|
||||
| `--anti-mev` | No | Enable anti-MEV protection. |
|
||||
| `--priority-fee <sol>` | No | Priority fee in SOL (≥ 0.00001, SOL only). Required when using `--condition-orders` on SOL. |
|
||||
| `--tip-fee <amount>` | No | Tip fee (SOL ≥ 0.00001 / BSC ≥ 0.000001 BNB). Required when using `--condition-orders` on SOL. |
|
||||
| `--auto-tip-fee` | No | Enable automatic tip fee. |
|
||||
| `--max-auto-fee <amount>` | No | Max automatic fee cap. |
|
||||
| `--gas-price <gwei>` | No | Gas price in gwei (BSC: 0.05–10 / BASE: 0.01–10 / ETH: 2–20). Required when using `--condition-orders` on BSC. |
|
||||
| `--max-fee-per-gas <amount>` | No | EIP-1559 max fee per gas (Base / ETH). Defaults to `--gas-price` if omitted. |
|
||||
| `--max-priority-fee-per-gas <amount>` | No | EIP-1559 max priority fee per gas (Base / ETH). Defaults to `--gas-price` if omitted. |
|
||||
| `--condition-orders <json>` | No | JSON array of condition sub-orders (take-profit / stop-loss) attached to each successful wallet's swap. Same structure as `swap --condition-orders`. Strategy creation is best-effort per wallet. |
|
||||
| `--sell-ratio-type <type>` | No | Sell ratio base for `--condition-orders`: `buy_amount` (default) / `hold_amount`. |
|
||||
|
||||
## `multi-swap` Response Fields
|
||||
|
||||
The response `data` is an array — one element per wallet:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `account` | string | Wallet address |
|
||||
| `success` | bool | Whether this wallet's swap succeeded |
|
||||
| `error` | string | Error message on failure; absent on success |
|
||||
| `error_code` | string | Error code on failure; absent on success |
|
||||
| `result` | object | On success: OrderResponse (same fields as `swap` response). On failure: absent. |
|
||||
| `result.strategy_order_id` | string | Strategy order ID; only present when `--condition-orders` was passed and strategy creation succeeded (best-effort) |
|
||||
|
||||
## `order quote` Usage
|
||||
|
||||
Get an estimated output amount before submitting a swap. Uses normal auth — no private key required.
|
||||
Get an estimated output amount before submitting a swap. All supported quote chains use critical auth and require `GMGN_PRIVATE_KEY`.
|
||||
|
||||
```bash
|
||||
gmgn-cli order quote \
|
||||
@@ -163,7 +283,7 @@ gmgn-cli order get --chain sol --order-id <order_id>
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` |
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` / `eth` |
|
||||
| `--from` | Yes | Wallet address (must match API Key binding) |
|
||||
| `--input-token` | Yes | Input token contract address |
|
||||
| `--output-token` | Yes | Output token contract address |
|
||||
@@ -172,33 +292,113 @@ gmgn-cli order get --chain sol --order-id <order_id>
|
||||
| `--slippage <n>` | No | Slippage tolerance, e.g. `0.01` = 1%. **Mutually exclusive with `--auto-slippage`** — use one or the other. |
|
||||
| `--auto-slippage` | No | Enable automatic slippage. **Mutually exclusive with `--slippage`.** |
|
||||
| `--min-output <n>` | No | Minimum output amount |
|
||||
| `--anti-mev` | No | Enable anti-MEV protection (default true) |
|
||||
| `--anti-mev` | No | Enable anti-MEV protection — **recommended**; protects against frontrunning and sandwich attacks. Default: on |
|
||||
| `--priority-fee <sol>` | No | Priority fee in SOL (≥ 0.00001, SOL only) |
|
||||
| `--tip-fee <n>` | No | Tip fee (SOL ≥ 0.00001 / BSC ≥ 0.000001 BNB) |
|
||||
| `--max-auto-fee <n>` | No | Max automatic fee cap |
|
||||
| `--gas-price <gwei>` | No | Gas price in gwei (BSC ≥ 0.05 / BASE/ETH ≥ 0.01) |
|
||||
| `--max-fee-per-gas <n>` | No | EIP-1559 max fee per gas (Base only) |
|
||||
| `--max-priority-fee-per-gas <n>` | No | EIP-1559 max priority fee per gas (Base only) |
|
||||
| `--condition-orders <json>` | No | JSON array of condition sub-orders (take-profit / stop-loss) to attach after a successful swap. **Max 10 sub-orders.** Strategy creation is best-effort: if the swap succeeds but strategy creation fails, the swap result is still returned. See ConditionOrder fields below. |
|
||||
| `--sell-ratio-type <type>` | No | Sell ratio basis for `--condition-orders`: `buy_amount` (default) — when triggered, sells a fixed token amount stored at strategy creation time; `hold_amount` — when triggered, sells a fixed percentage of the position held at trigger time |
|
||||
|
||||
## `swap` Response Fields
|
||||
### ConditionOrder Fields (for `--condition-orders`)
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `order_id` | string | Order ID for follow-up queries |
|
||||
| `hash` | string | Transaction hash |
|
||||
| `status` | string | Order status: `pending` / `processed` / `confirmed` / `failed` / `expired` |
|
||||
| `error_code` | string | Error code on failure |
|
||||
| `error_status` | string | Error description on failure |
|
||||
| `input_token` | string | Input token contract address |
|
||||
| `output_token` | string | Output token contract address |
|
||||
| `filled_input_amount` | string | Actual input consumed (smallest unit); empty if not filled |
|
||||
| `filled_output_amount` | string | Actual output received (smallest unit); empty if not filled |
|
||||
Each element in the `--condition-orders` JSON array supports:
|
||||
|
||||
| Field | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `order_type` | Yes | string | Sub-order type: `profit_stop` (fixed take-profit), `loss_stop` (fixed stop-loss), `profit_stop_trace` (trailing take-profit), `loss_stop_trace` (trailing stop-loss) |
|
||||
| `side` | Yes | string | Always `"sell"` |
|
||||
| `price_scale` | Conditional | string | Gain/drop % from entry. Required for `profit_stop` / `loss_stop` / `profit_stop_trace`; optional for `loss_stop_trace`. For `profit_stop` / `profit_stop_trace`: gain % (e.g. `"100"` = +100% / 2× entry). For `loss_stop` / `loss_stop_trace`: drop % (e.g. `"65"` = drops 65%, triggers at 35% of entry). |
|
||||
| `sell_ratio` | Yes | string | Percentage of position to sell when triggered, e.g. `"100"` = 100% |
|
||||
| `drawdown_rate` | Conditional | string | Required for `profit_stop_trace` and `loss_stop_trace`. Trailing callback %: after price peaks, how far it must fall before the order fires. E.g. `"50"` = 50% drawdown from peak. |
|
||||
|
||||
**Example — attach take-profit at 2× (+100%) and stop-loss at -60%:**
|
||||
|
||||
```json
|
||||
[
|
||||
{"order_type": "profit_stop", "side": "sell", "price_scale": "100", "sell_ratio": "100"},
|
||||
{"order_type": "loss_stop", "side": "sell", "price_scale": "60", "sell_ratio": "100"}
|
||||
]
|
||||
```
|
||||
|
||||
**Example — buy token A with 0.01 SOL, take-profit 50% at +100%, take-profit remaining 50% at +300%, stop-loss 100% at -65% (trigger at 35% entry price) (`hold_amount` mode):**
|
||||
|
||||
```bash
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_A_address> \
|
||||
--amount 10000000 \
|
||||
--slippage 0.3 \
|
||||
--anti-mev \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"50"},{"order_type":"profit_stop","side":"sell","price_scale":"300","sell_ratio":"100"},{"order_type":"loss_stop","side":"sell","price_scale":"65","sell_ratio":"100"}]' \
|
||||
--sell-ratio-type hold_amount
|
||||
```
|
||||
|
||||
> `price_scale` for `profit_stop`: gain % from entry (`"100"` = +100% / 2×, `"300"` = +300% / 4×). For `loss_stop`: drop % from entry (`"65"` = drops 65%, triggers at 35% of entry).
|
||||
> `hold_amount`: the second take-profit fires on whatever is held at trigger time (the remaining 50%). If you added to your position in between, those additional tokens will be included as well.
|
||||
|
||||
**Same strategy using `buy_amount` mode — fixed percentage of the original bought amount at each trigger:**
|
||||
|
||||
```bash
|
||||
gmgn-cli swap \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--input-token So11111111111111111111111111111111111111112 \
|
||||
--output-token <token_A_address> \
|
||||
--amount 10000000 \
|
||||
--slippage 0.3 \
|
||||
--anti-mev \
|
||||
--condition-orders '[{"order_type":"profit_stop","side":"sell","price_scale":"100","sell_ratio":"50"},{"order_type":"profit_stop","side":"sell","price_scale":"300","sell_ratio":"50"},{"order_type":"loss_stop","side":"sell","price_scale":"65","sell_ratio":"100"}]' \
|
||||
--sell-ratio-type buy_amount
|
||||
```
|
||||
|
||||
> `buy_amount`: each take-profit sells 50% of the **original** bought amount. Stop-loss sells 100% of the original bought amount.
|
||||
|
||||
## `swap` / `order get` Response Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------- | ------ | ---- |
|
||||
| `order_id` | string | Order ID for follow-up queries |
|
||||
| `hash` | string | Transaction hash |
|
||||
| `status` | string | Order status: `pending` / `processed` / `confirmed` / `failed` / `expired` |
|
||||
| `error_code` | string | Error code on failure |
|
||||
| `error_status` | string | Error description on failure |
|
||||
| `strategy_order_id` | string | Strategy order ID; only present when `--condition-orders` was passed and strategy creation succeeded (best-effort) |
|
||||
| `report` | object | Execution report; only present when `state = 30` and `status = "successful"`. See Report Fields below. |
|
||||
|
||||
### Report Fields (present only when `status = "successful"`)
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----------------------- | ------- | ---- |
|
||||
| `input_token` | string | Input token contract address |
|
||||
| `input_token_decimals` | integer | Input token decimal places |
|
||||
| `swap_mode` | string | Swap mode: `ExactIn` / `ExactOut` |
|
||||
| `input_amount` | string | Actual input consumed (smallest unit) |
|
||||
| `output_token` | string | Output token contract address |
|
||||
| `output_token_decimals` | integer | Output token decimal places |
|
||||
| `output_amount` | string | Actual output received (smallest unit) |
|
||||
| `quote_token` | string | Quote token contract address |
|
||||
| `quote_decimals` | integer | Quote token decimal places |
|
||||
| `quote_amount` | string | Quote amount (smallest unit) |
|
||||
| `base_token` | string | Base token contract address |
|
||||
| `base_decimals` | integer | Base token decimal places |
|
||||
| `base_amount` | string | Base token amount (smallest unit) |
|
||||
| `price` | string | Execution price (quote/base token) |
|
||||
| `price_usd` | string | Execution price in USD |
|
||||
| `height` | integer | Block height of execution |
|
||||
| `order_height` | integer | Block height when order was placed |
|
||||
| `gas_native` | string | Gas fee in native token |
|
||||
| `gas_usd` | string | Gas fee in USD |
|
||||
|
||||
## Output Format
|
||||
|
||||
### Pre-swap Confirmation
|
||||
|
||||
Before displaying the confirmation, run `order quote` to get the estimated output (uses normal auth — no private key required):
|
||||
Before displaying the confirmation, run `order quote` to get the estimated output (requires critical auth and `GMGN_PRIVATE_KEY` on every supported quote chain):
|
||||
|
||||
```bash
|
||||
gmgn-cli order quote \
|
||||
@@ -240,19 +440,127 @@ After a confirmed swap, display:
|
||||
```
|
||||
✅ Swap Confirmed
|
||||
|
||||
Spent: {filled_input_amount in human units} {input symbol}
|
||||
Received: {filled_output_amount in human units} {output symbol}
|
||||
Spent: {report.input_amount in human units} {input symbol}
|
||||
Received: {report.output_amount in human units} {output symbol}
|
||||
Tx: {explorer link for hash}
|
||||
Order ID: {order_id}
|
||||
```
|
||||
|
||||
Convert `filled_input_amount` and `filled_output_amount` from smallest unit using token decimals before displaying.
|
||||
Convert `report.input_amount` and `report.output_amount` from smallest unit using `report.input_token_decimals` and `report.output_token_decimals` before displaying.
|
||||
|
||||
## `order strategy create` Parameters
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` / `eth` |
|
||||
| `--from` | Yes | Wallet address (must match API Key binding) |
|
||||
| `--base-token` | Yes | Base token contract address |
|
||||
| `--quote-token` | Yes | Quote token contract address |
|
||||
| `--order-type` | Yes | Order type: `limit_order` |
|
||||
| `--sub-order-type` | Yes | Sub-order type: `buy_low` / `buy_high` / `stop_loss` / `take_profit` |
|
||||
| `--check-price` | Yes | Trigger check price |
|
||||
| `--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) — when triggered, sells a fixed token amount stored at strategy creation time; `hold_amount` — when triggered, sells a fixed percentage of the position held at trigger time |
|
||||
| `--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 gwei (BSC ≥ 0.05 gwei / BASE/ETH ≥ 0.01 gwei) |
|
||||
| `--anti-mev` | No | Enable anti-MEV protection |
|
||||
|
||||
|
||||
### `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` / `eth` |
|
||||
| `--type` | No | `open` (default) / `history` |
|
||||
| `--from` | No | Filter by wallet address |
|
||||
| `--group-tag` | Yes | Filter by order group: `LimitOrder` (limit orders only) / `STMix` (mixed strategy orders: take-profit, stop-loss, trailing take-profit, trailing stop-loss) |
|
||||
| `--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` / `eth` |
|
||||
| `--from` | Yes | Wallet address (must match API Key binding) |
|
||||
| `--order-id` | Yes | Order ID to cancel |
|
||||
| `--order-type` | No | Order type: `limit_order` (limit order) / `smart_trade` (mixed strategy order: take-profit, stop-loss, trailing take-profit, trailing stop-loss) |
|
||||
| `--close-sell-model` | No | Sell model when closing the order |
|
||||
|
||||
## `order strategy` Usage Examples
|
||||
|
||||
```bash
|
||||
# Create a take-profit order: sell when price rises to target
|
||||
gmgn-cli order strategy create \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--base-token <token_address> \
|
||||
--quote-token <sol_address> \
|
||||
--order-type limit_order \
|
||||
--sub-order-type take_profit \
|
||||
--check-price 0.002 \
|
||||
--amount-in 1000000 \
|
||||
--slippage 0.01
|
||||
|
||||
# Create a stop-loss order: sell when price drops to target
|
||||
gmgn-cli order strategy create \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--base-token <token_address> \
|
||||
--quote-token <sol_address> \
|
||||
--order-type limit_order \
|
||||
--sub-order-type stop_loss \
|
||||
--check-price 0.0005 \
|
||||
--amount-in-percent 100 \
|
||||
--slippage 0.01
|
||||
|
||||
# List open condition orders (profit_stop / loss_stop / trace types) — use STMix
|
||||
gmgn-cli order strategy list --chain sol --group-tag STMix
|
||||
|
||||
# List open limit orders (buy_low / buy_high / stop_loss / take_profit) — use LimitOrder
|
||||
gmgn-cli order strategy list --chain sol --group-tag LimitOrder
|
||||
|
||||
# List condition order history with pagination
|
||||
gmgn-cli order strategy list --chain sol --group-tag STMix --type history --limit 20
|
||||
|
||||
# Filter by token
|
||||
gmgn-cli order strategy list --chain sol --group-tag STMix --base-token <token_address>
|
||||
|
||||
# Cancel a strategy order
|
||||
gmgn-cli order strategy cancel \
|
||||
--chain sol \
|
||||
--from <wallet_address> \
|
||||
--order-id <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`, `order strategy list`, and `order strategy cancel` use critical auth (require `GMGN_PRIVATE_KEY`)
|
||||
- Use `--raw` to get single-line JSON for further processing
|
||||
|
||||
## Input Validation
|
||||
@@ -300,7 +608,7 @@ For full token research before swapping, see [`docs/workflow-token-research.md`]
|
||||
- **Percentage sell restriction** — `--percent` is ONLY valid when `input_token` is NOT a currency. Do NOT use `--percent` when `input_token` is SOL/BNB/ETH (native) or USDC. This includes: "sell 50% of my SOL", "use 30% of my BNB to buy X", "spend 50% of my USDC on X" — all unsupported. Explain the restriction to the user and ask for an explicit absolute amount instead.
|
||||
- **Chain-wallet compatibility** — SOL addresses are incompatible with EVM chains (bsc/base). Warn the user and abort if the address format does not match the chain.
|
||||
- **Credential sensitivity** — `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` can directly execute trades on the linked wallet. Never log, display, or expose these values.
|
||||
- **Order polling** — After a swap, if `status` is not yet `confirmed` / `failed` / `expired`, poll with `order get` up to 3 times at 5-second intervals before reporting a timeout. Once confirmed, display the trade result using `filled_input_amount` and `filled_output_amount` (convert from smallest unit using token decimals), e.g. "Spent 0.1 SOL → received 98.5 USDC" or "Sold 1000 TOKEN → received 0.08 SOL".
|
||||
- **Order polling** — After a swap, if `status` is not yet `confirmed` / `failed` / `expired`, poll with `order get` up to 3 times at 5-second intervals before reporting a timeout. Once confirmed, display the trade result using `report.input_amount` and `report.output_amount` (convert from smallest unit using `report.input_token_decimals` / `report.output_token_decimals`), e.g. "Spent 0.1 SOL → received 98.5 USDC" or "Sold 1000 TOKEN → received 0.08 SOL".
|
||||
- **Block explorer links** — After a successful swap, display a clickable explorer link for the returned `hash`:
|
||||
|
||||
| Chain | Explorer |
|
||||
|
||||
+117
-16
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: gmgn-token
|
||||
description: Query GMGN token information — basic info, security, pool, top holders and top traders. Supports sol / bsc / base.
|
||||
argument-hint: "<sub-command> --chain <sol|bsc|base> --address <token_address>"
|
||||
description: Research any crypto or meme token by address — real-time price, market cap, liquidity, holder list, trader list, top Smart Money and KOL positions, security audit (honeypot, rug pull risk, dev wallet, renounced status), social links (Twitter/X, website) via GMGN API on Solana, BSC, Base, or Ethereum. Use when user asks about a token's price, safety, holders, traders, smart money exposure, or wants due diligence before buying.
|
||||
argument-hint: "<sub-command> --chain <sol|bsc|base|eth> --address <token_address>"
|
||||
metadata:
|
||||
cliHelp: "gmgn-cli token --help"
|
||||
---
|
||||
@@ -17,7 +17,7 @@ Use the `gmgn-cli` tool to query token information based on the user's request.
|
||||
## Core Concepts
|
||||
|
||||
- **Token address** — The on-chain contract address that uniquely identifies a token on its chain. Required for all token sub-commands. Format: base58 (SOL) or `0x...` hex (BSC/Base).
|
||||
- **Chain** — The blockchain network: `sol` = Solana, `bsc` = BNB Smart Chain, `base` = Base (Coinbase L2).
|
||||
- **Chain** — The blockchain network: `sol` = Solana, `bsc` = BNB Smart Chain, `base` = Base (Coinbase L2), `eth` = Ethereum mainnet.
|
||||
- **Market cap** — Not returned directly by `token info`. Calculate as `price × circulating_supply` (both are top-level fields in the response, already in human-readable units).
|
||||
- **Liquidity** — USD value of token reserves in the main trading pool. Low liquidity (< $10k) means high price impact / slippage when buying or selling.
|
||||
- **Holder** — A wallet that currently holds the token. `token holders` returns wallets ranked by current balance.
|
||||
@@ -34,7 +34,7 @@ Use the `gmgn-cli` tool to query token information based on the user's request.
|
||||
|
||||
| Sub-command | Description |
|
||||
|-------------|-------------|
|
||||
| `token info` | Basic info + realtime price, liquidity, supply, holder count, social links (market cap = price × circulating_supply) |
|
||||
| `token info` | Basic info + realtime price, liquidity, market cap, total supply, holder count, social links (market cap = price × circulating_supply) |
|
||||
| `token security` | Security metrics (honeypot, taxes, holder concentration, contract risks) |
|
||||
| `token pool` | Liquidity pool info (DEX, reserves, liquidity depth) |
|
||||
| `token holders` | Top token holders list with profit/loss breakdown |
|
||||
@@ -42,19 +42,53 @@ Use the `gmgn-cli` tool to query token information based on the user's request.
|
||||
|
||||
## Supported Chains
|
||||
|
||||
`sol` / `bsc` / `base`
|
||||
`sol` / `bsc` / `base` / `eth`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `.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`
|
||||
- `gmgn-cli` installed globally — if missing, run: `npm install -g gmgn-cli`
|
||||
- `GMGN_API_KEY` configured in `~/.config/gmgn/.env`
|
||||
|
||||
## Rate Limit Handling
|
||||
|
||||
All token routes used by this skill go through GMGN's leaky-bucket limiter with `rate=10` and `capacity=10`. Sustained throughput is roughly `10 ÷ weight` requests/second, and the max burst is roughly `floor(10 ÷ weight)` when the bucket is full.
|
||||
|
||||
| Command | Route | Weight |
|
||||
|---------|-------|--------|
|
||||
| `token info` | `GET /v1/token/info` | 1 |
|
||||
| `token security` | `GET /v1/token/security` | 1 |
|
||||
| `token pool` | `GET /v1/token/pool_info` | 1 |
|
||||
| `token holders` | `GET /v1/market/token_top_holders` | 5 |
|
||||
| `token traders` | `GET /v1/market/token_top_traders` | 5 |
|
||||
|
||||
When a request returns `429`:
|
||||
|
||||
- Read `X-RateLimit-Reset` from the response headers. It is a Unix timestamp in seconds that marks when the limit is expected to reset.
|
||||
- If the response body contains `reset_at` (e.g., `{"code":429,"error":"RATE_LIMIT_BANNED","message":"...","reset_at":1775184222}`), extract `reset_at` — it is the Unix timestamp when the ban lifts (typically 5 minutes). Convert to local time and tell the user exactly when they can retry.
|
||||
- The CLI may wait and retry once automatically when the remaining cooldown is short. If it still fails, stop and tell the user the exact retry time instead of sending more requests.
|
||||
- For `RATE_LIMIT_EXCEEDED` or `RATE_LIMIT_BANNED`, repeated requests during the cooldown can extend the ban by 5 seconds each time, up to 5 minutes. Do not spam retries.
|
||||
|
||||
**First-time setup** (if `GMGN_API_KEY` is not configured):
|
||||
|
||||
1. Generate key pair and show the public key to the user:
|
||||
```bash
|
||||
openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
openssl pkey -in /tmp/gmgn_private.pem -pubout 2>/dev/null
|
||||
```
|
||||
Tell the user: *"This is your Ed25519 public key. Go to **https://gmgn.ai/ai**, paste it into the API key creation form, then send me the API Key value shown on the page."*
|
||||
|
||||
2. Wait for the user's API key, then configure:
|
||||
```bash
|
||||
mkdir -p ~/.config/gmgn
|
||||
echo 'GMGN_API_KEY=<key_from_user>' > ~/.config/gmgn/.env
|
||||
chmod 600 ~/.config/gmgn/.env
|
||||
```
|
||||
|
||||
## Parameters — `token info` / `token security` / `token pool`
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` |
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` / `eth` |
|
||||
| `--address` | Yes | Token contract address |
|
||||
| `--raw` | No | Output raw single-line JSON (for piping or further processing) |
|
||||
|
||||
@@ -62,12 +96,12 @@ Use the `gmgn-cli` tool to query token information based on the user's request.
|
||||
|
||||
| Parameter | Required | Default | Description |
|
||||
|-----------|----------|---------|-------------|
|
||||
| `--chain` | Yes | — | `sol` / `bsc` / `base` |
|
||||
| `--chain` | Yes | — | `sol` / `bsc` / `base` / `eth` |
|
||||
| `--address` | Yes | — | Token contract address |
|
||||
| `--limit` | No | `20` | Number of results, max `100` |
|
||||
| `--order-by` | No | `amount_percentage` | Sort field — see table below |
|
||||
| `--direction` | No | `desc` | Sort direction: `asc` / `desc` |
|
||||
| `--tag` | No | — | Wallet filter: `renowned` (KOL wallets) / `smart_degen` (smart money). Omit to return all wallets. |
|
||||
| `--tag` | No | — | Wallet filter: `smart_degen` / `renowned` / `fresh_wallet` / `dev` / `sniper` / `rat_trader` / `bundler` / `transfer_in` / `dex_bot` / `bluechip_owner`. Omit to return all wallets. |
|
||||
| `--raw` | No | — | Output raw single-line JSON |
|
||||
|
||||
### `--order-by` Values
|
||||
@@ -82,10 +116,18 @@ Use the `gmgn-cli` tool to query token information based on the user's request.
|
||||
|
||||
### `--tag` Values
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `renowned` | KOL / well-known wallets (influencers, funds, public figures) |
|
||||
| `smart_degen` | Smart money wallets (historically high-performing traders) |
|
||||
| Value | Description |
|
||||
| -------------- | ----------- |
|
||||
| `smart_degen` | Smart money wallets (historically high-performing traders) |
|
||||
| `renowned` | KOL / well-known wallets (influencers, funds, public figures) |
|
||||
| `fresh_wallet` | New wallets with no prior trading history |
|
||||
| `dev` | Token developer / creator wallets |
|
||||
| `sniper` | Wallets that sniped the token at launch |
|
||||
| `rat_trader` | Insider / sneak-trading wallets |
|
||||
| `bundler` | Bot-bundled buy wallets |
|
||||
| `transfer_in` | Wallets with a transfer-in record for this token |
|
||||
| `dex_bot` | DEX bot wallets (Axiom, Photon, BullX, Trojan, GMGN, Drops, PepeBoost, Padre) |
|
||||
| `bluechip_owner` | Wallets holding established bluechip tokens |
|
||||
|
||||
### `--tag` + `--order-by` Combination Guide
|
||||
|
||||
@@ -108,7 +150,7 @@ Recommended combinations for common use cases:
|
||||
|
||||
### `token info` — Key Fields
|
||||
|
||||
The response has four nested objects: `pool`, `link`, `stat`, `wallet_tags_stat`. Access fields with dot notation when parsing (e.g. `link.website`, `stat.top_10_holder_rate`).
|
||||
The response has five nested objects: `pool`, `dev`, `link`, `stat`, `wallet_tags_stat`. Access fields with dot notation when parsing (e.g. `link.website`, `stat.top_10_holder_rate`, `dev.creator_address`).
|
||||
|
||||
**Top-level Fields**
|
||||
|
||||
@@ -128,6 +170,15 @@ The response has four nested objects: `pool`, `link`, `stat`, `wallet_tags_stat`
|
||||
| `open_timestamp` | Time the token opened for trading (Unix seconds) |
|
||||
| `biggest_pool_address` | Address of the main liquidity pool |
|
||||
| `og` | Whether the token is flagged as an OG token (`true` / `false`) |
|
||||
| `launchpad` | Launchpad identifier (e.g. `pump`, `moonshot`) |
|
||||
| `launchpad_status` | Launchpad state: `0` = not opened, `1` = live, `2` = migrated |
|
||||
| `launchpad_progress` | Launchpad bonding-curve progress (0–1) |
|
||||
| `launchpad_platform` | Launchpad platform name |
|
||||
| `migrated_pool` | Pool address after migration |
|
||||
| `migration_market_cap` | Market cap at migration time (USD, float) |
|
||||
| `migration_market_cap_quote` | Quote currency for `migration_market_cap` |
|
||||
| `ath_price` | All-time-high price (USD, float) |
|
||||
| `locked_ratio` | Ratio of supply locked (0–1, float) |
|
||||
|
||||
**`pool` Object** — Main liquidity pool details
|
||||
|
||||
@@ -145,6 +196,38 @@ The response has four nested objects: `pool`, `link`, `stat`, `wallet_tags_stat`
|
||||
| `pool.fee_ratio` | Pool trading fee ratio (e.g. `0.1` = 0.1%) |
|
||||
| `pool.creation_timestamp` | Pool creation time (Unix seconds) |
|
||||
|
||||
**`dev` Object** — Token creator / developer info
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `dev.creator_address` | Creator wallet address |
|
||||
| `dev.creator_token_balance` | Creator's current token balance |
|
||||
| `dev.creator_token_status` | Creator holding status: `hold` (still holding) / `sell` (sold/exited) |
|
||||
| `dev.top_10_holder_rate` | Ratio of supply held by top 10 wallets (0–1) |
|
||||
| `dev.twitter_name_change_history` | Array of past Twitter username changes (each entry has `twitter_username`, `rename_timestamp`) |
|
||||
| `dev.dexscr_ad` | Creator bought a DEXScreener ad: `1` = yes, `0` = no |
|
||||
| `dev.dexscr_update_link` | Creator updated DEXScreener socials/links: `1` = yes, `0` = no |
|
||||
| `dev.dexscr_boost_fee` | Creator used DEXScreener Boost: `1` = yes, `0` = no |
|
||||
| `dev.dexscr_trending_bar` | Token appeared in DEXScreener trending bar: `1` = yes, `0` = no |
|
||||
| `dev.dexscr_ad_ts` | Timestamp of DEXScreener ad purchase (Unix seconds) |
|
||||
| `dev.dexscr_update_link_ts` | Timestamp of DEXScreener link update (Unix seconds) |
|
||||
| `dev.dexscr_boost_ts` | Timestamp of DEXScreener Boost (Unix seconds) |
|
||||
| `dev.dexscr_trending_bar_ts` | Timestamp of DEXScreener trending bar appearance (Unix seconds) |
|
||||
| `dev.cto_flag` | Token has been Community Takeover'd (original dev abandoned): `1` = yes, `0` = no |
|
||||
| `dev.fund_from` | Address that funded the creator wallet |
|
||||
| `dev.fund_from_ts` | Timestamp of that funding event (Unix seconds) |
|
||||
| `dev.creator_open_count` | Number of tokens this creator has previously launched |
|
||||
| `dev.twitter_del_post_token_count` | Number of posts the creator deleted from Twitter |
|
||||
| `dev.twitter_create_token_count` | Number of tokens the creator has promoted on Twitter |
|
||||
| `dev.offchain` | Whether the token is an offchain token |
|
||||
| `dev.ath_token_info` | Creator's all-time-high token info object (optional); see sub-fields below |
|
||||
| `dev.ath_token_info.ath_token` | Contract address of the creator's best-performing token ever |
|
||||
| `dev.ath_token_info.ath_mc` | All-time-high market cap of that token (USD, string) |
|
||||
| `dev.ath_token_info.avatar` | Token logo URL |
|
||||
| `dev.ath_token_info.symbol` | Token symbol |
|
||||
| `dev.ath_token_info.name` | Token name |
|
||||
| `dev.ath_token_info.creation_timestamp` | Token creation time (Unix seconds) |
|
||||
|
||||
**`link` Object** — Social and explorer links
|
||||
|
||||
| Field | Description |
|
||||
@@ -178,6 +261,7 @@ The response has four nested objects: `pool`, `link`, `stat`, `wallet_tags_stat`
|
||||
| `stat.bot_degen_count` | Number of bot degen wallets |
|
||||
| `stat.bot_degen_rate` | Ratio of bot degen wallets |
|
||||
| `stat.fresh_wallet_rate` | Ratio of fresh/new wallets among holders |
|
||||
| `stat.private_vault_hold_rate` | Ratio held by private vault (vanish) addresses — displayed as "vanish" in GMGN UI (0–1) |
|
||||
|
||||
**`wallet_tags_stat` Object** — Wallet type breakdown
|
||||
|
||||
@@ -363,6 +447,9 @@ gmgn-cli token info --chain bsc --address 0x2170Ed0880ac9A755fd29B2688956BD959F9
|
||||
# Get basic info for a Base token
|
||||
gmgn-cli token info --chain base --address 0x4200000000000000000000000000000000000006
|
||||
|
||||
# Get basic info for an ETH token
|
||||
gmgn-cli token info --chain eth --address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
|
||||
|
||||
# Raw JSON output for downstream processing
|
||||
gmgn-cli token info --chain sol --address EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v --raw
|
||||
```
|
||||
@@ -379,6 +466,9 @@ gmgn-cli token security --chain bsc --address 0x2170Ed0880ac9A755fd29B2688956BD9
|
||||
# Check a Base token for tax, rug ratio, and insider concentration
|
||||
gmgn-cli token security --chain base --address 0x4200000000000000000000000000000000000006
|
||||
|
||||
# Check an ETH token for honeypot and contract risks
|
||||
gmgn-cli token security --chain eth --address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
|
||||
|
||||
# Raw output for parsing key fields (e.g. is_honeypot, buy_tax, rug_ratio)
|
||||
gmgn-cli token security --chain bsc --address 0x2170Ed0880ac9A755fd29B2688956BD959F933F8 --raw
|
||||
```
|
||||
@@ -391,6 +481,9 @@ gmgn-cli token pool --chain sol --address EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZw
|
||||
|
||||
# Get pool info for a BSC token
|
||||
gmgn-cli token pool --chain bsc --address 0x2170Ed0880ac9A755fd29B2688956BD959F933F8
|
||||
|
||||
# Get pool info for an ETH token
|
||||
gmgn-cli token pool --chain eth --address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
|
||||
```
|
||||
|
||||
### `token holders` — Analyze Holder Distribution
|
||||
@@ -427,6 +520,10 @@ gmgn-cli token holders --chain sol --address EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGG
|
||||
gmgn-cli token holders --chain bsc --address 0x2170Ed0880ac9A755fd29B2688956BD959F933F8 \
|
||||
--tag renowned --order-by profit --direction desc --limit 50
|
||||
|
||||
# ETH token holders — smart money by supply percentage
|
||||
gmgn-cli token holders --chain eth --address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
|
||||
--tag smart_degen --order-by amount_percentage --direction desc --limit 20
|
||||
|
||||
# Raw output for downstream analysis
|
||||
gmgn-cli token holders --chain sol --address EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v \
|
||||
--limit 100 --raw
|
||||
@@ -475,6 +572,10 @@ gmgn-cli token traders --chain sol --address EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGG
|
||||
# BSC token traders by profit
|
||||
gmgn-cli token traders --chain bsc --address 0x2170Ed0880ac9A755fd29B2688956BD959F933F8 \
|
||||
--tag smart_degen --order-by profit --direction desc --limit 50
|
||||
|
||||
# ETH token traders by profit
|
||||
gmgn-cli token traders --chain eth --address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
|
||||
--tag smart_degen --order-by profit --direction desc --limit 50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
+46
-13
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: gmgn-track
|
||||
description: Query GMGN on-chain tracking data — follow-wallet trade records, KOL trades, and Smart Money trades. Supports sol / bsc / base.
|
||||
argument-hint: "<follow-wallet|kol|smartmoney> [--chain <sol|bsc|base>] [--wallet <wallet_address>]"
|
||||
description: Get real-time crypto buy/sell activity from Smart Money wallets, KOL influencer wallets, and personally followed wallets via GMGN API — alpha signals, whale tracking, meme token copy-trading ideas on Solana, BSC, Base, or Ethereum. Use when user asks what smart money or KOLs are buying, wants whale alerts, on-chain alpha, or copy-trade signals. (For a specific wallet address, use gmgn-portfolio.)
|
||||
argument-hint: "<follow-wallet|kol|smartmoney> --chain <sol|bsc|base|eth> [--wallet <wallet_address>]"
|
||||
metadata:
|
||||
cliHelp: "gmgn-cli track --help"
|
||||
---
|
||||
@@ -16,7 +16,7 @@ Use the `gmgn-cli` tool to query on-chain tracking data based on the user's requ
|
||||
|
||||
## Core Concepts
|
||||
|
||||
- **`follow-wallet` vs `kol` vs `smartmoney`** — Three distinct data sources. `follow-wallet` returns trades from wallets the user has personally followed on the GMGN platform (user-specific, requires private key). `kol` and `smartmoney` return trades from platform-tagged public wallet lists (not user-specific, API Key only). Never substitute one for another.
|
||||
- **`follow-wallet` vs `kol` vs `smartmoney`** — Three distinct data sources. `follow-wallet` returns trades from wallets the user has personally followed on the GMGN platform (user-specific; the follow list is resolved from the GMGN user account bound to the API Key). `kol` and `smartmoney` return trades from platform-tagged public wallet lists (not user-specific). Never substitute one for another.
|
||||
|
||||
- **KOL (Key Opinion Leader)** — Wallets publicly identified as influencers or well-known traders on GMGN. Tagged as `renowned` in the platform's wallet label system. Their trades carry social/marketing signal, not necessarily alpha.
|
||||
|
||||
@@ -55,14 +55,48 @@ Use the `gmgn-cli` tool to query on-chain tracking data based on the user's requ
|
||||
|
||||
## Supported Chains
|
||||
|
||||
`sol` / `bsc` / `base`
|
||||
`sol` / `bsc` / `base` / `eth`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `.env` file with `GMGN_API_KEY` set
|
||||
- `GMGN_PRIVATE_KEY` required for `track follow-wallet` (signature auth); not needed for `track kol` / `track smartmoney`
|
||||
- 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`
|
||||
- `gmgn-cli` installed globally — if missing, run: `npm install -g gmgn-cli`
|
||||
- `GMGN_API_KEY` configured in `~/.config/gmgn/.env` — required for all sub-commands
|
||||
- `GMGN_PRIVATE_KEY` — required for `track follow-wallet` only (critical auth); not needed for `kol` or `smartmoney`
|
||||
|
||||
## Rate Limit Handling
|
||||
|
||||
All tracking routes used by this skill go through GMGN's leaky-bucket limiter with `rate=10` and `capacity=10`. Sustained throughput is roughly `10 ÷ weight` requests/second, and the max burst is roughly `floor(10 ÷ weight)` when the bucket is full.
|
||||
|
||||
| Command | Route | Weight |
|
||||
|---------|-------|--------|
|
||||
| `track follow-wallet` | `GET /v1/trade/follow_wallet` | 3 |
|
||||
| `track kol` | `GET /v1/user/kol` | 1 |
|
||||
| `track smartmoney` | `GET /v1/user/smartmoney` | 1 |
|
||||
|
||||
When a request returns `429`:
|
||||
|
||||
- Read `X-RateLimit-Reset` from the response headers. It is a Unix timestamp in seconds that marks when the limit is expected to reset.
|
||||
- If the response body contains `reset_at` (e.g., `{"code":429,"error":"RATE_LIMIT_BANNED","message":"...","reset_at":1775184222}`), extract `reset_at` — it is the Unix timestamp when the ban lifts (typically 5 minutes). Convert to local time and tell the user exactly when they can retry.
|
||||
- The CLI may wait and retry once automatically when the remaining cooldown is short. If it still fails, stop and tell the user the exact retry time instead of sending more requests.
|
||||
- For `RATE_LIMIT_EXCEEDED` or `RATE_LIMIT_BANNED`, repeated requests during the cooldown can extend the ban by 5 seconds each time, up to 5 minutes. Do not spam retries.
|
||||
|
||||
**First-time setup** (if `GMGN_API_KEY` is not configured):
|
||||
|
||||
1. Generate key pair and show the public key to the user:
|
||||
```bash
|
||||
openssl genpkey -algorithm ed25519 -out /tmp/gmgn_private.pem 2>/dev/null && \
|
||||
openssl pkey -in /tmp/gmgn_private.pem -pubout 2>/dev/null
|
||||
```
|
||||
Tell the user: *"This is your Ed25519 public key. Go to **https://gmgn.ai/ai**, paste it into the API key creation form, then send me the API Key value shown on the page."*
|
||||
|
||||
2. Wait for the user's API key, then configure (saves both API key and private key — private key is required for `track follow-wallet`):
|
||||
```bash
|
||||
mkdir -p ~/.config/gmgn
|
||||
echo "GMGN_API_KEY=<key_from_user>" > ~/.config/gmgn/.env
|
||||
echo "GMGN_PRIVATE_KEY=$(awk '{printf "%s\\n", $0}' /tmp/gmgn_private.pem)" >> ~/.config/gmgn/.env
|
||||
chmod 600 ~/.config/gmgn/.env
|
||||
rm /tmp/gmgn_private.pem
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
@@ -96,7 +130,7 @@ gmgn-cli track smartmoney --chain sol --side sell --limit 10 --raw
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--chain` | Required. `sol` / `bsc` / `base` |
|
||||
| `--chain` | Required. `sol` / `bsc` / `base` / `eth` |
|
||||
| `--wallet <address>` | Filter by wallet address |
|
||||
| `--limit <n>` | Page size (1–100, default 10) |
|
||||
| `--side <side>` | Trade direction: `buy` / `sell` |
|
||||
@@ -108,7 +142,7 @@ gmgn-cli track smartmoney --chain sol --side sell --limit 10 --raw
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--chain <chain>` | Chain: `sol` / `bsc` / `base` (default `sol`) |
|
||||
| `--chain <chain>` | Required. Chain: `sol` / `bsc` / `base` / `eth` |
|
||||
| `--limit <n>` | Page size (1–200, default 100) |
|
||||
| `--side <side>` | Filter by trade direction: `buy` / `sell` (client-side filter — applied locally after fetching results) |
|
||||
|
||||
@@ -272,13 +306,12 @@ To research any token surfaced by smart money activity, follow [`docs/workflow-t
|
||||
|
||||
## Safety Constraints
|
||||
|
||||
- **`track follow-wallet` requires `GMGN_PRIVATE_KEY`** — this signing key is linked to your GMGN account. It is used for authentication only (no on-chain access), but must be protected like any credential. Never expose it in logs or command output.
|
||||
- **`follow-wallet` reveals your following list** — results expose which wallets you have followed on GMGN. Do not share raw output in public channels.
|
||||
- **`track kol` / `track smartmoney` expose no personal data** — these use API Key auth only and return platform-tagged public wallet activity. Safe to share raw output.
|
||||
|
||||
## Notes
|
||||
|
||||
- `track kol` / `track smartmoney` use normal auth (API Key only, no signature required)
|
||||
- `track follow-wallet` requires `GMGN_PRIVATE_KEY` for signature auth — and wallets must be followed via the GMGN platform first
|
||||
- `track follow-wallet` uses critical auth (API Key + private key signature); `track kol` and `track smartmoney` use normal auth (API Key only)
|
||||
- `track follow-wallet` returns trades from wallets followed on the GMGN platform; the follow list is resolved automatically from the GMGN user account bound to the API Key — `--wallet` is optional
|
||||
- Use `--raw` to get single-line JSON for further processing
|
||||
- `track kol` / `track smartmoney` `--side` is a **client-side filter** — the CLI fetches all results then filters locally; it is NOT sent to the API
|
||||
|
||||
+383
-41
@@ -3,11 +3,62 @@
|
||||
*
|
||||
* Auth modes:
|
||||
* Normal (market/token/portfolio): X-APIKEY + timestamp + client_id
|
||||
* Critical (swap/order): normal auth + X-Signature (private key signature)
|
||||
* Critical (swap and order routes): normal auth + X-Signature (private key signature)
|
||||
*/
|
||||
|
||||
import { buildAuthQuery, buildMessage, detectAlgorithm, sign } from "./signer.js";
|
||||
|
||||
const RATE_LIMIT_RETRY_BUFFER_MS = 1000;
|
||||
const DEFAULT_RATE_LIMIT_AUTO_RETRY_MAX_WAIT_MS = 5000;
|
||||
|
||||
interface PreparedRequest {
|
||||
method: string;
|
||||
subPath: string;
|
||||
url: string;
|
||||
headers: Record<string, string>;
|
||||
body: string | null;
|
||||
curlStr: string;
|
||||
}
|
||||
|
||||
interface ResponseEnvelope {
|
||||
code: number | string;
|
||||
data?: unknown;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface OpenApiErrorParams {
|
||||
method: string;
|
||||
path: string;
|
||||
status: number;
|
||||
apiCode?: number | string;
|
||||
apiError?: string;
|
||||
apiMessage?: string;
|
||||
resetAtUnix?: number;
|
||||
}
|
||||
|
||||
class OpenApiError extends Error {
|
||||
readonly method: string;
|
||||
readonly path: string;
|
||||
readonly status: number;
|
||||
readonly apiCode?: number | string;
|
||||
readonly apiError?: string;
|
||||
readonly apiMessage?: string;
|
||||
readonly resetAtUnix?: number;
|
||||
|
||||
constructor(params: OpenApiErrorParams) {
|
||||
super(buildOpenApiErrorMessage(params));
|
||||
this.name = "OpenApiError";
|
||||
this.method = params.method;
|
||||
this.path = params.path;
|
||||
this.status = params.status;
|
||||
this.apiCode = params.apiCode;
|
||||
this.apiError = params.apiError;
|
||||
this.apiMessage = params.apiMessage;
|
||||
this.resetAtUnix = params.resetAtUnix;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
apiKey: string;
|
||||
privateKeyPem?: string;
|
||||
@@ -34,6 +85,110 @@ export interface SwapParams {
|
||||
gas_price?: string;
|
||||
max_fee_per_gas?: string;
|
||||
max_priority_fee_per_gas?: string;
|
||||
condition_orders?: StrategyConditionOrder[];
|
||||
sell_ratio_type?: string;
|
||||
}
|
||||
|
||||
export interface StrategyConditionOrder {
|
||||
order_type: string; // "profit_stop" | "loss_stop" | "profit_stop_trace" | "loss_stop_trace"
|
||||
side: string; // "sell"
|
||||
price_scale?: string;
|
||||
sell_ratio: string;
|
||||
drawdown_rate?: string;
|
||||
}
|
||||
|
||||
export interface MultiSwapParams {
|
||||
chain: string;
|
||||
accounts: string[];
|
||||
input_token: string;
|
||||
output_token: string;
|
||||
input_amount?: Record<string, string>;
|
||||
input_amount_bps?: Record<string, string>;
|
||||
output_amount?: Record<string, string>;
|
||||
swap_mode?: string;
|
||||
slippage?: number;
|
||||
auto_slippage?: boolean;
|
||||
is_anti_mev?: boolean;
|
||||
priority_fee?: string;
|
||||
tip_fee?: string;
|
||||
auto_tip_fee?: boolean;
|
||||
max_auto_fee?: string;
|
||||
gas_price?: string;
|
||||
max_fee_per_gas?: string;
|
||||
max_priority_fee_per_gas?: string;
|
||||
condition_orders?: StrategyConditionOrder[];
|
||||
sell_ratio_type?: string;
|
||||
}
|
||||
|
||||
export interface StrategyCreateParams {
|
||||
chain: string;
|
||||
from_address: string;
|
||||
base_token: string;
|
||||
quote_token: string;
|
||||
order_type: string;
|
||||
sub_order_type: string;
|
||||
check_price: string;
|
||||
open_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;
|
||||
order_type?: string;
|
||||
close_sell_model?: string;
|
||||
}
|
||||
|
||||
export interface TokenSignalGroup {
|
||||
signal_type?: number[];
|
||||
mc_min?: number;
|
||||
mc_max?: number;
|
||||
trigger_mc_min?: number;
|
||||
trigger_mc_max?: number;
|
||||
total_fee_min?: number;
|
||||
total_fee_max?: number;
|
||||
min_create_or_open_ts?: string;
|
||||
max_create_or_open_ts?: 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 {
|
||||
@@ -126,8 +281,8 @@ export class OpenApiClient {
|
||||
return this.normalRequest("GET", "/v1/user/wallet_token_balance", { chain, wallet_address: walletAddress, token_address: tokenAddress });
|
||||
}
|
||||
|
||||
async getTrenches(chain: string, types?: string[], platforms?: string[], limit?: number): Promise<unknown> {
|
||||
const body = buildTrenchesBody(chain, types, platforms, limit);
|
||||
async getTrenches(chain: string, types?: string[], platforms?: string[], limit?: number, filters?: Record<string, number | string>): Promise<unknown> {
|
||||
const body = buildTrenchesBody(chain, types, platforms, limit, filters);
|
||||
return this.normalRequest("POST", "/v1/trenches", { chain }, body);
|
||||
}
|
||||
|
||||
@@ -141,6 +296,10 @@ export class OpenApiClient {
|
||||
return this.normalRequest("GET", "/v1/market/rank", { chain, interval, ...extra });
|
||||
}
|
||||
|
||||
async getTokenSignalV2(chain: string, groups: TokenSignalGroup[]): Promise<unknown> {
|
||||
return this.normalRequest("POST", "/v1/market/token_signal", {}, { chain, groups });
|
||||
}
|
||||
|
||||
// ---- User endpoints (normal auth) ----
|
||||
|
||||
async getUserInfo(): Promise<unknown> {
|
||||
@@ -165,6 +324,10 @@ export class OpenApiClient {
|
||||
return this.normalRequest("GET", "/v1/user/smartmoney", query);
|
||||
}
|
||||
|
||||
async getCreatedTokens(chain: string, walletAddress: string, extra: Record<string, string | number> = {}): Promise<unknown> {
|
||||
return this.normalRequest("GET", "/v1/user/created_tokens", { chain, wallet_address: walletAddress, ...extra });
|
||||
}
|
||||
|
||||
async quoteOrder(
|
||||
chain: string,
|
||||
from_address: string,
|
||||
@@ -173,9 +336,8 @@ export class OpenApiClient {
|
||||
input_amount: string,
|
||||
slippage: number
|
||||
): Promise<unknown> {
|
||||
return this.normalRequest("GET", "/v1/trade/quote", {
|
||||
chain, from_address, input_token, output_token, input_amount, slippage,
|
||||
});
|
||||
const query = { chain, from_address, input_token, output_token, input_amount, slippage };
|
||||
return this.criticalRequest("GET", "/v1/trade/quote", query, null);
|
||||
}
|
||||
|
||||
// ---- Swap endpoints (critical auth) ----
|
||||
@@ -184,10 +346,38 @@ export class OpenApiClient {
|
||||
return this.criticalRequest("POST", "/v1/trade/swap", {}, params);
|
||||
}
|
||||
|
||||
async multiSwap(params: MultiSwapParams): Promise<unknown> {
|
||||
return this.criticalRequest("POST", "/v1/trade/multi_swap", {}, params);
|
||||
}
|
||||
|
||||
async queryOrder(orderId: string, chain: string): Promise<unknown> {
|
||||
return this.criticalRequest("GET", "/v1/trade/query_order", { order_id: orderId, chain }, null);
|
||||
}
|
||||
|
||||
// ---- Strategy order endpoints (critical auth) ----
|
||||
|
||||
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.criticalRequest("GET", "/v1/trade/strategy/orders", { chain, ...extra }, null);
|
||||
}
|
||||
|
||||
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 ----
|
||||
|
||||
private async normalRequest(
|
||||
@@ -196,46 +386,95 @@ export class OpenApiClient {
|
||||
queryExtra: Record<string, string | number | string[]>,
|
||||
body: unknown = null
|
||||
): Promise<unknown> {
|
||||
const { timestamp, client_id } = buildAuthQuery();
|
||||
const query: Record<string, string | number | string[]> = { ...queryExtra, timestamp, client_id };
|
||||
|
||||
const url = buildUrl(`${this.host}${subPath}`, query);
|
||||
const headers: Record<string, string> = {
|
||||
"X-APIKEY": this.apiKey,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
const bodyStr = body !== null ? JSON.stringify(body) : null;
|
||||
const curlStr = formatCurl(method, url, headers, bodyStr);
|
||||
const res = await this.doFetch(method, subPath, url, headers, bodyStr, curlStr);
|
||||
return this.parseResponse(method, subPath, res, curlStr);
|
||||
return this.executePreparedRequest(() => {
|
||||
const { timestamp, client_id } = buildAuthQuery();
|
||||
const query: Record<string, string | number | string[]> = { ...queryExtra, timestamp, client_id };
|
||||
const url = buildUrl(`${this.host}${subPath}`, query);
|
||||
const headers: Record<string, string> = {
|
||||
"X-APIKEY": this.apiKey,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
const bodyStr = body !== null ? JSON.stringify(body) : null;
|
||||
return {
|
||||
method,
|
||||
subPath,
|
||||
url,
|
||||
headers,
|
||||
body: bodyStr,
|
||||
curlStr: formatCurl(method, url, headers, bodyStr),
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
|
||||
private async criticalRequest(
|
||||
method: string,
|
||||
subPath: string,
|
||||
queryExtra: Record<string, string | number>,
|
||||
queryExtra: Record<string, string | number | string[]>,
|
||||
body: unknown
|
||||
): Promise<unknown> {
|
||||
if (!this.privateKeyPem) {
|
||||
throw new Error("GMGN_PRIVATE_KEY is required for swap/order commands");
|
||||
throw new Error("GMGN_PRIVATE_KEY is required for critical-auth commands (swap, order, and follow-wallet commands)");
|
||||
}
|
||||
|
||||
const { timestamp, client_id } = buildAuthQuery();
|
||||
const query: Record<string, string | number> = { ...queryExtra, timestamp, client_id };
|
||||
return this.executePreparedRequest(() => {
|
||||
const { timestamp, client_id } = buildAuthQuery();
|
||||
const query: Record<string, string | number | string[]> = { ...queryExtra, timestamp, client_id };
|
||||
const bodyStr = body !== null ? JSON.stringify(body) : "";
|
||||
const message = buildMessage(subPath, query, bodyStr, timestamp);
|
||||
const signature = sign(message, this.privateKeyPem!, detectAlgorithm(this.privateKeyPem!));
|
||||
|
||||
const bodyStr = body !== null ? JSON.stringify(body) : "";
|
||||
const message = buildMessage(subPath, query, bodyStr, timestamp);
|
||||
const signature = sign(message, this.privateKeyPem, detectAlgorithm(this.privateKeyPem));
|
||||
const url = buildUrl(`${this.host}${subPath}`, query);
|
||||
const headers: Record<string, string> = {
|
||||
"X-APIKEY": this.apiKey,
|
||||
"X-Signature": signature,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
return {
|
||||
method,
|
||||
subPath,
|
||||
url,
|
||||
headers,
|
||||
body: bodyStr || null,
|
||||
curlStr: formatCurl(method, url, headers, bodyStr || null),
|
||||
};
|
||||
}, method !== "POST");
|
||||
}
|
||||
|
||||
const url = buildUrl(`${this.host}${subPath}`, query);
|
||||
const headers: Record<string, string> = {
|
||||
"X-APIKEY": this.apiKey,
|
||||
"X-Signature": signature,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
const curlStr = formatCurl(method, url, headers, bodyStr || null);
|
||||
const res = await this.doFetch(method, subPath, url, headers, bodyStr || null, curlStr);
|
||||
return this.parseResponse(method, subPath, res, curlStr);
|
||||
private async executePreparedRequest(
|
||||
prepare: () => PreparedRequest,
|
||||
autoRetryOnRateLimit: boolean
|
||||
): Promise<unknown> {
|
||||
const maxAttempts = autoRetryOnRateLimit ? 2 : 1;
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
||||
const request = prepare();
|
||||
const res = await this.doFetch(
|
||||
request.method,
|
||||
request.subPath,
|
||||
request.url,
|
||||
request.headers,
|
||||
request.body,
|
||||
request.curlStr
|
||||
);
|
||||
|
||||
try {
|
||||
return this.parseResponse(request.method, request.subPath, res, request.curlStr);
|
||||
} catch (err) {
|
||||
const retryDelayMs = getRateLimitRetryDelayMs(err, attempt, maxAttempts, autoRetryOnRateLimit);
|
||||
if (retryDelayMs == null) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (process.env.GMGN_DEBUG) {
|
||||
console.error(
|
||||
`[gmgn-cli] ${request.method} ${request.subPath} hit rate limit, retrying once in ${Math.ceil(retryDelayMs / 1000)}s`
|
||||
);
|
||||
}
|
||||
await sleep(retryDelayMs);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("Unexpected retry loop exit");
|
||||
}
|
||||
|
||||
private async doFetch(
|
||||
@@ -278,6 +517,8 @@ export class OpenApiClient {
|
||||
throw new Error(msg);
|
||||
};
|
||||
|
||||
const resetAtUnix = parseRateLimitReset(res.headers.get("x-ratelimit-reset"));
|
||||
|
||||
let text!: string;
|
||||
try {
|
||||
text = await res.text();
|
||||
@@ -285,7 +526,7 @@ export class OpenApiClient {
|
||||
fail(`${method} ${path} failed: HTTP ${res.status} (failed to read response body: ${err})`);
|
||||
}
|
||||
|
||||
let json!: { code: number | string; data?: unknown; message?: string; error?: string };
|
||||
let json!: ResponseEnvelope;
|
||||
try {
|
||||
json = JSON.parse(text);
|
||||
} catch {
|
||||
@@ -293,16 +534,116 @@ export class OpenApiClient {
|
||||
}
|
||||
|
||||
if (json.code !== 0) {
|
||||
fail(
|
||||
`${method} ${path} failed: HTTP ${res.status} code=${json.code} error=${json.error ?? ""} message=${json.message ?? ""}`,
|
||||
text
|
||||
);
|
||||
if (process.env.GMGN_DEBUG) {
|
||||
console.error(`${curlStr}\n${formatResponse(res, text)}`);
|
||||
}
|
||||
throw new OpenApiError({
|
||||
method,
|
||||
path,
|
||||
status: res.status,
|
||||
apiCode: json.code,
|
||||
apiError: json.error,
|
||||
apiMessage: json.message,
|
||||
resetAtUnix,
|
||||
});
|
||||
}
|
||||
|
||||
return json.data;
|
||||
}
|
||||
}
|
||||
|
||||
function getRateLimitRetryDelayMs(
|
||||
err: unknown,
|
||||
attempt: number,
|
||||
maxAttempts: number,
|
||||
autoRetryOnRateLimit: boolean
|
||||
): number | null {
|
||||
if (!autoRetryOnRateLimit || attempt >= maxAttempts) {
|
||||
return null;
|
||||
}
|
||||
if (!(err instanceof OpenApiError)) {
|
||||
return null;
|
||||
}
|
||||
if (err.apiError !== "RATE_LIMIT_EXCEEDED" && err.apiError !== "RATE_LIMIT_BANNED") {
|
||||
return null;
|
||||
}
|
||||
if (err.resetAtUnix == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const waitMs = Math.max(err.resetAtUnix * 1000 - Date.now(), 0) + RATE_LIMIT_RETRY_BUFFER_MS;
|
||||
return waitMs <= getAutoRetryMaxWaitMs() ? waitMs : null;
|
||||
}
|
||||
|
||||
function parseRateLimitReset(raw: string | null): number | undefined {
|
||||
if (raw == null || raw.trim() === "") {
|
||||
return undefined;
|
||||
}
|
||||
const parsed = Number.parseInt(raw, 10);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
||||
}
|
||||
|
||||
function getAutoRetryMaxWaitMs(): number {
|
||||
const raw = process.env.GMGN_RATE_LIMIT_AUTO_RETRY_MAX_WAIT_MS;
|
||||
if (!raw) {
|
||||
return DEFAULT_RATE_LIMIT_AUTO_RETRY_MAX_WAIT_MS;
|
||||
}
|
||||
const parsed = Number.parseInt(raw, 10);
|
||||
return Number.isFinite(parsed) && parsed >= 0 ? parsed : DEFAULT_RATE_LIMIT_AUTO_RETRY_MAX_WAIT_MS;
|
||||
}
|
||||
|
||||
function buildOpenApiErrorMessage(params: OpenApiErrorParams): string {
|
||||
const parts = [`${params.method} ${params.path} failed: HTTP ${params.status}`];
|
||||
if (params.apiCode != null) parts.push(`code=${params.apiCode}`);
|
||||
if (params.apiError) parts.push(`error=${params.apiError}`);
|
||||
if (params.apiMessage) parts.push(`message=${params.apiMessage}`);
|
||||
|
||||
let message = parts.join(" ");
|
||||
|
||||
if (params.status !== 429) {
|
||||
return message;
|
||||
}
|
||||
|
||||
const resetText = params.resetAtUnix != null
|
||||
? formatRateLimitReset(params.resetAtUnix)
|
||||
: "an unknown time";
|
||||
|
||||
if (params.apiError === "ERROR_RATE_LIMIT_BLOCKED") {
|
||||
return `${message}. Repeated business errors triggered a temporary block until ${resetText}. Fix the underlying request before retrying.`;
|
||||
}
|
||||
|
||||
if (params.apiError === "RATE_LIMIT_EXCEEDED" || params.apiError === "RATE_LIMIT_BANNED") {
|
||||
return `${message}. Rate limit resets at ${resetText}. Stop sending requests before then; repeated requests can extend the ban by 5s up to 5 minutes.`;
|
||||
}
|
||||
|
||||
return `${message}. Received HTTP 429; retry after ${resetText}.`;
|
||||
}
|
||||
|
||||
function formatRateLimitReset(resetAtUnix: number): string {
|
||||
const resetAt = new Date(resetAtUnix * 1000);
|
||||
const remainingSeconds = Math.max(Math.ceil((resetAt.getTime() - Date.now()) / 1000), 0);
|
||||
return `${formatLocalTimestamp(resetAt)} (~${remainingSeconds}s remaining)`;
|
||||
}
|
||||
|
||||
function formatLocalTimestamp(date: Date): string {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
const hours = String(date.getHours()).padStart(2, "0");
|
||||
const minutes = String(date.getMinutes()).padStart(2, "0");
|
||||
const seconds = String(date.getSeconds()).padStart(2, "0");
|
||||
const offsetMinutes = -date.getTimezoneOffset();
|
||||
const sign = offsetMinutes >= 0 ? "+" : "-";
|
||||
const absOffsetMinutes = Math.abs(offsetMinutes);
|
||||
const offsetHours = String(Math.floor(absOffsetMinutes / 60)).padStart(2, "0");
|
||||
const offsetMins = String(absOffsetMinutes % 60).padStart(2, "0");
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} GMT${sign}${offsetHours}:${offsetMins}`;
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function formatResponse(res: Response, body: string | null): string {
|
||||
const headerLines = [...res.headers.entries()].map(([k, v]) => ` ${k}: ${v}`).join("\n");
|
||||
return `[response] HTTP ${res.status}\n${headerLines}\n\n${body ?? "(no body)"}`;
|
||||
@@ -342,17 +683,18 @@ const TRENCHES_QUOTE_ADDRESS_TYPES: Record<string, number[]> = {
|
||||
base: [11, 3, 12, 13, 0],
|
||||
};
|
||||
|
||||
function buildTrenchesBody(chain: string, types?: string[], platforms?: string[], limit?: number): Record<string, unknown> {
|
||||
function buildTrenchesBody(chain: string, types?: string[], platforms?: string[], limit?: number, filters?: Record<string, number | string>): Record<string, unknown> {
|
||||
const selectedTypes = types?.length ? types : ["new_creation", "near_completion", "completed"];
|
||||
const launchpad_platform = platforms?.length ? platforms : (TRENCHES_PLATFORMS[chain] ?? []);
|
||||
const quote_address_type = TRENCHES_QUOTE_ADDRESS_TYPES[chain] ?? [];
|
||||
const actualLimit = limit ?? 80;
|
||||
const section = {
|
||||
const section: Record<string, unknown> = {
|
||||
filters: ["offchain", "onchain"],
|
||||
launchpad_platform,
|
||||
quote_address_type,
|
||||
launchpad_platform_v2: true,
|
||||
limit: actualLimit,
|
||||
...filters,
|
||||
};
|
||||
const body: Record<string, unknown> = { version: "v2" };
|
||||
for (const type of selectedTypes) {
|
||||
|
||||
+10
-3
@@ -32,17 +32,24 @@ export function buildAuthQuery(): { timestamp: number; client_id: string } {
|
||||
/**
|
||||
* Build the signature message (critical auth)
|
||||
* Format: {sub_path}:{sorted_query_string}:{request_body}:{timestamp}
|
||||
* sorted_query_string: all query params (including timestamp, client_id) sorted alphabetically by key
|
||||
* sorted_query_string: all query params (including timestamp, client_id) sorted alphabetically by key.
|
||||
* Array values are serialized as repeated k=v pairs (same as buildUrl / URLSearchParams), sorted by value.
|
||||
*/
|
||||
export function buildMessage(
|
||||
subPath: string,
|
||||
queryParams: Record<string, string | number>,
|
||||
queryParams: Record<string, string | number | string[]>,
|
||||
body: string,
|
||||
timestamp: number
|
||||
): string {
|
||||
const sortedQs = Object.keys(queryParams)
|
||||
.sort()
|
||||
.map((k) => `${k}=${queryParams[k]}`)
|
||||
.flatMap((k) => {
|
||||
const v = queryParams[k];
|
||||
if (Array.isArray(v)) {
|
||||
return [...v].sort().map((item) => `${k}=${item}`);
|
||||
}
|
||||
return [`${k}=${v}`];
|
||||
})
|
||||
.join("&");
|
||||
return `${subPath}:${sortedQs}:${body}:${timestamp}`;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
+262
-8
@@ -1,16 +1,32 @@
|
||||
import { Command } from "commander";
|
||||
import { OpenApiClient } from "../client/OpenApiClient.js";
|
||||
import { OpenApiClient, TokenSignalGroup } from "../client/OpenApiClient.js";
|
||||
import { getConfig } from "../config.js";
|
||||
import { exitOnError, printResult } from "../output.js";
|
||||
import { validateAddress, validateChain } from "../validate.js";
|
||||
|
||||
// Parse token age string. If a unit suffix is present (s/m), use it as-is.
|
||||
// Bare numbers (no unit) are treated as minutes with a warning.
|
||||
function parseDuration(value: string): string {
|
||||
if (/^\d+(\.\d+)?[sm]$/.test(value)) return value;
|
||||
if (/^\d+(\.\d+)?$/.test(value)) {
|
||||
console.warn(
|
||||
`[gmgn-cli] Warning: no unit specified for duration "${value}" — treating as minutes (${value}m). Use a suffix to be explicit: ${value}s for seconds or ${value}m for minutes.`
|
||||
);
|
||||
return `${value}m`;
|
||||
}
|
||||
console.error(
|
||||
`[gmgn-cli] Invalid duration "${value}". Use seconds (e.g. 30s) or minutes (e.g. 0.5m / 1m / 5m).`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
export function registerMarketCommands(program: Command): void {
|
||||
const market = program.command("market").description("Market data commands");
|
||||
|
||||
market
|
||||
.command("kline")
|
||||
.description("Get token K-line (candlestick) data")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.requiredOption("--resolution <resolution>", "Candlestick resolution: 1m / 5m / 15m / 1h / 4h / 1d")
|
||||
.option("--from <timestamp>", "Start time (Unix seconds)", parseInt)
|
||||
@@ -35,7 +51,7 @@ export function registerMarketCommands(program: Command): void {
|
||||
market
|
||||
.command("trending")
|
||||
.description("Get trending token swap data")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--interval <interval>", "Time interval: 1m / 5m / 1h / 6h / 24h")
|
||||
.option("--limit <n>", "Number of results (default 100, max 100)", parseInt)
|
||||
.option("--order-by <field>", "Sort field: default / volume / swaps / marketcap / holder_count / price / change1h / ... (see docs for full list)")
|
||||
@@ -57,19 +73,257 @@ export function registerMarketCommands(program: Command): void {
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
market
|
||||
const trenchesCmd = market
|
||||
.command("trenches")
|
||||
.description("Get Trenches token data (new creation, near completion, completed)")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.option("--type <type...>", "Categories to query, repeatable: new_creation / near_completion / completed (default: all three)")
|
||||
.option("--launchpad-platform <platform...>", "Launchpad platform filter, repeatable (default: all platforms for the chain)")
|
||||
.option("--limit <n>", "Max results per category, max 80 (default: 80)", parseInt)
|
||||
.option("--filter-preset <preset>", "Apply a named filter preset: safe / smart-money / strict")
|
||||
.option("--sort-by <field>", "Client-side sort per category: smart_degen_count / renowned_count / volume_24h / volume_1h / swaps_24h / swaps_1h / rug_ratio / holder_count / usd_market_cap / created_timestamp")
|
||||
.option("--direction <dir>", "Sort direction: asc / desc (default: desc; asc for rug_ratio)")
|
||||
.option("--raw", "Output raw JSON");
|
||||
|
||||
// Dynamically register all server-side filter flags
|
||||
for (const def of TRENCHES_FILTER_FIELDS) {
|
||||
const flag = def.api.replace(/_/g, '-');
|
||||
if (def.type === "int") {
|
||||
trenchesCmd.option(`--${flag} <${def.type}>`, def.desc, parseInt);
|
||||
} else if (def.type === "float") {
|
||||
trenchesCmd.option(`--${flag} <${def.type}>`, def.desc, parseFloat);
|
||||
} else if (def.type === "duration") {
|
||||
trenchesCmd.option(`--${flag} <duration>`, def.desc, parseDuration);
|
||||
} else {
|
||||
trenchesCmd.option(`--${flag} <value>`, def.desc);
|
||||
}
|
||||
}
|
||||
|
||||
trenchesCmd.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
const client = new OpenApiClient(getConfig());
|
||||
|
||||
// Build server-side filter object
|
||||
const filters: Record<string, number | string> = {};
|
||||
|
||||
// Apply preset values first
|
||||
if (opts.filterPreset != null) {
|
||||
const preset = TRENCHES_FILTER_PRESETS[opts.filterPreset as string];
|
||||
if (!preset) {
|
||||
console.error(`Unknown --filter-preset "${opts.filterPreset}". Valid options: ${Object.keys(TRENCHES_FILTER_PRESETS).join(", ")}`);
|
||||
process.exit(1);
|
||||
}
|
||||
Object.assign(filters, preset);
|
||||
}
|
||||
|
||||
// Apply individual filter flags (override preset values)
|
||||
const optsMap = opts as Record<string, unknown>;
|
||||
for (const def of TRENCHES_FILTER_FIELDS) {
|
||||
const key = apiFieldToCliKey(def.api);
|
||||
const val = optsMap[key];
|
||||
if (val != null) filters[def.api] = val as number | string;
|
||||
}
|
||||
|
||||
const data = await client
|
||||
.getTrenches(opts.chain, opts.type, opts.launchpadPlatform, opts.limit, Object.keys(filters).length ? filters : undefined)
|
||||
.catch(exitOnError);
|
||||
|
||||
const result = opts.sortBy
|
||||
? sortTrenchesResult(data as Record<string, unknown>, opts.sortBy as string, (opts.direction as string) ?? "")
|
||||
: data;
|
||||
printResult(result, opts.raw);
|
||||
});
|
||||
|
||||
market
|
||||
.command("signal")
|
||||
.description("Query token signals (price spikes, smart money buys, large buys, etc.) — max 50 results per group")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc")
|
||||
.option("--signal-type <n...>", "Signal type(s), repeatable: 1–18 (default: all types)", (v: string, acc: number[]) => { acc.push(parseInt(v, 10)); return acc; }, [] as number[])
|
||||
.option("--mc-min <usd>", "Min market cap at trigger time (USD)", parseFloat)
|
||||
.option("--mc-max <usd>", "Max market cap at trigger time (USD)", parseFloat)
|
||||
.option("--trigger-mc-min <usd>", "Min market cap at signal trigger (USD)", parseFloat)
|
||||
.option("--trigger-mc-max <usd>", "Max market cap at signal trigger (USD)", parseFloat)
|
||||
.option("--total-fee-min <usd>", "Min total fees paid (USD)", parseFloat)
|
||||
.option("--total-fee-max <usd>", "Max total fees paid (USD)", parseFloat)
|
||||
.option("--min-create-or-open-ts <ts>", "Min token creation or open timestamp (Unix seconds string)")
|
||||
.option("--max-create-or-open-ts <ts>", "Max token creation or open timestamp (Unix seconds string)")
|
||||
.option("--groups <json>", "Multi-group override: JSON array of group objects — overrides all individual flags when provided")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
.action(async (opts: Record<string, unknown>) => {
|
||||
validateChain(opts["chain"] as string);
|
||||
if (!["sol", "bsc"].includes(opts["chain"] as string)) {
|
||||
console.error(`[gmgn-cli] market signal only supports sol and bsc, got "${opts["chain"]}"`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let groups: TokenSignalGroup[];
|
||||
if (opts["groups"] != null) {
|
||||
try {
|
||||
groups = JSON.parse(opts["groups"] as string) as TokenSignalGroup[];
|
||||
} catch {
|
||||
console.error(`[gmgn-cli] --groups must be a valid JSON array, e.g. '[{"signal_type":[12,14]},{"signal_type":[6,7],"mc_min":50000}]'`);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
const group: TokenSignalGroup = {};
|
||||
const signalType = opts["signalType"] as number[] | undefined;
|
||||
if (signalType?.length) group.signal_type = signalType;
|
||||
if (opts["mcMin"] != null) group.mc_min = opts["mcMin"] as number;
|
||||
if (opts["mcMax"] != null) group.mc_max = opts["mcMax"] as number;
|
||||
if (opts["triggerMcMin"] != null) group.trigger_mc_min = opts["triggerMcMin"] as number;
|
||||
if (opts["triggerMcMax"] != null) group.trigger_mc_max = opts["triggerMcMax"] as number;
|
||||
if (opts["totalFeeMin"] != null) group.total_fee_min = opts["totalFeeMin"] as number;
|
||||
if (opts["totalFeeMax"] != null) group.total_fee_max = opts["totalFeeMax"] as number;
|
||||
if (opts["minCreateOrOpenTs"] != null) group.min_create_or_open_ts = opts["minCreateOrOpenTs"] as string;
|
||||
if (opts["maxCreateOrOpenTs"] != null) group.max_create_or_open_ts = opts["maxCreateOrOpenTs"] as string;
|
||||
groups = [group];
|
||||
}
|
||||
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTrenches(opts.chain, opts.type, opts.launchpadPlatform, opts.limit).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
const data = await client.getTokenSignalV2(opts["chain"] as string, groups).catch(exitOnError);
|
||||
printResult(data, opts["raw"] as boolean | undefined);
|
||||
});
|
||||
}
|
||||
|
||||
// ---- Trenches filter field definitions ----
|
||||
|
||||
type TrenchesFieldType = "int" | "float" | "string" | "duration";
|
||||
|
||||
interface TrenchesFilterField {
|
||||
api: string;
|
||||
type: TrenchesFieldType;
|
||||
desc: string;
|
||||
}
|
||||
|
||||
// All server-side filter fields for market trenches
|
||||
// API field names map to CLI flags by replacing _ with - (e.g. min_volume_24h → --min-volume-24h)
|
||||
const TRENCHES_FILTER_FIELDS: TrenchesFilterField[] = [
|
||||
// Trading activity (24h)
|
||||
{ api: "min_volume_24h", type: "float", desc: "Min 24h trading volume (USD)" },
|
||||
{ api: "max_volume_24h", type: "float", desc: "Max 24h trading volume (USD)" },
|
||||
{ api: "min_net_buy_24h", type: "float", desc: "Min 24h net buy volume (USD)" },
|
||||
{ api: "max_net_buy_24h", type: "float", desc: "Max 24h net buy volume (USD)" },
|
||||
{ api: "min_swaps_24h", type: "int", desc: "Min 24h total swap count" },
|
||||
{ api: "max_swaps_24h", type: "int", desc: "Max 24h total swap count" },
|
||||
{ api: "min_buys_24h", type: "int", desc: "Min 24h buy count" },
|
||||
{ api: "max_buys_24h", type: "int", desc: "Max 24h buy count" },
|
||||
{ api: "min_sells_24h", type: "int", desc: "Min 24h sell count" },
|
||||
{ api: "max_sells_24h", type: "int", desc: "Max 24h sell count" },
|
||||
{ api: "min_visiting_count", type: "int", desc: "Min visitor count" },
|
||||
{ api: "max_visiting_count", type: "int", desc: "Max visitor count" },
|
||||
// Market & liquidity
|
||||
{ api: "min_progress", type: "float", desc: "Min bonding curve progress (0–1)" },
|
||||
{ api: "max_progress", type: "float", desc: "Max bonding curve progress (0–1, 1 = completed)" },
|
||||
{ api: "min_marketcap", type: "float", desc: "Min market cap (USD)" },
|
||||
{ api: "max_marketcap", type: "float", desc: "Max market cap (USD)" },
|
||||
{ api: "min_liquidity", type: "float", desc: "Min liquidity (USD)" },
|
||||
{ api: "max_liquidity", type: "float", desc: "Max liquidity (USD)" },
|
||||
// Token age
|
||||
{ api: "min_created", type: "duration", desc: "Min token age — unit recommended: seconds (e.g. 30s) or minutes (e.g. 0.5m / 1m / 5m / 30m). Bare numbers treated as minutes." },
|
||||
{ api: "max_created", type: "duration", desc: "Max token age — unit recommended: seconds (e.g. 30s) or minutes (e.g. 0.5m / 1m / 5m / 30m). Bare numbers treated as minutes." },
|
||||
// Holders
|
||||
{ api: "min_holder_count", type: "int", desc: "Min holder count" },
|
||||
{ api: "max_holder_count", type: "int", desc: "Max holder count" },
|
||||
{ api: "min_top_holder_rate", type: "float", desc: "Min top-10 holder concentration (0–1)" },
|
||||
{ api: "max_top_holder_rate", type: "float", desc: "Max top-10 holder concentration (0–1)" },
|
||||
// Risk signals
|
||||
{ api: "min_rug_ratio", type: "float", desc: "Min rug pull risk score (0–1)" },
|
||||
{ api: "max_rug_ratio", type: "float", desc: "Max rug pull risk score (0–1, e.g. 0.3 to exclude rugs)" },
|
||||
{ api: "min_bundler_rate", type: "float", desc: "Min bundle-bot trading ratio (0–1)" },
|
||||
{ api: "max_bundler_rate", type: "float", desc: "Max bundle-bot trading ratio (0–1)" },
|
||||
{ api: "min_insider_ratio", type: "float", desc: "Min insider trading ratio (0–1)" },
|
||||
{ api: "max_insider_ratio", type: "float", desc: "Max insider trading ratio (0–1)" },
|
||||
{ api: "min_entrapment_ratio", type: "float", desc: "Min entrapment trading ratio (0–1)" },
|
||||
{ api: "max_entrapment_ratio", type: "float", desc: "Max entrapment trading ratio (0–1)" },
|
||||
{ api: "min_private_vault_hold_rate", type: "float", desc: "Min private vault holding ratio (0–1)" },
|
||||
{ api: "max_private_vault_hold_rate", type: "float", desc: "Max private vault holding ratio (0–1)" },
|
||||
{ api: "min_top70_sniper_hold_rate", type: "float", desc: "Min top-70 sniper holding ratio (0–1)" },
|
||||
{ api: "max_top70_sniper_hold_rate", type: "float", desc: "Max top-70 sniper holding ratio (0–1)" },
|
||||
{ api: "min_bot_count", type: "int", desc: "Min bot wallet count" },
|
||||
{ api: "max_bot_count", type: "int", desc: "Max bot wallet count" },
|
||||
{ api: "min_bot_degen_rate", type: "float", desc: "Min bot-degen wallet ratio (0–1)" },
|
||||
{ api: "max_bot_degen_rate", type: "float", desc: "Max bot-degen wallet ratio (0–1)" },
|
||||
{ api: "min_fresh_wallet_rate", type: "float", desc: "Min fresh wallet ratio (0–1)" },
|
||||
{ api: "max_fresh_wallet_rate", type: "float", desc: "Max fresh wallet ratio (0–1)" },
|
||||
{ api: "min_total_fee", type: "float", desc: "Min total fee" },
|
||||
{ api: "max_total_fee", type: "float", desc: "Max total fee" },
|
||||
// Smart money
|
||||
{ api: "min_smart_degen_count", type: "int", desc: "Min smart-money holder count" },
|
||||
{ api: "max_smart_degen_count", type: "int", desc: "Max smart-money holder count" },
|
||||
{ api: "min_renowned_count", type: "int", desc: "Min KOL / renowned wallet count" },
|
||||
{ api: "max_renowned_count", type: "int", desc: "Max KOL / renowned wallet count" },
|
||||
// Dev / creator
|
||||
{ api: "min_creator_balance_rate", type: "float", desc: "Min creator holding ratio (0–1)" },
|
||||
{ api: "max_creator_balance_rate", type: "float", desc: "Max creator holding ratio (0–1)" },
|
||||
{ api: "min_creator_created_count", type: "int", desc: "Min creator total token creation count" },
|
||||
{ api: "max_creator_created_count", type: "int", desc: "Max creator total token creation count" },
|
||||
{ api: "min_creator_created_open_count", type: "int", desc: "Min creator graduated token count" },
|
||||
{ api: "max_creator_created_open_count", type: "int", desc: "Max creator graduated token count" },
|
||||
{ api: "min_creator_created_open_ratio", type: "float", desc: "Min creator graduation ratio (0–1)" },
|
||||
{ api: "max_creator_created_open_ratio", type: "float", desc: "Max creator graduation ratio (0–1)" },
|
||||
// Social
|
||||
{ api: "min_x_follower", type: "int", desc: "Min Twitter / X follower count" },
|
||||
{ api: "max_x_follower", type: "int", desc: "Max Twitter / X follower count" },
|
||||
{ api: "min_twitter_rename_count", type: "int", desc: "Min Twitter rename count (high = suspicious)" },
|
||||
{ api: "max_twitter_rename_count", type: "int", desc: "Max Twitter rename count" },
|
||||
{ api: "min_tg_call_count", type: "int", desc: "Min Telegram call count" },
|
||||
{ api: "max_tg_call_count", type: "int", desc: "Max Telegram call count" },
|
||||
];
|
||||
|
||||
// Named filter presets using actual server-side API field names
|
||||
const TRENCHES_FILTER_PRESETS: Record<string, Record<string, number | string>> = {
|
||||
safe: {
|
||||
max_rug_ratio: 0.3,
|
||||
max_bundler_rate: 0.3,
|
||||
max_insider_ratio: 0.3,
|
||||
},
|
||||
"smart-money": {
|
||||
min_smart_degen_count: 1,
|
||||
},
|
||||
strict: {
|
||||
max_rug_ratio: 0.3,
|
||||
max_bundler_rate: 0.3,
|
||||
max_insider_ratio: 0.3,
|
||||
min_smart_degen_count: 1,
|
||||
min_volume_24h: 1000,
|
||||
},
|
||||
};
|
||||
|
||||
// Convert API snake_case field to Commander.js opts key
|
||||
// Commander.js camelCase: only converts -[a-z] patterns, digits stay as-is
|
||||
// e.g. min_volume_24h → min-volume-24h → minVolume-24h (digit prefix -24 is NOT converted)
|
||||
// e.g. min_smart_degen_count → min-smart-degen-count → minSmartDegenCount (all letters, converts fully)
|
||||
function apiFieldToCliKey(apiField: string): string {
|
||||
return apiField
|
||||
.replace(/_/g, '-')
|
||||
.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());
|
||||
}
|
||||
|
||||
// Client-side sort helpers (API does not support server-side sort for trenches)
|
||||
interface TrenchesCategory {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
const TRENCHES_SORT_ASC_DEFAULTS = new Set(["rug_ratio"]);
|
||||
const TRENCHES_STRING_NUMERIC_FIELDS = new Set(["usd_market_cap", "liquidity", "volume_1h", "volume_24h"]);
|
||||
|
||||
function sortTrenchesCategory(items: TrenchesCategory[], sortBy: string, direction: string): TrenchesCategory[] {
|
||||
const dir = direction || (TRENCHES_SORT_ASC_DEFAULTS.has(sortBy) ? "asc" : "desc");
|
||||
return [...items].sort((a, b) => {
|
||||
const aVal = TRENCHES_STRING_NUMERIC_FIELDS.has(sortBy)
|
||||
? parseFloat(String(a[sortBy] ?? 0))
|
||||
: Number(a[sortBy] ?? 0);
|
||||
const bVal = TRENCHES_STRING_NUMERIC_FIELDS.has(sortBy)
|
||||
? parseFloat(String(b[sortBy] ?? 0))
|
||||
: Number(b[sortBy] ?? 0);
|
||||
return dir === "asc" ? aVal - bVal : bVal - aVal;
|
||||
});
|
||||
}
|
||||
|
||||
function sortTrenchesResult(data: Record<string, unknown>, sortBy: string, direction: string): Record<string, unknown> {
|
||||
const result: Record<string, unknown> = {};
|
||||
for (const [key, val] of Object.entries(data)) {
|
||||
result[key] = Array.isArray(val) ? sortTrenchesCategory(val as TrenchesCategory[], sortBy, direction) : val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export function registerPortfolioCommands(program: Command): void {
|
||||
portfolio
|
||||
.command("holdings")
|
||||
.description("Get wallet token holdings")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--wallet <address>", "Wallet address")
|
||||
.option("--limit <n>", "Page size (default 20, max 50)", parseInt, 20)
|
||||
.option("--cursor <cursor>", "Pagination cursor")
|
||||
@@ -46,7 +46,7 @@ export function registerPortfolioCommands(program: Command): void {
|
||||
portfolio
|
||||
.command("activity")
|
||||
.description("Get wallet transaction activity")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--wallet <address>", "Wallet address")
|
||||
.option("--token <address>", "Filter by token contract address")
|
||||
.option("--limit <n>", "Page size", parseInt)
|
||||
@@ -71,7 +71,7 @@ export function registerPortfolioCommands(program: Command): void {
|
||||
portfolio
|
||||
.command("stats")
|
||||
.description("Get wallet trading statistics (supports multiple wallets)")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--wallet <address...>", "Wallet address(es), repeatable")
|
||||
.option("--period <period>", "Stats period: 7d / 30d", "7d")
|
||||
.option("--raw", "Output raw JSON")
|
||||
@@ -96,7 +96,7 @@ export function registerPortfolioCommands(program: Command): void {
|
||||
portfolio
|
||||
.command("token-balance")
|
||||
.description("Get wallet token balance for a single token")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--wallet <address>", "Wallet address")
|
||||
.requiredOption("--token <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
@@ -109,5 +109,26 @@ export function registerPortfolioCommands(program: Command): void {
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
portfolio
|
||||
.command("created-tokens")
|
||||
.description("Get tokens created by a developer wallet")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--wallet <address>", "Developer wallet address")
|
||||
.option("--order-by <field>", "Sort field: market_cap / token_ath_mc")
|
||||
.option("--direction <dir>", "Sort direction: asc / desc")
|
||||
.option("--migrate-state <state>", "Filter: migrated / non_migrated")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.wallet, opts.chain, "--wallet");
|
||||
const extra: Record<string, string | number> = {};
|
||||
if (opts.orderBy) extra["order_by"] = opts.orderBy;
|
||||
if (opts.direction) extra["direction"] = opts.direction;
|
||||
if (opts.migrateState) extra["migrate_state"] = opts.migrateState;
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getCreatedTokens(opts.chain, opts.wallet, extra).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
+195
-5
@@ -1,5 +1,5 @@
|
||||
import { Command } from "commander";
|
||||
import { OpenApiClient, SwapParams } from "../client/OpenApiClient.js";
|
||||
import { OpenApiClient, SwapParams, MultiSwapParams, 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";
|
||||
@@ -8,7 +8,7 @@ export function registerSwapCommands(program: Command): void {
|
||||
program
|
||||
.command("swap")
|
||||
.description("Submit a token swap")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth ")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--from <address>", "Wallet address (must match API Key binding)")
|
||||
.requiredOption("--input-token <address>", "Input token contract address")
|
||||
.requiredOption("--output-token <address>", "Output token contract address")
|
||||
@@ -24,6 +24,8 @@ export function registerSwapCommands(program: Command): void {
|
||||
.option("--gas-price <gwei>", "Gas price in gwei (BSC ≥ 0.05 / BASE/ETH ≥ 0.01)")
|
||||
.option("--max-fee-per-gas <amount>", "EIP-1559 max fee per gas (Base)")
|
||||
.option("--max-priority-fee-per-gas <amount>", "EIP-1559 max priority fee per gas (Base)")
|
||||
.option("--condition-orders <json>", 'JSON array of take-profit/stop-loss conditions, e.g. \'[{"order_type":"profit_stop","side":"sell","price_scale":"150","sell_ratio":"100"}]\'; trace types: \'[{"order_type":"profit_stop_trace","side":"sell","price_scale":"150","sell_ratio":"100","drawdown_rate":"50"}]\'')
|
||||
.option("--sell-ratio-type <type>", "Sell ratio base: buy_amount (default) / hold_amount; only used with --condition-orders")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
if (opts.percent == null && !opts.amount) {
|
||||
@@ -54,6 +56,15 @@ export function registerSwapCommands(program: Command): void {
|
||||
if (opts.gasPrice) params.gas_price = String(Math.round(parseFloat(opts.gasPrice) * 1e9));
|
||||
if (opts.maxFeePerGas) params.max_fee_per_gas = opts.maxFeePerGas;
|
||||
if (opts.maxPriorityFeePerGas) params.max_priority_fee_per_gas = opts.maxPriorityFeePerGas;
|
||||
if (opts.conditionOrders) {
|
||||
try {
|
||||
params.condition_orders = JSON.parse(opts.conditionOrders);
|
||||
} catch {
|
||||
console.error("[gmgn-cli] --condition-orders must be valid JSON");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
if (opts.sellRatioType) params.sell_ratio_type = opts.sellRatioType;
|
||||
|
||||
const client = new OpenApiClient(getConfig(true));
|
||||
const data = await client.swap(params).catch(exitOnError);
|
||||
@@ -64,8 +75,8 @@ export function registerSwapCommands(program: Command): void {
|
||||
|
||||
order
|
||||
.command("quote")
|
||||
.description("Get a swap quote without submitting a transaction")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.description("Get a swap quote without submitting a transaction (requires critical auth)")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth (requires GMGN_PRIVATE_KEY)")
|
||||
.requiredOption("--from <address>", "Wallet address (must match API Key binding)")
|
||||
.requiredOption("--input-token <address>", "Input token contract address")
|
||||
.requiredOption("--output-token <address>", "Output token contract address")
|
||||
@@ -78,7 +89,7 @@ export function registerSwapCommands(program: Command): void {
|
||||
validateAddress(opts.inputToken, opts.chain, "--input-token");
|
||||
validateAddress(opts.outputToken, opts.chain, "--output-token");
|
||||
validatePositiveInt(opts.amount, "--amount");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const client = new OpenApiClient(getConfig(true));
|
||||
const data = await client
|
||||
.quoteOrder(opts.chain, opts.from, opts.inputToken, opts.outputToken, opts.amount, opts.slippage)
|
||||
.catch(exitOnError);
|
||||
@@ -97,4 +108,183 @@ export function registerSwapCommands(program: Command): void {
|
||||
const data = await client.queryOrder(opts.orderId, opts.chain).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
program
|
||||
.command("multi-swap")
|
||||
.description("Submit token swaps across multiple wallets concurrently (up to 100 wallets)")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--accounts <addresses>", "Comma-separated wallet addresses (all must be bound to the API Key)")
|
||||
.requiredOption("--input-token <address>", "Input token contract address")
|
||||
.requiredOption("--output-token <address>", "Output token contract address")
|
||||
.option("--input-amount <json>", 'JSON map of wallet→amount (smallest unit), e.g. \'{"addr1":"1000000","addr2":"2000000"}\'')
|
||||
.option("--input-amount-bps <json>", 'JSON map of wallet→percent in bps (1–10000, e.g. 5000=50%), e.g. \'{"addr1":"5000"}\'')
|
||||
.option("--output-amount <json>", "JSON map of wallet→target output amount")
|
||||
.option("--slippage <n>", "Slippage tolerance (e.g. 0.01 = 1%)", parseFloat)
|
||||
.option("--auto-slippage", "Enable automatic slippage")
|
||||
.option("--anti-mev", "Enable anti-MEV protection")
|
||||
.option("--priority-fee <sol>", "Priority fee in SOL (SOL only, ≥ 0.00001)")
|
||||
.option("--tip-fee <amount>", "Tip fee (SOL ≥ 0.00001 / BSC ≥ 0.000001 BNB)")
|
||||
.option("--auto-tip-fee", "Enable automatic tip fee")
|
||||
.option("--max-auto-fee <amount>", "Max auto fee cap")
|
||||
.option("--gas-price <gwei>", "Gas price in gwei (BSC ≥ 0.05 / BASE/ETH ≥ 0.01)")
|
||||
.option("--max-fee-per-gas <amount>", "EIP-1559 max fee per gas (Base only)")
|
||||
.option("--max-priority-fee-per-gas <amount>", "EIP-1559 max priority fee per gas (Base only)")
|
||||
.option("--condition-orders <json>", "JSON array of take-profit/stop-loss conditions attached to each successful wallet's swap")
|
||||
.option("--sell-ratio-type <type>", "Sell ratio base: buy_amount (default) / hold_amount; only used with --condition-orders")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
if (!opts.inputAmount && !opts.inputAmountBps && !opts.outputAmount) {
|
||||
console.error("[gmgn-cli] At least one of --input-amount, --input-amount-bps, or --output-amount must be provided");
|
||||
process.exit(1);
|
||||
}
|
||||
validateChain(opts.chain);
|
||||
const accounts = (opts.accounts as string).split(",").map((a: string) => a.trim()).filter(Boolean);
|
||||
if (accounts.length === 0 || accounts.length > 100) {
|
||||
console.error("[gmgn-cli] --accounts must be 1–100 comma-separated wallet addresses");
|
||||
process.exit(1);
|
||||
}
|
||||
const params: MultiSwapParams = {
|
||||
chain: opts.chain,
|
||||
accounts,
|
||||
input_token: opts.inputToken,
|
||||
output_token: opts.outputToken,
|
||||
};
|
||||
if (opts.inputAmount) {
|
||||
try { params.input_amount = JSON.parse(opts.inputAmount); }
|
||||
catch { console.error("[gmgn-cli] --input-amount must be valid JSON"); process.exit(1); }
|
||||
}
|
||||
if (opts.inputAmountBps) {
|
||||
try { params.input_amount_bps = JSON.parse(opts.inputAmountBps); }
|
||||
catch { console.error("[gmgn-cli] --input-amount-bps must be valid JSON"); process.exit(1); }
|
||||
}
|
||||
if (opts.outputAmount) {
|
||||
try { params.output_amount = JSON.parse(opts.outputAmount); }
|
||||
catch { console.error("[gmgn-cli] --output-amount must be valid JSON"); process.exit(1); }
|
||||
}
|
||||
if (opts.slippage != null) params.slippage = opts.slippage;
|
||||
if (opts.autoSlippage) params.auto_slippage = true;
|
||||
if (opts.antiMev) params.is_anti_mev = true;
|
||||
if (opts.priorityFee) params.priority_fee = opts.priorityFee;
|
||||
if (opts.tipFee) params.tip_fee = opts.tipFee;
|
||||
if (opts.autoTipFee) params.auto_tip_fee = true;
|
||||
if (opts.maxAutoFee) params.max_auto_fee = opts.maxAutoFee;
|
||||
if (opts.gasPrice) params.gas_price = String(Math.round(parseFloat(opts.gasPrice) * 1e9));
|
||||
if (opts.maxFeePerGas) params.max_fee_per_gas = opts.maxFeePerGas;
|
||||
if (opts.maxPriorityFeePerGas) params.max_priority_fee_per_gas = opts.maxPriorityFeePerGas;
|
||||
if (opts.conditionOrders) {
|
||||
try { params.condition_orders = JSON.parse(opts.conditionOrders); }
|
||||
catch { console.error("[gmgn-cli] --condition-orders must be valid JSON"); process.exit(1); }
|
||||
}
|
||||
if (opts.sellRatioType) params.sell_ratio_type = opts.sellRatioType;
|
||||
const client = new OpenApiClient(getConfig(true));
|
||||
const data = await client.multiSwap(params).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>", "Chain: sol / bsc / base / eth")
|
||||
.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("--order-type <type>", "Order type: limit_order")
|
||||
.requiredOption("--sub-order-type <type>", "Sub-order type: buy_low / buy_high / stop_loss / take_profit")
|
||||
.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 (required for SOL chain)")
|
||||
.option("--tip-fee <amount>", "Tip fee (required for SOL chain)")
|
||||
.option("--gas-price <gwei>", "Gas price in gwei (required for BSC; ≥ 0.05 gwei / BASE/ETH ≥ 0.01 gwei)")
|
||||
.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,
|
||||
order_type: opts.orderType,
|
||||
sub_order_type: opts.subOrderType,
|
||||
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 = String(Math.round(parseFloat(opts.gasPrice) * 1e9));
|
||||
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 (requires private key)")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.option("--type <type>", "open (default) / history")
|
||||
.option("--from <address>", "Filter by wallet address")
|
||||
.option("--group-tag <tag>", "Filter by group: LimitOrder / STMix")
|
||||
.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.groupTag) extra["group_tag"] = opts.groupTag;
|
||||
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(true));
|
||||
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 / eth")
|
||||
.requiredOption("--from <address>", "Wallet address (must match API Key binding)")
|
||||
.requiredOption("--order-id <id>", "Order ID to cancel")
|
||||
.option("--order-type <type>", "Order type: limit_order / smart_trade")
|
||||
.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.orderType) params.order_type = opts.orderType;
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export function registerTokenCommands(program: Command): void {
|
||||
token
|
||||
.command("info")
|
||||
.description("Get token basic information and realtime price")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
@@ -24,7 +24,7 @@ export function registerTokenCommands(program: Command): void {
|
||||
token
|
||||
.command("security")
|
||||
.description("Get token security metrics")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
@@ -38,7 +38,7 @@ export function registerTokenCommands(program: Command): void {
|
||||
token
|
||||
.command("pool")
|
||||
.description("Get token liquidity pool information")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
@@ -52,12 +52,12 @@ export function registerTokenCommands(program: Command): void {
|
||||
token
|
||||
.command("holders")
|
||||
.description("Get top token holders")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--limit <n>", "Number of results (default 20, max 100)", parseInt)
|
||||
.option("--order-by <field>", "Sort field: amount_percentage / profit / unrealized_profit / buy_volume_cur / sell_volume_cur", "amount_percentage")
|
||||
.option("--direction <dir>", "Sort direction: asc / desc", "desc")
|
||||
.option("--tag <tag>", "Wallet tag filter: renowned / smart_degen")
|
||||
.option("--tag <tag>", "Wallet tag filter: smart_degen / renowned / fresh_wallet / dev / sniper / rat_trader / bundler / transfer_in / dex_bot / bluechip_owner")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
@@ -75,12 +75,12 @@ export function registerTokenCommands(program: Command): void {
|
||||
token
|
||||
.command("traders")
|
||||
.description("Get top token traders")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--limit <n>", "Number of results (default 20, max 100)", parseInt)
|
||||
.option("--order-by <field>", "Sort field: amount_percentage / profit / unrealized_profit / buy_volume_cur / sell_volume_cur", "amount_percentage")
|
||||
.option("--direction <dir>", "Sort direction: asc / desc", "desc")
|
||||
.option("--tag <tag>", "Wallet tag filter: renowned / smart_degen")
|
||||
.option("--tag <tag>", "Wallet tag filter: smart_degen / renowned / fresh_wallet / dev / sniper / rat_trader / bundler / transfer_in / dex_bot / bluechip_owner")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
|
||||
@@ -10,7 +10,7 @@ export function registerTrackCommands(program: Command): void {
|
||||
track
|
||||
.command("follow-wallet")
|
||||
.description("Get follow-wallet trade records")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.option("--wallet <address>", "Filter by wallet address")
|
||||
.option("--limit <n>", "Page size (1–100, default 10)", parseInt)
|
||||
.option("--side <side>", "Trade direction filter: buy / sell")
|
||||
@@ -27,7 +27,7 @@ export function registerTrackCommands(program: Command): void {
|
||||
if (opts.filter?.length) extra["filters"] = opts.filter;
|
||||
if (opts.minAmountUsd != null) extra["min_amount_usd"] = opts.minAmountUsd;
|
||||
if (opts.maxAmountUsd != null) extra["max_amount_usd"] = opts.maxAmountUsd;
|
||||
const client = new OpenApiClient(getConfig(true));
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getFollowWallet(opts.chain, extra).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
@@ -35,7 +35,7 @@ export function registerTrackCommands(program: Command): void {
|
||||
track
|
||||
.command("kol")
|
||||
.description("Get KOL trade records")
|
||||
.option("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.option("--limit <n>", "Page size (1–200, default 100)", parseInt)
|
||||
.option("--side <side>", "Filter by trade direction: buy / sell (client-side filter)")
|
||||
.option("--raw", "Output raw JSON")
|
||||
@@ -52,7 +52,7 @@ export function registerTrackCommands(program: Command): void {
|
||||
track
|
||||
.command("smartmoney")
|
||||
.description("Get Smart Money trade records")
|
||||
.option("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
.option("--limit <n>", "Page size (1–200, default 100)", parseInt)
|
||||
.option("--side <side>", "Filter by trade direction: buy / sell (client-side filter)")
|
||||
.option("--raw", "Output raw JSON")
|
||||
|
||||
+4
-2
@@ -14,11 +14,13 @@ export interface Config {
|
||||
}
|
||||
|
||||
let _config: Config | null = null;
|
||||
const PRIVATE_KEY_REQUIRED_MSG =
|
||||
"GMGN_PRIVATE_KEY is required for critical-auth commands (swap, order, and follow-wallet commands)";
|
||||
|
||||
export function getConfig(requirePrivateKey = false): Config {
|
||||
if (_config) {
|
||||
if (requirePrivateKey && !_config.privateKeyPem) {
|
||||
die("GMGN_PRIVATE_KEY is required for swap/order commands");
|
||||
die(PRIVATE_KEY_REQUIRED_MSG);
|
||||
}
|
||||
return _config;
|
||||
}
|
||||
@@ -34,7 +36,7 @@ export function getConfig(requirePrivateKey = false): Config {
|
||||
// Support escaped newlines (e.g. from single-line .env values)
|
||||
privateKeyPem = privateKey.replace(/\\n/g, "\n");
|
||||
} else if (requirePrivateKey) {
|
||||
die("GMGN_PRIVATE_KEY is required for swap/order commands");
|
||||
die(PRIVATE_KEY_REQUIRED_MSG);
|
||||
}
|
||||
|
||||
const host = process.env.GMGN_HOST ?? "https://openapi.gmgn.ai";
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
Reference in New Issue
Block a user