nansen-cli 1.27.1 → 1.29.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#423](https://github.com/nansen-ai/nansen-cli/pull/423) [`d10aa57`](https://github.com/nansen-ai/nansen-cli/commit/d10aa575c31f7702241ad114276fa5234f2bdf59) Thanks [@imhta](https://github.com/imhta)! - Add Relay aggregator support for Base↔Solana cross-chain swaps. Users now see Relay quotes alongside Li.Fi in `nansen trade quote --to-chain ...`, can execute them through `trade execute`, and optionally use Relay's gasless path with `--gasless` (local/Privy wallets only — not WalletConnect). `trade bridge-status` auto-detects which aggregator produced a tx (via a local tx record) and polls the right backend.
8
+
9
+ ## 1.28.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#417](https://github.com/nansen-ai/nansen-cli/pull/417) [`ae6079f`](https://github.com/nansen-ai/nansen-cli/commit/ae6079f12d06d11fe357237b84387fcaffcfd387) Thanks [@0xlaveen](https://github.com/0xlaveen)! - Add `trade limit-order` commands (create, list, cancel, update) for Jupiter Limit Order V2 on Solana. Supports local, Privy, and WalletConnect wallets.
14
+
15
+ - [#413](https://github.com/nansen-ai/nansen-cli/pull/413) [`94bd349`](https://github.com/nansen-ai/nansen-cli/commit/94bd349bdf9a0a3f3389975144281306eea0e4ca) Thanks [@jake-kennis](https://github.com/jake-kennis)! - Add `top-tokens` subcommand to discover top-scoring tokens by Nansen Score. Calls the public endpoint (`/api/v1/nansen-score/top-tokens`) with optional `--market-cap` filter.
16
+
3
17
  ## 1.27.1
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -51,7 +51,16 @@ nansen trade quote --chain solana --from SOL --to USDC --amount 1000000000
51
51
  nansen trade execute --quote <quoteId>
52
52
  ```
53
53
 
54
- Amounts are in base units (lamports, wei). Common symbols (`SOL`, `ETH`, `USDC`, `USDT`) resolve automatically. A wallet is required set one with `nansen wallet default <name>`.
54
+ Cross-chain swaps work the same way add `--to-chain`. Bridge providers (Li.Fi or Relay) are selected automatically based on best price.
55
+
56
+ ```bash
57
+ nansen trade quote --chain base --to-chain solana --from ETH --to SOL --amount 0.0003 --amount-unit token
58
+ nansen trade execute --quote <quoteId> # signed broadcast
59
+ nansen trade execute --quote <quoteId> --gasless # Relay-only: solver pays gas
60
+ nansen trade bridge-status --tx-hash <hash> --from-chain base --to-chain solana
61
+ ```
62
+
63
+ Amounts are in base units (lamports, wei) by default — use `--amount-unit token|usd|percent` for friendlier inputs. Common symbols (`SOL`, `ETH`, `USDC`, `USDT`) resolve automatically. A wallet is required — set one with `nansen wallet default <name>`.
55
64
 
56
65
  ## Wallet
57
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nansen-cli",
3
- "version": "1.27.1",
3
+ "version": "1.29.0",
4
4
  "description": "Command-line interface for Nansen API - designed for AI agents",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -45,10 +45,64 @@ nansen research token indicators --token $TOKEN --chain $CHAIN
45
45
  # Flow intelligence — only use for promising tokens from screener/indicators above
46
46
  nansen research token flow-intelligence --token $TOKEN --chain $CHAIN
47
47
  # → net_flow_usd per label: smart_trader, whale, exchange, fresh_wallets, public_figure
48
+
49
+ # Nansen Score Top Tokens — "what should I buy?" (public endpoint, any authenticated API key)
50
+ # Use this FIRST for discovery, then drill into individual tokens with `indicators` above
51
+ nansen research token top-tokens --limit 25
52
+ nansen research token top-tokens --market-cap largecap --limit 10
53
+ # → chain, token_address, token_symbol, performance_score, risk_score,
54
+ # per-indicator contributions, market_cap_group, latest_date, last_trigger_on
48
55
  ```
49
56
 
50
57
  Screener timeframes: `5m`, `10m`, `1h`, `6h`, `24h`, `7d`, `30d`
51
58
 
52
59
  Indicators: score is "bullish"/"bearish"/"neutral". signal_percentile > 70 = historically significant. Some tokens return empty indicators — not an error.
53
60
 
61
+ ## Top tokens — Nansen Score field reference
62
+
63
+ Results are pre-filtered to `performance_score >= 15` server-side and returned sorted by:
64
+ 1. `performance_score` DESC
65
+ 2. `market_cap_group` priority (largecap → midcap → lowcap)
66
+ 3. `risk_score` DESC
67
+ 4. 24h volume DESC
68
+
69
+ So row 0 is always the strongest candidate for the filter you applied — no client-side ranking needed.
70
+
71
+ Market cap buckets (used in both the sort priority and the `--market-cap` filter):
72
+ - `lowcap`: market cap < $100M
73
+ - `midcap`: market cap $100M – $1B
74
+ - `largecap`: market cap > $1B
75
+
76
+ Every contribution is **ternary** — exactly one of `{negative, 0, positive}` per field. No partial values. Zero means "indicator didn't apply to this token" (out of scope), not "indicator was neutral".
77
+
78
+ **Performance Score (Alpha — "likely to outperform BTC over 7–30d")**
79
+ Range: `-60 to +75` (arithmetic bounds; live max is closer to `+45` since no single token hits every positive indicator simultaneously). Buy threshold: `>= 15`. Sum of the five `*_performance` fields below.
80
+ | Field | Contribution | Trigger | What the underlying indicator measures |
81
+ |---|---|---|---|
82
+ | `price_momentum_performance` | +30 / 0 | upstream score `bullish` → +30 | Price momentum, scored against separate thresholds for large-cap vs. low/mid-cap tokens. |
83
+ | `chain_fees_performance` | +30 / 0 | `bullish` (30-day fee growth > +1%) → +30 | 30-day spending momentum on network fees (geometric mean of daily returns). **Only tracked for a handful of L1 native tokens (e.g. ETH, TRX, AVAX, RON); always 0 for every other token.** |
84
+ | `trading_range_performance` | +15 / 0 | `bullish` (price breaks above resistance in an uptrend) → +15 | 14-day price trend combined with position vs. nearest support/resistance. In practice fires mostly on established tokens that have well-defined levels — can fire at any market cap, but is rare for new / low-liquidity tokens. |
85
+ | `chain_tvl_performance` | 0 / -35 | `bearish` (composite TVL growth < 0) → -35 | TVL momentum composite signal. Only non-zero for chains / L2s whose TVL is tracked. No positive path exists — the field only deducts. |
86
+ | `protocol_fees_performance` | 0 / -25 | `bearish` (14-day fee growth < -3%) → -25 | 14-day protocol fee momentum. Only non-zero for tokens backed by protocols with measurable fee revenue. No positive path — deduction only. |
87
+
88
+ **Risk Score (Safety — "filters falling knives / dangerous setups")**
89
+ Range: `-60 to +80` (arithmetic bounds). Safety threshold: `> 0` (positive = safer, negative = riskier). Sum of the four `*_risk` fields below. For every risk field: upstream score `low` → positive contribution, `high` → negative contribution, `medium`/missing → 0.
90
+ | Field | Contribution | What the underlying indicator measures |
91
+ |---|---|---|
92
+ | `btc_reflexivity_risk` | +40 / -20 | Rolling 5-event median ratio of token drop to BTC drop on days BTC falls >3%. Ratio ≤ 1 → `low` → **+40** (token holds up as well as or better than BTC on drawdowns). Ratio > 1 → `high` → **-20** (token drops harder than BTC). Skipped for stablecoins and tokens with <$1M 24h volume. |
93
+ | `liquidity_risk` | +20 / -20 | Ratio of on-chain liquidity to market cap (`total_liquidity_usd / market_cap_usd`). Higher ratio → `low` → **+20** (deep books relative to cap). Very thin ratio → `high` → **-20**. |
94
+ | `concentration_risk` | +10 / -10 | Top-10 holder concentration as a fraction of supply. `< 0.12` → `low` → **+10** (well-distributed). `> 0.55` → `high` → **-10** (whale-concentrated). |
95
+ | `inflation_risk` | +10 / -10 | EMA of daily token supply inflation rate. Negative / near-zero → `low` → **+10** (stable or deflationary supply). Strongly positive → `high` → **-10** (high dilution). Only evaluated for tokens >= $100M market cap. |
96
+
97
+ Other response fields:
98
+ - `market_cap_group`: `lowcap` / `midcap` / `largecap` — see thresholds above.
99
+ - `latest_date`: ISO datetime of the most recent indicator refresh for this token.
100
+ - `last_trigger_on`: ISO datetime of the most recent trigger across contributing indicators (MAX aggregate — individual indicators may be days-to-months stale even when this looks fresh). Use `indicators` on a specific token to audit per-indicator ages.
101
+
102
+ **Stablecoins rank high but aren't picks.** USDC, USDT, DAI, FDUSD and similar score well on chain_fees + liquidity indicators but aren't what "what should I buy" means. Filter them out of the shortlist using the canonical whitelist at `nansen-dbt-ch-tokens/seeds/stablecoins_for_indicator.csv` before drilling into `indicators`.
103
+
104
+ Typical workflow: start with `top-tokens` for a shortlist → drop stablecoins → run `indicators` on the top 3–5 to inspect individual signals and their signal_percentile → `flow-intelligence` only on the finalists to confirm SM conviction.
105
+
106
+ Field meanings and contribution mappings above are sourced from `nansen-dbt-ch-tokens/models/indicators/api_nansen_score_indicators_all_tokens_latest.sql` and per-indicator model yml files. Sign conventions and live value ranges were validated against production ClickHouse data.
107
+
54
108
  Flow intelligence is credit-heavy. Use it to confirm SM conviction on tokens that already look promising from screener + indicators, not as a first pass on every token.
package/src/api.js CHANGED
@@ -1203,6 +1203,13 @@ export class NansenAPI {
1203
1203
  });
