gmgn-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.claude-plugin/marketplace.json +45 -0
  2. package/.claude-plugin/plugin.json +13 -0
  3. package/.cursor-plugin/plugin.json +23 -0
  4. package/LICENSE +21 -0
  5. package/Readme.md +236 -0
  6. package/Readme.zh.md +236 -0
  7. package/dist/client/OpenApiClient.d.ts +58 -0
  8. package/dist/client/OpenApiClient.d.ts.map +1 -0
  9. package/dist/client/OpenApiClient.js +174 -0
  10. package/dist/client/OpenApiClient.js.map +1 -0
  11. package/dist/client/signer.d.ts +32 -0
  12. package/dist/client/signer.d.ts.map +1 -0
  13. package/dist/client/signer.js +66 -0
  14. package/dist/client/signer.js.map +1 -0
  15. package/dist/commands/market.d.ts +3 -0
  16. package/dist/commands/market.d.ts.map +1 -0
  17. package/dist/commands/market.js +50 -0
  18. package/dist/commands/market.js.map +1 -0
  19. package/dist/commands/portfolio.d.ts +3 -0
  20. package/dist/commands/portfolio.d.ts.map +1 -0
  21. package/dist/commands/portfolio.js +112 -0
  22. package/dist/commands/portfolio.js.map +1 -0
  23. package/dist/commands/swap.d.ts +3 -0
  24. package/dist/commands/swap.d.ts.map +1 -0
  25. package/dist/commands/swap.js +73 -0
  26. package/dist/commands/swap.js.map +1 -0
  27. package/dist/commands/token.d.ts +3 -0
  28. package/dist/commands/token.d.ts.map +1 -0
  29. package/dist/commands/token.js +62 -0
  30. package/dist/commands/token.js.map +1 -0
  31. package/dist/config.d.ts +7 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +36 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/index.d.ts +3 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +55 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/output.d.ts +3 -0
  40. package/dist/output.d.ts.map +1 -0
  41. package/dist/output.js +22 -0
  42. package/dist/output.js.map +1 -0
  43. package/package.json +51 -0
  44. package/skills/gmgn-market/SKILL.md +144 -0
  45. package/skills/gmgn-portfolio/SKILL.md +105 -0
  46. package/skills/gmgn-swap/SKILL.md +142 -0
  47. package/skills/gmgn-token/SKILL.md +55 -0
