fix bsc order quote auth

This commit is contained in:
deepfeature
2026-04-08 17:19:16 +08:00
parent fce314b9ab
commit ca3c640afc
7 changed files with 48 additions and 22 deletions
+13 -2
View File
@@ -158,7 +158,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 capability or BSC order quotes, append the private key:
```bash
# Append private key (use the PEM content from Step 3)
@@ -500,7 +500,7 @@ 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
@@ -539,10 +539,21 @@ gmgn-cli order quote \
--amount 1000000 \
--slippage 0.01
# BSC quotes use critical auth and require 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
# Query order
gmgn-cli order get --chain sol --order-id <order-id>
```
> `order quote` uses API Key only on `sol` / `base`. On `bsc`, the same route uses critical auth and requires `GMGN_PRIVATE_KEY`.
### Swap with Take-Profit / Stop-Loss Orders (requires private key)
**`hold_amount` mode** — each condition order fires based on current holdings at trigger time:
+13 -2
View File
@@ -164,7 +164,7 @@ echo 'GMGN_API_KEY=<user_api_key>' > ~/.config/gmgn/.env
chmod 600 ~/.config/gmgn/.env
```
如果用户需要 swap 能力,追加私钥:
如果用户需要 swap 能力或 BSC 链上的 `order quote`,追加私钥:
```bash
# 追加私钥(使用第 3 步输出的 PEM 内容)
@@ -532,7 +532,7 @@ gmgn-cli track smartmoney --limit 100 --raw
gmgn-cli track smartmoney --chain sol --side sell --limit 50 --raw
```
### Swap(需要私钥)
### Swap / Quote / Query
```bash
# 提交兑换(固定滑点)
@@ -571,10 +571,21 @@ gmgn-cli order quote \
--amount 1000000 \
--slippage 0.01
# BSC 报价走关键鉴权,需要 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>
```
> `order quote` 在 `sol` / `base` 上仍只需要 API Key;在 `bsc` 上改为关键鉴权,必须配置 `GMGN_PRIVATE_KEY`。
### 带止盈止损的 Swap(需要私钥)
**`hold_amount` 模式** — 按触发时的实际持仓比例卖出:
+2 -2
View File
@@ -344,7 +344,7 @@ npx gmgn-cli portfolio smartmoney [--limit <n>] [--raw]
## 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. `sol` / `base` use normal auth (API Key only). `bsc` uses critical auth and requires `GMGN_PRIVATE_KEY`.
```bash
npx gmgn-cli order quote \
@@ -359,7 +359,7 @@ npx gmgn-cli order quote \
| Option | Required | Description |
|--------|----------|-------------|
| `--chain` | Yes | `sol` / `bsc` / `base` |
| `--chain` | Yes | `sol` / `bsc` / `base` (`bsc` quote requires `GMGN_PRIVATE_KEY`) |
| `--from` | Yes | Wallet address (must match API Key binding) |
| `--input-token` | Yes | Input token contract address |
| `--output-token` | Yes | Output token contract address |
+6 -6
View File
@@ -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`, `order get`, strategy order commands, and `order quote --chain bsc`.
## Core Concepts
@@ -26,7 +26,7 @@ Use the `gmgn-cli` tool to submit a token swap or query an existing order. **Req
- **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`, `order get`, strategy order commands, and `order quote --chain bsc` 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 quote` on `sol` / `base` still uses API Key alone.
- **`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`.
@@ -46,7 +46,7 @@ Use the `gmgn-cli` tool to submit a token swap or query an existing order. **Req
| Sub-command | Description |
|-------------|-------------|
| `swap` | Submit a token swap |
| `order quote` | Get a swap quote (no transaction submitted) |
| `order quote` | Get a swap quote (no transaction submitted; BSC uses 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) |
@@ -70,7 +70,7 @@ Currency tokens are the base/native assets of each chain. They are used to buy o
## Prerequisites
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_API_KEY` must be configured in `~/.config/gmgn/.env`. `GMGN_PRIVATE_KEY` is additionally required for `swap`, `order get`, strategy order commands, and `order quote --chain bsc`. 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`
@@ -165,7 +165,7 @@ gmgn-cli swap \
## `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. `sol` / `base` use normal auth (API Key only). `bsc` uses critical auth and requires `GMGN_PRIVATE_KEY`.
```bash
gmgn-cli order quote \
@@ -292,7 +292,7 @@ gmgn-cli swap \
### 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 (`sol` / `base` use normal auth; `bsc` requires critical auth and `GMGN_PRIVATE_KEY`):
```bash
gmgn-cli order quote \
+7 -5
View File
@@ -3,7 +3,7 @@
*
* Auth modes:
* Normal (market/token/portfolio): X-APIKEY + timestamp + client_id
* Critical (swap/order): normal auth + X-Signature (private key signature)
* Critical (swap, order get/strategy, BSC order quote): normal auth + X-Signature (private key signature)
*/
import { buildAuthQuery, buildMessage, detectAlgorithm, sign } from "./signer.js";
@@ -293,9 +293,11 @@ 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 };
if (chain === "bsc") {
return this.criticalRequest("GET", "/v1/trade/quote", query, null);
}
return this.normalRequest("GET", "/v1/trade/quote", query);
}
// ---- Swap endpoints (critical auth) ----
@@ -367,7 +369,7 @@ export class OpenApiClient {
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 get/strategy, and order quote on BSC)");
}
return this.executePreparedRequest(() => {
+3 -3
View File
@@ -75,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 (BSC uses critical auth)")
.requiredOption("--chain <chain>", "Chain: sol / bsc / base (BSC quote 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")
@@ -89,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(opts.chain === "bsc"));
const data = await client
.quoteOrder(opts.chain, opts.from, opts.inputToken, opts.outputToken, opts.amount, opts.slippage)
.catch(exitOnError);
+4 -2
View File
@@ -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 get/strategy, and order quote on BSC)";
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";