1204
1204
  }
1205
1205
 
1206
+ async topTokens(params = {}) {
1207
+ const { marketCapGroup, limit = 25 } = params;
1208
+ const body = { limit };
1209
+ if (marketCapGroup) body.market_cap_group = marketCapGroup;
1210
+ return this.request('/api/v1/nansen-score/top-tokens', body);
1211
+ }
1212
+
1206
1213
  // ============= Perp Endpoints =============
1207
1214
 
1208
1215
  async perpScreener(params = {}) {
package/src/cli.js CHANGED
@@ -6,6 +6,7 @@
6
6
  import { NansenAPI, NansenError, CommandError, ErrorCode, saveConfig, deleteConfig, getConfigFile, clearCache, getCacheDir, validateAddress, normalizeAddress, sleep } from './api.js';
7
7
  import { buildWalletCommands } from './wallet.js';
8
8
  import { buildTradingCommands } from './trading.js';
9
+ import { buildLimitOrderCommands } from './limit-order.js';
9
10
  import { formatAlertsTable, buildAlertsCommands } from './commands/alerts.js';
10
11
  import { buildAgentCommands } from './commands/agent.js';
11
12
  import { resolveAddress, isEnsName } from './ens.js';
@@ -1276,8 +1277,13 @@ export function buildCommands(deps = {}) {
1276
1277
  const withLabels = resolveBooleanOption(options, flags, 'premium-labels');
1277
1278
  return apiInstance.tokenPerpPnlLeaderboard({ tokenSymbol, filters, orderBy, pagination, days, withLabels });
1278
1279
  },
1280
+ 'top-tokens': () => {
1281
+ const marketCapGroup = options['market-cap'] || options['market-cap-group'];
1282
+ const limit = options.limit ? parseInt(options.limit) : undefined;
1283
+ return apiInstance.topTokens({ marketCapGroup, limit });
1284
+ },
1279
1285
  'help': () => ({
1280
- commands: ['info', 'ohlcv', 'screener', 'holders', 'flows', 'dex-trades', 'pnl', 'who-bought-sold', 'flow-intelligence', 'transfers', 'jup-dca', 'perp-trades', 'perp-positions', 'perp-pnl-leaderboard'],
1286
+ commands: ['info', 'ohlcv', 'screener', 'holders', 'flows', 'dex-trades', 'pnl', 'who-bought-sold', 'flow-intelligence', 'transfers', 'jup-dca', 'perp-trades', 'perp-positions', 'perp-pnl-leaderboard', 'top-tokens'],
1281
1287
  description: 'Token God Mode endpoints',
1282
1288
  example: 'nansen token screener --chain solana --timeframe 24h --smart-money --include-stablecoins false'
1283
1289
  })
@@ -1474,8 +1480,9 @@ export function buildCommands(deps = {}) {
1474
1480
  return cmds[category](args.slice(1), apiInstance, flags, options);
1475
1481
  };
1476
1482
 
1477
- // 'trade' delegates to quote/execute from buildTradingCommands
1483
+ // 'trade' delegates to quote/execute from buildTradingCommands and limit-order from buildLimitOrderCommands
1478
1484
  const tradingCmds = buildTradingCommands(deps);
1485
+ const limitOrderCmds = buildLimitOrderCommands(deps);
1479
1486
  cmds['trade'] = async (args, apiInstance, flags, options) => {
1480
1487
  const sub = args[0];
1481
1488
  if (!sub || sub === 'help') {
@@ -1485,12 +1492,14 @@ SUBCOMMANDS:
1485
1492
  quote Get a swap quote (price, route, fees)
1486
1493
  execute Sign and broadcast a quoted swap
1487
1494
  bridge-status Check cross-chain bridge transaction status
1495
+ limit-order Limit order management (Solana only)
1488
1496
 
1489
1497
  USAGE:
1490
1498
  nansen trade quote --chain <chain> --from <token> --to <token> --amount <units> [--wallet <name>]
1491
1499
  nansen trade quote --chain <chain> --to-chain <chain> --from <token> --to <token> --amount <units>
1492
1500
  nansen trade execute --quote <quoteId> [--wallet <name>]
1493
1501
  nansen trade bridge-status --tx-hash <hash> --from-chain <chain> --to-chain <chain>
1502
+ nansen trade limit-order <create|list|cancel|update> [options]
1494
1503
 
1495
1504
  EXAMPLES:
1496
1505
  nansen trade quote --chain solana --from SOL --to USDC --amount 1000000000
@@ -1498,9 +1507,11 @@ EXAMPLES:
1498
1507
  nansen trade quote --chain base --to-chain solana --from USDC --to USDC --amount 1000000
1499
1508
  nansen trade execute --quote 1708900000000-abc123
1500
1509
  nansen trade bridge-status --tx-hash 0xabc... --from-chain base --to-chain solana
1510
+ nansen trade limit-order create --from SOL --to USDC --amount 1000000000 --trigger-mint SOL --trigger-condition below --trigger-price 80
1511
+ nansen trade limit-order list
1501
1512
 
1502
1513
  WALLET:
1503
- --wallet <name> Use a named wallet, or "walletconnect" / "wc" for WalletConnect (EVM only).
1514
+ --wallet <name> Use a named wallet, or "walletconnect" / "wc" for WalletConnect.
1504
1515
  Defaults to the default local wallet if omitted.
1505
1516
 
1506
1517
  SYMBOLS:
@@ -1509,17 +1520,40 @@ SYMBOLS:
1509
1520
 
1510
1521
  CROSS-CHAIN NOTES (when using --to-chain):
1511
1522
  Supported combos:
1512
- native → native (ETH <-> SOL) — requires $5+ per trade
1523
+ native → native (ETH <-> SOL)
1513
1524
  USDC → USDC (both directions)
1514
1525
  USDC → native (USDC → ETH or SOL)
1515
1526
  native → USDC (ETH/SOL → USDC)
1516
1527
  non-native → non-native — not supported (use USDC as intermediate)
1517
- Bridge provider: Li.Fi
1528
+ Bridge providers: Li.Fi or Relay (selected automatically based on best price)
1518
1529
  Typical bridge time: 1-5 minutes`);
1519
1530
  return;
1520
1531
  }
1532
+ if (sub === 'limit-order') {
1533
+ const loSub = args[1];
1534
+ if (!loSub || loSub === 'help') {
1535
+ log(`nansen trade limit-order — Limit order commands (Solana only)
1536
+
1537
+ SUBCOMMANDS:
1538
+ create Place a new limit order
1539
+ list List your limit orders
1540
+ cancel Cancel an open order
1541
+ update Update trigger price or slippage
1542
+
1543
+ USAGE:
1544
+ nansen trade limit-order create --from <token> --to <token> --amount <units> --trigger-mint <token> --trigger-condition <above|below> --trigger-price <usd>
1545
+ nansen trade limit-order list [--state <active|past>]
1546
+ nansen trade limit-order cancel --order <orderId>
1547
+ nansen trade limit-order update --order <orderId> --trigger-price <usd>`);
1548
+ return;
1549
+ }
1550
+ if (!limitOrderCmds[loSub]) {
1551
+ throw new NansenError(`Unknown limit-order subcommand: ${loSub}. Available: create, list, cancel, update`, ErrorCode.UNKNOWN);
1552
+ }
1553
+ return limitOrderCmds[loSub](args.slice(2), apiInstance, flags, options);
1554
+ }
1521
1555
  if (!tradingCmds[sub]) {
1522
- throw new NansenError(`Unknown trade subcommand: ${sub}. Available: quote, execute, bridge-status`, ErrorCode.UNKNOWN);
1556
+ throw new NansenError(`Unknown trade subcommand: ${sub}. Available: quote, execute, bridge-status, limit-order`, ErrorCode.UNKNOWN);
1523
1557
  }
1524
1558
  return tradingCmds[sub](args.slice(1), apiInstance, flags, options);
1525
1559
  };
package/src/keychain.js CHANGED
@@ -227,3 +227,4 @@ export function deleteCredentialsFile() {
227
227
  export function resolvePassword() {
228
228
  return retrievePassword().password;
229
229
  }
230
+