@@ -0,0 +1,62 @@
1
+ import { OpenApiClient } from "../client/OpenApiClient.js";
2
+ import { getConfig } from "../config.js";
3
+ import { exitOnError, printResult } from "../output.js";
4
+ export function registerTokenCommands(program) {
5
+ const token = program.command("token").description("Token information commands");
6
+ token
7
+ .command("info")
8
+ .description("Get token basic information and realtime price")
9
+ .requiredOption("--chain <chain>", "Chain: sol / bsc / base")
10
+ .requiredOption("--address <address>", "Token contract address")
11
+ .option("--raw", "Output raw JSON")
12
+ .action(async (opts) => {
13
+ const client = new OpenApiClient(getConfig());
14
+ const data = await client.getTokenInfo(opts.chain, opts.address).catch(exitOnError);
15
+ printResult(data, opts.raw);
16
+ });
17
+ token
18
+ .command("security")
19
+ .description("Get token security metrics")
20
+ .requiredOption("--chain <chain>", "Chain: sol / bsc / base")
21
+ .requiredOption("--address <address>", "Token contract address")
22
+ .option("--raw", "Output raw JSON")
23
+ .action(async (opts) => {
24
+ const client = new OpenApiClient(getConfig());
25
+ const data = await client.getTokenSecurity(opts.chain, opts.address).catch(exitOnError);
26
+ printResult(data, opts.raw);
27
+ });
28
+ token
29
+ .command("pool")
30
+ .description("Get token liquidity pool information")
31
+ .requiredOption("--chain <chain>", "Chain: sol / bsc / base")
32
+ .requiredOption("--address <address>", "Token contract address")
33
+ .option("--raw", "Output raw JSON")
34
+ .action(async (opts) => {
35
+ const client = new OpenApiClient(getConfig());
36
+ const data = await client.getTokenPoolInfo(opts.chain, opts.address).catch(exitOnError);
37
+ printResult(data, opts.raw);
38
+ });
39
+ token
40
+ .command("holders")
41
+ .description("Get top token holders")
42
+ .requiredOption("--chain <chain>", "Chain: sol / bsc / base")
43
+ .requiredOption("--address <address>", "Token contract address")
44
+ .option("--raw", "Output raw JSON")
45
+ .action(async (opts) => {
46
+ const client = new OpenApiClient(getConfig());
47
+ const data = await client.getTokenTopHolders(opts.chain, opts.address).catch(exitOnError);
48
+ printResult(data, opts.raw);
49
+ });
50
+ token
51
+ .command("traders")
52
+ .description("Get top token traders")
53
+ .requiredOption("--chain <chain>", "Chain: sol / bsc / base")
54
+ .requiredOption("--address <address>", "Token contract address")
55
+ .option("--raw", "Output raw JSON")
56
+ .action(async (opts) => {
57
+ const client = new OpenApiClient(getConfig());
58
+ const data = await client.getTokenTopTraders(opts.chain, opts.address).catch(exitOnError);
59
+ printResult(data, opts.raw);
60
+ });
61
+ }
62
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/commands/token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface Config {
2
+ apiKey: string;
3
+ privateKeyPem?: string;
4
+ host: string;
5
+ }
6
+ export declare function getConfig(requirePrivateKey?: boolean): Config;
7
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAID,wBAAgB,SAAS,CAAC,iBAAiB,UAAQ,GAAG,MAAM,CAyB3D"}
package/dist/config.js ADDED
@@ -0,0 +1,36 @@
1
+ import { config as loadDotenv } from "dotenv";
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+ // Load global config first (~/.config/gmgn/.env), then project .env (project takes precedence)
5
+ loadDotenv({ path: join(homedir(), ".config", "gmgn", ".env") });
6
+ loadDotenv({ override: true });
7
+ let _config = null;
8
+ export function getConfig(requirePrivateKey = false) {
9
+ if (_config) {
10
+ if (requirePrivateKey && !_config.privateKeyPem) {
11
+ die("GMGN_PRIVATE_KEY is required for swap/order commands");
12
+ }
13
+ return _config;
14
+ }
15
+ const apiKey = process.env.GMGN_API_KEY;
16
+ if (!apiKey) {
17
+ die("GMGN_API_KEY is required. Set it in your .env file or environment.");
18
+ }
19
+ let privateKeyPem;
20
+ const privateKey = process.env.GMGN_PRIVATE_KEY;
21
+ if (privateKey) {
22
+ // Support escaped newlines (e.g. from single-line .env values)
23
+ privateKeyPem = privateKey.replace(/\\n/g, "\n");
24
+ }
25
+ else if (requirePrivateKey) {
26
+ die("GMGN_PRIVATE_KEY is required for swap/order commands");
27
+ }
28
+ const host = process.env.GMGN_HOST ?? "https://openapi.gmgn.ai";
29
+ _config = { apiKey: apiKey, privateKeyPem, host };
30
+ return _config;
31
+ }
32
+ function die(msg) {
33
+ console.error(`[gmgn-cli] Error: ${msg}`);
34
+ process.exit(1);
35
+ }
36
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,+FAA+F;AAC/F,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AACjE,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAQ/B,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC,MAAM,UAAU,SAAS,CAAC,iBAAiB,GAAG,KAAK;IACjD,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,iBAAiB,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAChD,GAAG,CAAC,sDAAsD,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,aAAiC,CAAC;IACtC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAChD,IAAI,UAAU,EAAE,CAAC;QACf,+DAA+D;QAC/D,aAAa,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;SAAM,IAAI,iBAAiB,EAAE,CAAC;QAC7B,GAAG,CAAC,sDAAsD,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,yBAAyB,CAAC;IAChE,OAAO,GAAG,EAAE,MAAM,EAAE,MAAO,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IACnD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,GAAG,CAAC,GAAW;IACtB,OAAO,CAAC,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ import { setGlobalDispatcher, ProxyAgent, Agent } from "undici";
3
+ import { SocksClient } from "socks";
4
+ import * as tls from "tls";
5
+ import { Command } from "commander";
6
+ import { registerTokenCommands } from "./commands/token.js";
7
+ import { registerMarketCommands } from "./commands/market.js";
8
+ import { registerPortfolioCommands } from "./commands/portfolio.js";
9
+ import { registerSwapCommands } from "./commands/swap.js";
10
+ const proxy = process.env.HTTPS_PROXY ?? process.env.https_proxy
11
+ ?? process.env.HTTP_PROXY ?? process.env.http_proxy;
12
+ if (proxy) {
13
+ const u = new URL(proxy);
14
+ if (u.protocol === "socks5:" || u.protocol === "socks4:") {
15
+ const type = u.protocol === "socks5:" ? 5 : 4;
16
+ setGlobalDispatcher(new Agent({
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ connect: async (options, callback) => {
19
+ try {
20
+ const { socket } = await SocksClient.createConnection({
21
+ proxy: { host: u.hostname, port: parseInt(u.port || "1080"), type },
22
+ command: "connect",
23
+ destination: { host: options.hostname, port: +options.port },
24
+ });
25
+ if (options.protocol === "https:") {
26
+ callback(null, tls.connect({ socket, servername: options.hostname, rejectUnauthorized: options.rejectUnauthorized !== false }));
27
+ }
28
+ else {
29
+ callback(null, socket);
30
+ }
31
+ }
32
+ catch (err) {
33
+ callback(err, null);
34
+ }
35
+ },
36
+ }));
37
+ }
38
+ else {
39
+ setGlobalDispatcher(new ProxyAgent(proxy));
40
+ }
41
+ }
42
+ const program = new Command();
43
+ program
44
+ .name("gmgn-cli")
45
+ .version("1.0.0")
46
+ .description("GMGN OpenAPI CLI — market data, token info, portfolio and swap");
47
+ registerTokenCommands(program);
48
+ registerMarketCommands(program);
49
+ registerPortfolioCommands(program);
50
+ registerSwapCommands(program);
51
+ program.parseAsync().catch((err) => {
52
+ console.error(`[gmgn-cli] ${err.message}`);
53
+ process.exit(1);
54
+ });
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW;OAClD,OAAO,CAAC,GAAG,CAAC,UAAU,IAAK,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;AAChE,IAAI,KAAK,EAAE,CAAC;IACV,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACzD,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,mBAAmB,CAAC,IAAI,KAAK,CAAC;YAC5B,8DAA8D;YAC9D,OAAO,EAAE,KAAK,EAAE,OAAY,EAAE,QAAa,EAAE,EAAE;gBAC7C,IAAI,CAAC;oBACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,gBAAgB,CAAC;wBACpD,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE;wBACnE,OAAO,EAAE,SAAS;wBAClB,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,QAAS,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,IAAK,EAAE;qBAC/D,CAAC,CAAC;oBACH,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;wBAClC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;oBAClI,CAAC;yBAAM,CAAC;wBACN,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;oBACzB,CAAC;gBACH,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,QAAQ,CAAC,GAAY,EAAE,IAAI,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;SACF,CAAC,CAAC,CAAC;IACN,CAAC;SAAM,CAAC;QACN,mBAAmB,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,gEAAgE,CAAC,CAAC;AAEjF,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,yBAAyB,CAAC,OAAO,CAAC,CAAC;AACnC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAE9B,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACjC,OAAO,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function printResult(data: unknown, raw?: boolean): void;
2
+ export declare function exitOnError(err: Error): never;
3
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAM9D;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,KAAK,GAAG,KAAK,CAY7C"}
package/dist/output.js ADDED
@@ -0,0 +1,22 @@
1
+ export function printResult(data, raw) {
2
+ if (raw) {
3
+ console.log(JSON.stringify(data));
4
+ }
5
+ else {
6
+ console.log(JSON.stringify(data, null, 2));
7
+ }
8
+ }
9
+ export function exitOnError(err) {
10
+ console.error(`[gmgn-cli] ${err.message}`);
11
+ if (process.env.GMGN_DEBUG) {
12
+ if (err.code) {
13
+ console.error(`[gmgn-cli] code: ${err.code}`);
14
+ }
15
+ if (err.cause) {
16
+ console.error(`[gmgn-cli] cause: ${err.cause}`);
17
+ }
18
+ console.error(err.stack ?? "");
19
+ }
20
+ process.exit(1);
21
+ }
22
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,IAAa,EAAE,GAAa;IACtD,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAU;IACpC,OAAO,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QAC3B,IAAK,GAA6B,CAAC,IAAI,EAAE,CAAC;YACxC,OAAO,CAAC,KAAK,CAAC,oBAAqB,GAA6B,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC;QACD,IAAK,GAA2B,CAAC,KAAK,EAAE,CAAC;YACvC,OAAO,CAAC,KAAK,CAAC,qBAAsB,GAA2B,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "gmgn-cli",
3
+ "version": "1.0.0",
4
+ "description": "GMGN OpenAPI CLI — call GMGN market, token, portfolio and swap APIs from the command line",
5
+ "type": "module",
6
+ "bin": {
7
+ "gmgn-cli": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "files": [
11
+ "dist",
12
+ "skills",
13
+ ".claude-plugin",
14
+ ".cursor-plugin"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "dev": "tsx src/index.ts",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "dependencies": {
22
+ "commander": "^12.1.0",
23
+ "dotenv": "^16.4.5",
24
+ "socks": "^2.8.7",
25
+ "undici": "^7.24.1"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22.0.0",
29
+ "tsx": "^4.19.0",
30
+ "typescript": "^5.5.0"
31
+ },
32
+ "engines": {
33
+ "node": ">=18.0.0"
34
+ },
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/gmgn-ai/gmgn-skills"
39
+ },
40
+ "keywords": [
41
+ "gmgn",
42
+ "crypto",
43
+ "solana",
44
+ "token",
45
+ "defi",
46
+ "swap",
47
+ "portfolio",
48
+ "market",
49
+ "claude-skill"
50
+ ]
51
+ }
@@ -0,0 +1,144 @@
1
+ ---
2
+ name: gmgn-market
3
+ description: Query GMGN market data — token K-line (candlestick) and trending token swap data. Supports sol / bsc / base.
4
+ 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 <1h|3h|6h|24h>"
5
+ ---
6
+
7
+ Use the `gmgn-cli` tool to query K-line data for a token or browse trending tokens.
8
+
9
+ ## Sub-commands
10
+
11
+ | Sub-command | Description |
12
+ |-------------|-------------|
13
+ | `market kline` | Token candlestick data |
14
+ | `market trending` | Trending token swap data |
15
+
16
+ ## Supported Chains
17
+
18
+ `sol` / `bsc` / `base`
19
+
20
+ ## Prerequisites
21
+
22
+ - `.env` file with `GMGN_API_KEY` set
23
+ - Run from the directory where your `.env` file is located, or set `GMGN_HOST` in your environment
24
+
25
+ ## Kline Parameters
26
+
27
+ | Parameter | Required | Description |
28
+ |-----------|----------|-------------|
29
+ | `--chain` | Yes | `sol` / `bsc` / `base` |
30
+ | `--address` | Yes | Token contract address |
31
+ | `--resolution` | Yes | Candlestick resolution |
32
+ | `--from` | No | Start time (Unix seconds) |
33
+ | `--to` | No | End time (Unix seconds) |
34
+
35
+ ## Resolutions
36
+
37
+ `1m` / `5m` / `15m` / `1h` / `4h` / `1d`
38
+
39
+ ## Trending Options
40
+
41
+ | Option | Description |
42
+ |--------|-------------|
43
+ | `--chain` | Required. `sol` / `bsc` / `base` |
44
+ | `--interval` | Required. `1h` / `3h` / `6h` / `24h` |
45
+ | `--limit <n>` | Number of results (default 100, max 100) |
46
+ | `--orderby <field>` | Sort field: `score` / `volume` / `swaps` / `liquidity` / `marketcap` / `holders` / `price` / `change` / `change1m` / `change5m` / `change1h` / `renowned_count` / `smart_degen_count` / `bluechip_owner_percentage` / `rank` / `creation_timestamp` / `square_mentions` / `history_highest_market_cap` / `gas_fee` |
47
+ | `--direction <asc\|desc>` | Sort direction (default `desc`) |
48
+ | `--filter <tag...>` | Repeatable filter tags: `has_social` / `not_risk` / `not_honeypot` / `verified` / `locked` / `renounced` / `distributed` / `frozen` / `burn` / `token_burnt` / `creator_hold` / `creator_close` / `creator_add_liquidity` / `creator_remove_liquidity` / `creator_sell` / `creator_buy` / `not_wash_trading` / `not_social_dup` / `not_image_dup` / `is_internal_market` / `is_out_market` |
49
+ | `--platform <name...>` | Repeatable platform filter: `pump` / `moonshot` / `launchlab` |
50
+
51
+ ## Usage Examples
52
+
53
+ ```bash
54
+ # Last 1 hour of 1-minute candles
55
+ # macOS:
56
+ npx gmgn-cli market kline \
57
+ --chain sol \
58
+ --address <token_address> \
59
+ --resolution 1m \
60
+ --from $(date -v-1H +%s) \
61
+ --to $(date +%s)
62
+ # Linux: use $(date -d '1 hour ago' +%s) instead of $(date -v-1H +%s)
63
+
64
+ # Last 24 hours of 1-hour candles
65
+ # macOS:
66
+ npx gmgn-cli market kline \
67
+ --chain sol \
68
+ --address <token_address> \
69
+ --resolution 1h \
70
+ --from $(date -v-24H +%s) \
71
+ --to $(date +%s)
72
+ # Linux: use $(date -d '24 hours ago' +%s) instead of $(date -v-24H +%s)
73
+
74
+ # Top 20 hot tokens on SOL in the last 1 hour, sorted by volume
75
+ npx gmgn-cli market trending --chain sol --interval 1h --orderby volume --limit 20
76
+
77
+ # Hot tokens with social links only, not risky, on BSC over 24h
78
+ npx gmgn-cli market trending \
79
+ --chain bsc --interval 24h \
80
+ --filter has_social --filter not_risk
81
+
82
+ # Pump platform tokens on SOL, last 6 hours
83
+ npx gmgn-cli market trending --chain sol --interval 6h --platform pump
84
+
85
+ # Raw output for further processing
86
+ npx gmgn-cli market kline --chain sol --address <addr> \
87
+ --resolution 5m --from <ts> --to <ts> --raw | jq '.[]'
88
+ ```
89
+
90
+ ## Workflow: Discover Trading Opportunities via Trending
91
+
92
+ ### Step 1 — Fetch trending data
93
+
94
+ Fetch a broad pool with safe filters, sorted by GMGN's composite score:
95
+
96
+ ```bash
97
+ npx gmgn-cli market trending \
98
+ --chain <chain> --interval 1h \
99
+ --orderby score --limit 50 \
100
+ --filter not_risk --filter not_honeypot --filter has_social --raw
101
+ ```
102
+
103
+ ### Step 2 — AI multi-factor analysis
104
+
105
+ Analyze each record in the response using the following signals (apply judgment, not rigid rules):
106
+
107
+ | Signal | Field(s) | Weight | Notes |
108
+ |--------|----------|--------|-------|
109
+ | GMGN quality score | `score` | High | Primary ranking signal from GMGN |
110
+ | Smart money interest | `smart_degen_count`, `renowned_count` | High | Key conviction indicator |
111
+ | Bluechip ownership | `bluechip_owner_percentage` | Medium | Quality of holder base |
112
+ | Real trading activity | `volume`, `swaps` | Medium | Distinguishes genuine interest from wash trading |
113
+ | Price momentum | `change1h`, `change5m` | Medium | Prefer positive, non-parabolic moves |
114
+ | Pool safety | `liquidity` | Medium | Low liquidity = high slippage risk |
115
+ | Token maturity | `creation_timestamp` | Low | Avoid tokens less than ~1h old unless other signals are very strong |
116
+
117
+ Select the **top 5** tokens with the best composite profile. Prefer tokens that score well across multiple signals rather than excelling in just one.
118
+
119
+ ### Step 3 — Present top 5 to user
120
+
121
+ Present results as a concise table, then give a one-line rationale for each pick:
122
+
123
+ ```
124
+ Top 5 Trending Tokens — SOL / 1h
125
+
126
+ # | Symbol | Address (short) | Score | Smart Degens | Volume | 1h Chg | Reasoning
127
+ 1 | ... | ... | ... | ... | ... | ... | High score + smart money accumulating
128
+ 2 | ...
129
+ ...
130
+ ```
131
+
132
+ ### Step 4 — Follow-up actions
133
+
134
+ For each token, offer:
135
+ - **Deep dive**: `token info` + `token security` for full due diligence
136
+ - **Swap**: execute directly if the user is satisfied with the trending data alone
137
+
138
+ ## Notes
139
+
140
+ - `market kline`: `--from` and `--to` are Unix timestamps in **seconds** — CLI converts to milliseconds automatically
141
+ - `market trending`: `--filter` and `--platform` are repeatable flags
142
+ - All commands use normal auth (API Key only, no signature)
143
+ - If the user doesn't provide kline timestamps, calculate them from the current time based on their desired time range
144
+ - Use `--raw` to get single-line JSON for further processing
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: gmgn-portfolio
3
+ description: Query GMGN wallet portfolio — API Key wallet info, holdings, transaction activity, trading stats, and token balance. Supports sol / bsc / base.
4
+ argument-hint: "<info|holdings|activity|stats|token-balance> [--chain <sol|bsc|base>] [--wallet <wallet_address>]"
5
+ ---
6
+
7
+ Use the `gmgn-cli` tool to query wallet portfolio data based on the user's request.
8
+
9
+ ## Sub-commands
10
+
11
+ | Sub-command | Description |
12
+ |-------------|-------------|
13
+ | `portfolio info` | Wallets and main currency balances bound to the API Key |
14
+ | `portfolio holdings` | Wallet token holdings with P&L |
15
+ | `portfolio activity` | Transaction history |
16
+ | `portfolio stats` | Trading statistics (supports batch) |
17
+ | `portfolio token-balance` | Token balance for a specific token |
18
+
19
+ ## Supported Chains
20
+
21
+ `sol` / `bsc` / `base`
22
+
23
+ ## Prerequisites
24
+
25
+ - `.env` file with `GMGN_API_KEY` set
26
+ - Run from the directory where your `.env` file is located, or set `GMGN_HOST` in your environment
27
+
28
+ ## Usage Examples
29
+
30
+ ```bash
31
+ # API Key wallet info (no --chain or --wallet needed)
32
+ npx gmgn-cli portfolio info
33
+
34
+ # Wallet holdings (default sort)
35
+ npx gmgn-cli portfolio holdings --chain sol --wallet <wallet_address>
36
+
37
+ # Holdings sorted by USD value, descending
38
+ npx gmgn-cli portfolio holdings \
39
+ --chain sol --wallet <wallet_address> \
40
+ --order-by usd_value --direction desc --limit 20
41
+
42
+ # Include sold-out positions
43
+ npx gmgn-cli portfolio holdings --chain sol --wallet <wallet_address> --sell-out
44
+
45
+ # Transaction activity
46
+ npx gmgn-cli portfolio activity --chain sol --wallet <wallet_address>
47
+
48
+ # Activity filtered by type
49
+ npx gmgn-cli portfolio activity --chain sol --wallet <wallet_address> \
50
+ --type buy --type sell
51
+
52
+ # Activity for a specific token
53
+ npx gmgn-cli portfolio activity --chain sol --wallet <wallet_address> \
54
+ --token <token_address>
55
+
56
+ # Trading stats (default 7d)
57
+ npx gmgn-cli portfolio stats --chain sol --wallet <wallet_address>
58
+
59
+ # Trading stats for 30 days
60
+ npx gmgn-cli portfolio stats --chain sol --wallet <wallet_address> --period 30d
61
+
62
+ # Batch stats for multiple wallets
63
+ npx gmgn-cli portfolio stats --chain sol \
64
+ --wallet <wallet_1> --wallet <wallet_2>
65
+
66
+ # Token balance
67
+ npx gmgn-cli portfolio token-balance \
68
+ --chain sol --wallet <wallet_address> --token <token_address>
69
+ ```
70
+
71
+ ## Holdings Options
72
+
73
+ | Option | Description |
74
+ |--------|-------------|
75
+ | `--limit <n>` | Page size (default `20`, max 50) |
76
+ | `--cursor <cursor>` | Pagination cursor |
77
+ | `--order-by <field>` | Sort field: `usd_value` / `price` / `unrealized_profit` / `realized_profit` / `total_profit` / `history_bought_cost` / `history_sold_income` (default `usd_value`) |
78
+ | `--direction <asc\|desc>` | Sort direction (default `desc`) |
79
+ | `--sell-out` | Include sold-out positions |
80
+ | `--show-small` | Include small-value positions |
81
+ | `--hide-abnormal` | Hide abnormal positions |
82
+ | `--hide-airdrop` | Hide airdrop positions |
83
+ | `--hide-closed` | Hide closed positions |
84
+ | `--hide-open` | Hide open positions |
85
+
86
+ ## Activity Options
87
+
88
+ | Option | Description |
89
+ |--------|-------------|
90
+ | `--token <address>` | Filter by token |
91
+ | `--limit <n>` | Page size |
92
+ | `--cursor <cursor>` | Pagination cursor |
93
+ | `--type <type>` | Repeatable: `buy` / `sell` / `add` / `remove` / `transfer` |
94
+
95
+ ## Stats Options
96
+
97
+ | Option | Description |
98
+ |--------|-------------|
99
+ | `--period <period>` | Stats period: `7d` / `30d` (default `7d`) |
100
+
101
+ ## Notes
102
+
103
+ - All portfolio commands use normal auth (API Key only, no signature required)
104
+ - `portfolio stats` supports multiple `--wallet` flags for batch queries
105
+ - Use `--raw` to get single-line JSON for further processing