mirror of
https://github.com/GMGNAI/gmgn-skills.git
synced 2026-08-22 20:48:05 +00:00
initial import
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import { Command } from "commander";
|
||||
import { OpenApiClient } from "../client/OpenApiClient.js";
|
||||
import { getConfig } from "../config.js";
|
||||
import { exitOnError, printResult } from "../output.js";
|
||||
import { validateAddress, validateChain } from "../validate.js";
|
||||
|
||||
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("--address <address>", "Token contract address")
|
||||
.requiredOption("--resolution <resolution>", "Candlestick resolution: 1m / 5m / 15m / 1h / 4h / 1d")
|
||||
.requiredOption("--from <timestamp>", "Start time (Unix seconds)", parseInt)
|
||||
.requiredOption("--to <timestamp>", "End time (Unix seconds)", parseInt)
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.address, opts.chain, "--address");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client
|
||||
.getTokenKline(opts.chain, opts.address, opts.resolution, opts.from * 1000, opts.to * 1000)
|
||||
.catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
market
|
||||
.command("trending")
|
||||
.description("Get trending token swap data")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--interval <interval>", "Time interval: 1h / 3h / 6h / 24h")
|
||||
.option("--limit <n>", "Number of results (default 100, max 100)", parseInt)
|
||||
.option("--orderby <field>", "Sort field: score / volume / swaps / liquidity / marketcap / holders / price / change / ...")
|
||||
.option("--direction <dir>", "Sort direction: asc / desc")
|
||||
.option("--filter <tag...>", "Filter tags, repeatable: has_social / not_risk / not_honeypot / verified / locked / renounced / ...")
|
||||
.option("--platform <name...>", "Platform filter, repeatable: pump / moonshot / ...")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
const extra: Record<string, string | number | string[]> = {};
|
||||
if (opts.limit != null) extra["limit"] = opts.limit;
|
||||
if (opts.orderby) extra["order_by"] = opts.orderby;
|
||||
if (opts.direction) extra["direction"] = opts.direction;
|
||||
if (opts.filter?.length) extra["filters"] = opts.filter;
|
||||
if (opts.platform?.length) extra["platforms"] = opts.platform;
|
||||
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTrendingSwaps(opts.chain, opts.interval, extra).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import { Command } from "commander";
|
||||
import { OpenApiClient } from "../client/OpenApiClient.js";
|
||||
import { getConfig } from "../config.js";
|
||||
import { exitOnError, printResult } from "../output.js";
|
||||
import { validateAddress, validateChain } from "../validate.js";
|
||||
|
||||
export function registerPortfolioCommands(program: Command): void {
|
||||
const portfolio = program.command("portfolio").description("Wallet portfolio commands");
|
||||
|
||||
portfolio
|
||||
.command("holdings")
|
||||
.description("Get wallet token holdings")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--wallet <address>", "Wallet address")
|
||||
.option("--limit <n>", "Page size (default 20, max 50)", parseInt, 20)
|
||||
.option("--cursor <cursor>", "Pagination cursor")
|
||||
.option("--order-by <field>", "Sort field: usd_value / price / price_change / unrealized_profit / realized_profit / ...", "usd_value")
|
||||
.option("--direction <dir>", "Sort direction: asc / desc", "desc")
|
||||
.option("--interval <interval>", "Stats interval (default 24h)")
|
||||
.option("--sell-out", "Include sold-out positions")
|
||||
.option("--show-small", "Include small-value positions")
|
||||
.option("--hide-abnormal", "Hide abnormal positions")
|
||||
.option("--hide-airdrop", "Hide airdrop positions")
|
||||
.option("--hide-closed", "Hide closed positions")
|
||||
.option("--hide-open", "Hide open positions")
|
||||
.option("--tx30d", "Only show positions with trades in last 30 days")
|
||||
.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.limit != null) extra["limit"] = opts.limit;
|
||||
if (opts.cursor) extra["cursor"] = opts.cursor;
|
||||
if (opts.orderBy) extra["order_by"] = opts.orderBy;
|
||||
if (opts.direction) extra["direction"] = opts.direction;
|
||||
if (opts.interval) extra["interval"] = opts.interval;
|
||||
if (opts.sellOut) extra["sell_out"] = "true";
|
||||
if (opts.showSmall) extra["show_small"] = "true";
|
||||
if (opts.hideAbnormal) extra["hide_abnormal"] = "true";
|
||||
if (opts.hideAirdrop) extra["hide_airdrop"] = "true";
|
||||
if (opts.hideClosed) extra["hide_closed"] = "true";
|
||||
if (opts.hideOpen) extra["hide_open"] = "true";
|
||||
if (opts.tx30d) extra["tx30d"] = "true";
|
||||
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getWalletHoldings(opts.chain, opts.wallet, extra).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
portfolio
|
||||
.command("activity")
|
||||
.description("Get wallet transaction activity")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--wallet <address>", "Wallet address")
|
||||
.option("--token <address>", "Filter by token contract address")
|
||||
.option("--limit <n>", "Page size", parseInt)
|
||||
.option("--cursor <cursor>", "Pagination cursor")
|
||||
.option("--type <type...>", "Activity type filter, repeatable: buy / sell / add / remove / transfer")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.wallet, opts.chain, "--wallet");
|
||||
if (opts.token) validateAddress(opts.token, opts.chain, "--token");
|
||||
const extra: Record<string, string | number | string[]> = {};
|
||||
if (opts.token) extra["token"] = opts.token;
|
||||
if (opts.limit != null) extra["limit"] = opts.limit;
|
||||
if (opts.cursor) extra["cursor"] = opts.cursor;
|
||||
if (opts.type?.length) extra["type"] = opts.type;
|
||||
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getWalletActivity(opts.chain, opts.wallet, extra).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
portfolio
|
||||
.command("stats")
|
||||
.description("Get wallet trading statistics (supports multiple wallets)")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--wallet <address...>", "Wallet address(es), repeatable")
|
||||
.option("--period <period>", "Stats period: 7d / 30d", "7d")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
for (const w of opts.wallet as string[]) validateAddress(w, opts.chain, "--wallet");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getWalletStats(opts.chain, opts.wallet, opts.period).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
portfolio
|
||||
.command("info")
|
||||
.description("Get wallets and main currency balances bound to the API Key")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getUserInfo().catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
portfolio
|
||||
.command("token-balance")
|
||||
.description("Get wallet token balance for a single token")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--wallet <address>", "Wallet address")
|
||||
.requiredOption("--token <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.wallet, opts.chain, "--wallet");
|
||||
validateAddress(opts.token, opts.chain, "--token");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getWalletTokenBalance(opts.chain, opts.wallet, opts.token).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Command } from "commander";
|
||||
import { OpenApiClient, SwapParams } from "../client/OpenApiClient.js";
|
||||
import { getConfig } from "../config.js";
|
||||
import { exitOnError, printResult } from "../output.js";
|
||||
import { validateAddress, validateChain, validatePercent, validatePositiveInt } from "../validate.js";
|
||||
|
||||
export function registerSwapCommands(program: Command): void {
|
||||
program
|
||||
.command("swap")
|
||||
.description("Submit a token swap")
|
||||
.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")
|
||||
.option("--amount <amount>", "Input raw amount (smallest unit)")
|
||||
.option("--percent <pct>", "Input amount as a percentage, e.g. 50 = 50%, 1 = 1%; only valid when input_token is NOT a currency", parseFloat)
|
||||
.option("--slippage <n>", "Slippage tolerance (e.g. 0.01 = 1%)", parseFloat)
|
||||
.option("--min-output <amount>", "Minimum output amount")
|
||||
.option("--anti-mev", "Enable anti-MEV protection, default true")
|
||||
.option("--priority-fee <sol>", "Priority fee in SOL (≥ 0.00001, SOL only)")
|
||||
.option("--tip-fee <amount>", "Tip fee (SOL ≥ 0.00001 SOL / BSC ≥ 0.000001 BNB)")
|
||||
.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)")
|
||||
.option("--max-priority-fee-per-gas <amount>", "EIP-1559 max priority fee per gas (Base)")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
if (opts.percent == null && !opts.amount) {
|
||||
console.error("[gmgn-cli] Either --amount or --percent must be provided");
|
||||
process.exit(1);
|
||||
}
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.from, opts.chain, "--from");
|
||||
validateAddress(opts.inputToken, opts.chain, "--input-token");
|
||||
validateAddress(opts.outputToken, opts.chain, "--output-token");
|
||||
if (opts.amount) validatePositiveInt(opts.amount, "--amount");
|
||||
if (opts.percent != null) validatePercent(opts.percent);
|
||||
const params: SwapParams = {
|
||||
chain: opts.chain,
|
||||
from_address: opts.from,
|
||||
input_token: opts.inputToken,
|
||||
output_token: opts.outputToken,
|
||||
input_amount: opts.percent != null ? (opts.amount ?? "0") : opts.amount,
|
||||
};
|
||||
if (opts.percent != null) params.input_amount_bps = String(Math.round(opts.percent * 100));
|
||||
if (opts.slippage != null) params.slippage = opts.slippage;
|
||||
if (opts.minOutput) params.min_output_amount = opts.minOutput;
|
||||
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.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;
|
||||
|
||||
const client = new OpenApiClient(getConfig(true));
|
||||
const data = await client.swap(params).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
const order = program.command("order").description("Order management commands");
|
||||
|
||||
order
|
||||
.command("get")
|
||||
.description("Query order status (requires private key)")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth / monad")
|
||||
.requiredOption("--order-id <id>", "Order ID")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
const client = new OpenApiClient(getConfig(true));
|
||||
const data = await client.queryOrder(opts.orderId, opts.chain).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { Command } from "commander";
|
||||
import { OpenApiClient } from "../client/OpenApiClient.js";
|
||||
import { getConfig } from "../config.js";
|
||||
import { exitOnError, printResult } from "../output.js";
|
||||
import { validateAddress, validateChain } from "../validate.js";
|
||||
|
||||
export function registerTokenCommands(program: Command): void {
|
||||
const token = program.command("token").description("Token information commands");
|
||||
|
||||
token
|
||||
.command("info")
|
||||
.description("Get token basic information and realtime price")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.address, opts.chain, "--address");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTokenInfo(opts.chain, opts.address).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
token
|
||||
.command("security")
|
||||
.description("Get token security metrics")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.address, opts.chain, "--address");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTokenSecurity(opts.chain, opts.address).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
token
|
||||
.command("pool")
|
||||
.description("Get token liquidity pool information")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.address, opts.chain, "--address");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTokenPoolInfo(opts.chain, opts.address).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
token
|
||||
.command("holders")
|
||||
.description("Get top token holders")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.address, opts.chain, "--address");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTokenTopHolders(opts.chain, opts.address).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
token
|
||||
.command("traders")
|
||||
.description("Get top token traders")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base")
|
||||
.requiredOption("--address <address>", "Token contract address")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
validateAddress(opts.address, opts.chain, "--address");
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTokenTopTraders(opts.chain, opts.address).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user