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 +14 -0
- package/README.md +10 -1
- package/package.json +1 -1
- package/skills/nansen-token-screener/SKILL.md +54 -0
- package/src/api.js +7 -0
- package/src/cli.js +40 -6
- package/src/keychain.js +1 -0
- package/src/limit-order.js +873 -0
- package/src/privy.js +9 -0
- package/src/schema.json +159 -2
- package/src/telemetry.js +5 -1
- package/src/trading.js +261 -59
- package/src/transfer.js +1 -1
- package/src/walletconnect-trading.js +25 -0
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
|
-
|
|
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
|
@@ -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
|
|
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)
|
|
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
|
|
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