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: sol / bsc / base / eth / robinhood") .requiredOption("--wallet
", "Wallet address") .option("--limit ", "Page size (default 20, max 50)", parseInt, 20) .option("--cursor ", "Pagination cursor") .option("--order-by ", "Sort field: usd_value / last_active_timestamp / realized_profit / unrealized_profit / total_profit / history_bought_cost / history_sold_income", "usd_value") .option("--direction ", "Sort direction: asc / desc", "desc") .option("--interval ", "Stats interval (default 24h)") .option("--hide-abnormal ", "Hide abnormal positions (default: false)", "false") .option("--hide-airdrop ", "Hide airdrop positions (default: true)", "true") .option("--hide-closed ", "Hide closed positions (default: true)", "true") .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 = {}; 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; extra["hide_abnormal"] = opts.hideAbnormal; extra["hide_airdrop"] = opts.hideAirdrop; extra["hide_closed"] = opts.hideClosed; 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: sol / bsc / base / eth / robinhood") .requiredOption("--wallet
", "Wallet address") .option("--token
", "Filter by token contract address") .option("--limit ", "Page size", parseInt) .option("--cursor ", "Pagination cursor") .option("--type ", "Activity type filter, repeatable: buy / sell / transferIn / transferOut / add / remove") .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 = {}; if (opts.token) extra["token_address"] = 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: sol / bsc / base / eth / robinhood") .requiredOption("--wallet ", "Wallet address(es), repeatable") .option("--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: sol / bsc / base / eth / robinhood") .requiredOption("--wallet
", "Wallet address") .requiredOption("--token
", "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); }); portfolio .command("created-tokens") .description("Get tokens created by a developer wallet") .requiredOption("--chain ", "Chain: sol / bsc / base / eth / robinhood") .requiredOption("--wallet
", "Developer wallet address") .option("--order-by ", "Sort field: market_cap / token_ath_mc") .option("--direction ", "Sort direction: asc / desc") .option("--migrate-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 = {}; 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); }); }