From 2f76b375c512aedeea4e62480ba3ebdb1124048b Mon Sep 17 00:00:00 2001 From: deepfeature Date: Tue, 26 May 2026 11:19:30 +0800 Subject: [PATCH] breaking(portfolio): upgrade wallet_holdings to critical auth Align CLI with server-side breaking change: GET /v1/user/wallet_holdings was upgraded from authExistMW to authCriticalMW on the openapi-service. - OpenApiClient: switch getWalletHoldings to authSignedRequest - SKILL.md: split rate-limit table by auth level; update Notes section - CLAUDE.md: move portfolio holdings from Normal to Critical auth row Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 4 ++-- skills/gmgn-portfolio/SKILL.md | 11 +++++++++-- src/client/OpenApiClient.ts | 8 ++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e26aa78..19ca6da 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -93,8 +93,8 @@ EOF | Mode | Commands | Requirements | |------|----------|--------------| -| 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 | +| Normal | token / market / portfolio (except holdings) / track kol / track smartmoney | `GMGN_API_KEY` only, no signature | +| Critical | swap / order / portfolio holdings / track follow-wallet | `GMGN_API_KEY` + `GMGN_PRIVATE_KEY` — CLI handles signing automatically | ## SKILL.md Authoring Rules diff --git a/skills/gmgn-portfolio/SKILL.md b/skills/gmgn-portfolio/SKILL.md index 47f49f8..c68b862 100644 --- a/skills/gmgn-portfolio/SKILL.md +++ b/skills/gmgn-portfolio/SKILL.md @@ -54,10 +54,17 @@ Use the `gmgn-cli` tool to query wallet portfolio data based on the user's reque All portfolio routes used by this skill go through GMGN's leaky-bucket limiter with `rate=20` and `capacity=20`. Sustained throughput is roughly `20 ÷ weight` requests/second, and the max burst is roughly `floor(20 ÷ weight)` when the bucket is full. +**Critical auth** (`GMGN_API_KEY` + `GMGN_PRIVATE_KEY` required): + +| Command | Route | Weight | +|---------|-------|--------| +| `portfolio holdings` | `GET /v1/user/wallet_holdings` | 5 | + +**Exist auth** (`GMGN_API_KEY` only): + | 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 | @@ -360,7 +367,7 @@ Show the `[Identity: ...]` line only if `common` is present in the response. For ## Notes -- All portfolio commands use exist auth (API Key only, no signature required) +- `portfolio holdings` uses **critical auth** (`GMGN_API_KEY` + `GMGN_PRIVATE_KEY` required — CLI signs the request automatically). All other portfolio commands use exist auth (API Key only, no signature required). - `portfolio stats` supports multiple `--wallet` flags for batch queries - Use `--raw` to get single-line JSON for further processing - **Input validation** — Wallet and token addresses are validated against the expected chain format at runtime (sol: base58 32–44 chars; bsc/base/eth: `0x` + 40 hex digits). The CLI exits with an error on invalid input. diff --git a/src/client/OpenApiClient.ts b/src/client/OpenApiClient.ts index b3bd6a9..39fe902 100644 --- a/src/client/OpenApiClient.ts +++ b/src/client/OpenApiClient.ts @@ -241,18 +241,18 @@ export class OpenApiClient { return this.authExistRequest("GET", "/v1/market/token_kline", query); } - // ---- Portfolio endpoints (exist auth) ---- + // ---- Portfolio endpoints ---- async getWalletHoldings( chain: string, walletAddress: string, extra: Record = {} ): Promise { - return this.authExistRequest("GET", "/v1/user/wallet_holdings", { + return this.authSignedRequest("GET", "/v1/user/wallet_holdings", { chain, wallet_address: walletAddress, ...extra, - }); + }, null); } async getWalletActivity( @@ -419,7 +419,7 @@ export class OpenApiClient { body: unknown ): Promise { if (!this.privateKeyPem) { - throw new Error("GMGN_PRIVATE_KEY is required for critical-auth commands (swap, order, and follow-wallet commands)"); + throw new Error("GMGN_PRIVATE_KEY is required for critical-auth commands (swap, order, follow-wallet, and portfolio holdings commands)"); } return this.executePreparedRequest(() => {