nansen-cli 1.10.0 → 1.11.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 +34 -0
- package/README.md +2 -2
- package/package.json +3 -2
- package/src/api.js +13 -9
- package/src/cli.js +31 -164
- package/src/index.js +4 -4
- package/src/schema.json +1684 -0
- package/src/trading.js +121 -134
- package/src/wallet.js +32 -39
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#186](https://github.com/nansen-ai/nansen-cli/pull/186) [`feecc50`](https://github.com/nansen-ai/nansen-cli/commit/feecc5080254b55aaef0addb646279d52a468063) Thanks [@TimNooren](https://github.com/TimNooren)! - Trade commands output to stdout instead of stderr; wallet send prints human-readable text instead of JSON
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#166](https://github.com/nansen-ai/nansen-cli/pull/166) [`c1034db`](https://github.com/nansen-ai/nansen-cli/commit/c1034dbb4bf2fc173f377cbc0adbbbe3e67873aa) Thanks [@0xlaveen](https://github.com/0xlaveen)! - fix: pass --page parameter correctly in smart-money, profiler, token, perp, and points commands
|
|
12
|
+
|
|
13
|
+
- [#137](https://github.com/nansen-ai/nansen-cli/pull/137) [`1214767`](https://github.com/nansen-ai/nansen-cli/commit/12147675aadfd0bd97627cb2f41f1dcc5205b0d7) Thanks [@0xlaveen](https://github.com/0xlaveen)! - Add missing sort/filters options to profiler schema and fix pnl sort/filters forwarding
|
|
14
|
+
|
|
15
|
+
## 1.10.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [#133](https://github.com/nansen-ai/nansen-cli/pull/133) [`4cbeb65`](https://github.com/nansen-ai/nansen-cli/commit/4cbeb6510c286660f611117d2d8b0508f2340e31) Thanks [@0xlaveen](https://github.com/0xlaveen)! - fix: correct profiler pagination parameter from `recordsPerPage` to `per_page`; remove unsupported pagination from pnl-summary; add --limit to labels, historical-balances, counterparties schema
|
|
20
|
+
|
|
21
|
+
- [#164](https://github.com/nansen-ai/nansen-cli/pull/164) [`ec6ab78`](https://github.com/nansen-ai/nansen-cli/commit/ec6ab78d604a177c3459833091531de3fc07add1) Thanks [@DMagowan](https://github.com/DMagowan)! - fix: correct `--date` option marked as `required: true` when it is optional
|
|
22
|
+
|
|
23
|
+
The schema incorrectly marked `--date` as `required: true` for three commands:
|
|
24
|
+
|
|
25
|
+
- `research token flows`
|
|
26
|
+
- `research token who-bought-sold`
|
|
27
|
+
- `research profiler transactions`
|
|
28
|
+
|
|
29
|
+
All three use `parseDateOption` with a `days` fallback, so `--date` is optional — omitting it defaults to a rolling window based on `--days`. An agent following the schema strictly would unnecessarily refuse to run these commands without a date.
|
|
30
|
+
|
|
31
|
+
- [#162](https://github.com/nansen-ai/nansen-cli/pull/162) [`4dbe181`](https://github.com/nansen-ai/nansen-cli/commit/4dbe181d3b4973881bcb7fb445cf6559819006b6) Thanks [@DMagowan](https://github.com/DMagowan)! - fix: surface wallet prerequisite in `trade quote` help text and schema
|
|
32
|
+
|
|
33
|
+
`nansen trade quote` requires a configured wallet (the trading API builds a transaction specific to the sender address), but this was not communicated until the command failed. Adds a PREREQUISITE section to the usage text and a `prerequisites` field to the schema so agents can discover this requirement before running the command.
|
|
34
|
+
|
|
35
|
+
- [#165](https://github.com/nansen-ai/nansen-cli/pull/165) [`92f37ea`](https://github.com/nansen-ai/nansen-cli/commit/92f37eaa8655ae1a39b9200aafaf4771a0859229) Thanks [@0xlaveen](https://github.com/0xlaveen)! - Fix trading docs and config to reflect actual supported chains (Base and Solana only)
|
|
36
|
+
|
|
3
37
|
## 1.10.0
|
|
4
38
|
|
|
5
39
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/nansen-cli)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
> **Built by agents, for agents.** Command-line interface for the [Nansen API](https://docs.nansen.ai)
|
|
6
|
+
> **Built by agents, for agents.** Command-line interface for the [Nansen API](https://docs.nansen.ai), designed for AI agents.
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -32,7 +32,7 @@ nansen schema [command] [--pretty] # full command reference (no API key neede
|
|
|
32
32
|
|
|
33
33
|
**Research categories:** `smart-money` (`sm`), `token` (`tgm`), `profiler` (`prof`), `portfolio` (`port`), `search`, `perp`, `points`
|
|
34
34
|
|
|
35
|
-
**Trade:** `quote`, `execute` — DEX swaps
|
|
35
|
+
**Trade:** `quote`, `execute` — DEX swaps on Solana and Base.
|
|
36
36
|
|
|
37
37
|
**Wallet:** `create`, `list`, `show`, `export`, `default`, `delete`, `send` — local keypairs (EVM + Solana).
|
|
38
38
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nansen-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Command-line interface for Nansen API - designed for AI agents",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"src/*.js",
|
|
12
|
+
"src/*.json",
|
|
12
13
|
"CHANGELOG.md"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|
|
@@ -60,4 +61,4 @@
|
|
|
60
61
|
"globals": "^17.4.0",
|
|
61
62
|
"vitest": "^4.0.18"
|
|
62
63
|
}
|
|
63
|
-
}
|
|
64
|
+
}
|
package/src/api.js
CHANGED
|
@@ -62,7 +62,7 @@ export class NansenError extends Error {
|
|
|
62
62
|
this.name = 'NansenError';
|
|
63
63
|
this.code = code;
|
|
64
64
|
this.status = status;
|
|
65
|
-
this.
|
|
65
|
+
this.details = data;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
toJSON() {
|
|
@@ -70,7 +70,7 @@ export class NansenError extends Error {
|
|
|
70
70
|
error: this.message,
|
|
71
71
|
code: this.code,
|
|
72
72
|
status: this.status,
|
|
73
|
-
details: this.
|
|
73
|
+
details: this.details,
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -646,11 +646,12 @@ export class NansenAPI {
|
|
|
646
646
|
}
|
|
647
647
|
|
|
648
648
|
async smartMoneyPerpTrades(params = {}) {
|
|
649
|
-
const { filters = {}, orderBy, pagination } = params;
|
|
649
|
+
const { filters = {}, orderBy, pagination, onlyNewPositions } = params;
|
|
650
650
|
return this.request('/api/v1/smart-money/perp-trades', {
|
|
651
651
|
filters,
|
|
652
652
|
order_by: orderBy,
|
|
653
|
-
pagination
|
|
653
|
+
pagination,
|
|
654
|
+
only_new_positions: onlyNewPositions
|
|
654
655
|
});
|
|
655
656
|
}
|
|
656
657
|
|
|
@@ -703,7 +704,7 @@ export class NansenAPI {
|
|
|
703
704
|
}
|
|
704
705
|
|
|
705
706
|
async addressLabels(params = {}) {
|
|
706
|
-
const { address, chain = 'ethereum', pagination = { page: 1,
|
|
707
|
+
const { address, chain = 'ethereum', pagination = { page: 1, per_page: 100 } } = params;
|
|
707
708
|
if (address) {
|
|
708
709
|
const validation = validateAddress(address, chain);
|
|
709
710
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
@@ -732,7 +733,7 @@ export class NansenAPI {
|
|
|
732
733
|
}
|
|
733
734
|
|
|
734
735
|
async addressPnl(params = {}) {
|
|
735
|
-
const { address, chain = 'ethereum', date, days = 30, pagination } = params;
|
|
736
|
+
const { address, chain = 'ethereum', date, days = 30, filters = {}, orderBy, pagination } = params;
|
|
736
737
|
if (address) {
|
|
737
738
|
const validation = validateAddress(address, chain);
|
|
738
739
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
@@ -742,6 +743,8 @@ export class NansenAPI {
|
|
|
742
743
|
address,
|
|
743
744
|
chain,
|
|
744
745
|
date: dateRange,
|
|
746
|
+
filters,
|
|
747
|
+
order_by: orderBy,
|
|
745
748
|
pagination
|
|
746
749
|
});
|
|
747
750
|
}
|
|
@@ -814,7 +817,9 @@ export class NansenAPI {
|
|
|
814
817
|
}
|
|
815
818
|
|
|
816
819
|
async addressPnlSummary(params = {}) {
|
|
817
|
-
|
|
820
|
+
// Note: pnl-summary endpoint is non-paginated (returns aggregate stats, not a list).
|
|
821
|
+
// Pagination param intentionally omitted from this request.
|
|
822
|
+
const { address, chain = 'ethereum', orderBy, days = 30 } = params;
|
|
818
823
|
if (address) {
|
|
819
824
|
const validation = validateAddress(address, chain);
|
|
820
825
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
@@ -823,8 +828,7 @@ export class NansenAPI {
|
|
|
823
828
|
address,
|
|
824
829
|
chain,
|
|
825
830
|
date: buildDateRange(days),
|
|
826
|
-
order_by: orderBy
|
|
827
|
-
pagination
|
|
831
|
+
order_by: orderBy
|
|
828
832
|
});
|
|
829
833
|
}
|
|
830
834
|
|
package/src/cli.js
CHANGED
|
@@ -17,159 +17,22 @@ const { version: VERSION } = require('../package.json');
|
|
|
17
17
|
|
|
18
18
|
// ============= Schema Definition =============
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
sort: { type: 'string', description: 'Sort field:direction (e.g., value_usd:desc)' },
|
|
37
|
-
filters: { type: 'object', description: 'Additional filters as JSON' }
|
|
38
|
-
},
|
|
39
|
-
returns: ['token_address', 'token_symbol', 'token_name', 'chain', 'inflow_usd', 'outflow_usd', 'net_flow_usd']
|
|
40
|
-
},
|
|
41
|
-
'dex-trades': {
|
|
42
|
-
description: 'Real-time DEX trading activity',
|
|
43
|
-
options: { chain: { type: 'string', default: 'solana' }, chains: { type: 'array' }, limit: { type: 'number' }, labels: { type: 'string|array' }, sort: { type: 'string' }, filters: { type: 'object' } },
|
|
44
|
-
returns: ['chain', 'block_timestamp', 'transaction_hash', 'trader_address', 'trader_address_label', 'token_bought_address', 'token_sold_address', 'token_bought_amount', 'token_sold_amount', 'token_bought_symbol', 'token_sold_symbol', 'trade_value_usd']
|
|
45
|
-
},
|
|
46
|
-
'perp-trades': {
|
|
47
|
-
description: 'Perpetual trading on Hyperliquid',
|
|
48
|
-
options: { limit: { type: 'number' }, sort: { type: 'string' }, filters: { type: 'object' } },
|
|
49
|
-
returns: ['trader_address', 'trader_address_label', 'token_symbol', 'side', 'action', 'token_amount', 'price_usd', 'value_usd', 'type', 'block_timestamp', 'transaction_hash']
|
|
50
|
-
},
|
|
51
|
-
'holdings': {
|
|
52
|
-
description: 'Aggregated token balances',
|
|
53
|
-
options: { chain: { type: 'string', default: 'solana' }, chains: { type: 'array' }, limit: { type: 'number' }, labels: { type: 'string|array' } },
|
|
54
|
-
returns: ['chain', 'token_address', 'token_symbol', 'token_sectors', 'value_usd', 'balance_24h_percent_change', 'holders_count', 'share_of_holdings_percent', 'token_age_days', 'market_cap_usd']
|
|
55
|
-
},
|
|
56
|
-
'dcas': {
|
|
57
|
-
description: 'DCA strategies on Jupiter',
|
|
58
|
-
options: { limit: { type: 'number' }, filters: { type: 'object' } },
|
|
59
|
-
returns: ['dca_created_at', 'dca_updated_at', 'trader_address', 'trader_address_label', 'dca_vault_address', 'input_token_address', 'output_token_address', 'deposit_token_amount', 'token_spent_amount', 'output_token_redeemed_amount', 'dca_status', 'input_token_symbol', 'output_token_symbol', 'deposit_value_usd']
|
|
60
|
-
},
|
|
61
|
-
'historical-holdings': {
|
|
62
|
-
description: 'Historical holdings over time',
|
|
63
|
-
options: { chain: { type: 'string', default: 'solana' }, chains: { type: 'array' }, days: { type: 'number', default: 30 }, limit: { type: 'number' } },
|
|
64
|
-
returns: ['date', 'token_address', 'token_symbol', 'balance', 'balance_usd']
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
'profiler': {
|
|
69
|
-
description: 'Wallet profiling - detailed information about any blockchain address',
|
|
70
|
-
subcommands: {
|
|
71
|
-
'balance': { description: 'Current token holdings', options: { address: { type: 'string', required: true, description: 'Wallet address to query' }, chain: { type: 'string', default: 'ethereum' }, entity: { type: 'string', description: 'Entity name instead of address' } }, returns: ['chain', 'address', 'token_address', 'token_symbol', 'token_name', 'token_amount', 'price_usd', 'value_usd'] },
|
|
72
|
-
'labels': { description: 'Behavioral and entity labels', options: { address: { type: 'string', required: true }, chain: { type: 'string', default: 'ethereum' } }, returns: ['label', 'label_type', 'label_subtype'] },
|
|
73
|
-
'transactions': { description: 'Transaction history', options: { address: { type: 'string', required: true }, chain: { type: 'string', default: 'ethereum' }, date: { type: 'string', required: true, description: 'Date or date range' }, limit: { type: 'number' }, days: { type: 'number', default: 30 } }, returns: ['chain', 'method', 'tokens_sent', 'tokens_received', 'volume_usd', 'block_timestamp', 'transaction_hash'] },
|
|
74
|
-
'pnl': { description: 'PnL and trade performance', options: { address: { type: 'string', required: true }, chain: { type: 'string', default: 'ethereum' }, date: { type: 'string', description: 'Date or date range' }, days: { type: 'number', default: 30 }, limit: { type: 'number' } }, returns: ['token_address', 'token_symbol', 'realized_pnl_usd', 'unrealized_pnl_usd', 'total_pnl_usd'] },
|
|
75
|
-
'search': { description: 'Search for entities by name', options: { query: { type: 'string', required: true, description: 'Search query' }, limit: { type: 'number' } }, returns: ['entity_name'] },
|
|
76
|
-
'historical-balances': { description: 'Historical balances over time', options: { address: { type: 'string', required: true }, chain: { type: 'string', default: 'ethereum' }, days: { type: 'number', default: 30 } }, returns: ['date', 'token_address', 'token_symbol', 'balance', 'balance_usd'] },
|
|
77
|
-
'related-wallets': { description: 'Find wallets related to an address', options: { address: { type: 'string', required: true }, chain: { type: 'string', default: 'ethereum' }, limit: { type: 'number' } }, returns: ['address', 'address_label', 'relation', 'transaction_hash', 'block_timestamp', 'order', 'chain'] },
|
|
78
|
-
'counterparties': { description: 'Top counterparties by volume', options: { address: { type: 'string', required: true }, chain: { type: 'string', default: 'ethereum' }, days: { type: 'number', default: 30 } }, returns: ['counterparty_address', 'counterparty_address_label', 'interaction_count', 'total_volume_usd', 'volume_in_usd', 'volume_out_usd', 'tokens_info'] },
|
|
79
|
-
'pnl-summary': { description: 'Summarized PnL metrics', options: { address: { type: 'string', required: true }, chain: { type: 'string', default: 'ethereum' }, days: { type: 'number', default: 30 } }, returns: ['top5_tokens', 'traded_token_count', 'traded_times', 'realized_pnl_usd', 'realized_pnl_percent', 'win_rate'] },
|
|
80
|
-
'perp-positions': { description: 'Current perpetual positions', options: { address: { type: 'string', required: true }, limit: { type: 'number' } }, returns: ['symbol', 'side', 'size', 'entry_price', 'mark_price', 'unrealized_pnl', 'leverage'] },
|
|
81
|
-
'perp-trades': { description: 'Perpetual trading history', options: { address: { type: 'string', required: true }, days: { type: 'number', default: 30 }, limit: { type: 'number' } }, returns: ['symbol', 'side', 'size', 'price', 'value_usd', 'pnl_usd', 'timestamp'] },
|
|
82
|
-
'batch': { description: 'Batch profile multiple addresses', options: { addresses: { type: 'string', description: 'Comma-separated addresses' }, file: { type: 'string', description: 'File with one address per line' }, chain: { type: 'string', default: 'ethereum' }, include: { type: 'string', default: 'labels,balance', description: 'Comma-separated: labels,balance,pnl' }, delay: { type: 'number', default: 1000, description: 'Delay between requests in ms' } }, returns: ['address', 'chain', 'labels', 'balance', 'pnl', 'error'] },
|
|
83
|
-
'trace': { description: 'Multi-hop counterparty trace (BFS)', options: { address: { type: 'string', required: true }, chain: { type: 'string', default: 'ethereum' }, depth: { type: 'number', default: 2, description: 'Max hops (1-5)' }, width: { type: 'number', default: 10, description: 'Top N counterparties per hop' }, days: { type: 'number', default: 30 }, delay: { type: 'number', default: 1000, description: 'Delay between requests in ms' } }, returns: ['root', 'chain', 'depth', 'nodes', 'edges', 'stats'] },
|
|
84
|
-
'compare': { description: 'Compare two wallets (shared counterparties, tokens)', options: { addresses: { type: 'string', required: true, description: 'Two comma-separated addresses' }, chain: { type: 'string', default: 'ethereum' }, days: { type: 'number', default: 30 } }, returns: ['addresses', 'chain', 'shared_counterparties', 'shared_tokens', 'balances'] }
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
'token': {
|
|
88
|
-
description: 'Token God Mode - deep analytics for any token',
|
|
89
|
-
subcommands: {
|
|
90
|
-
'indicators': { description: 'Risk and reward indicators for a token (Nansen Score)', options: { token: { type: 'string', required: true, description: 'Token address' }, chain: { type: 'string', default: 'ethereum' } }, returns: ['token_info[market_cap_usd, market_cap_group, is_stablecoin]', 'risk_indicators[indicator_type, score, signal, signal_percentile, last_trigger_on]', 'reward_indicators[indicator_type, score, signal, signal_percentile, last_trigger_on]'] },
|
|
91
|
-
'ohlcv': { description: 'OHLCV candle data for a token', options: { token: { type: 'string', required: true, description: 'Token address' }, chain: { type: 'string', default: 'solana' }, timeframe: { type: 'string', default: '1h', enum: ['1m', '5m', '15m', '30m', '1h', '2h', '4h', '1d', '1w', '1M'], description: 'Candle timeframe (e.g., 1h, 4h, 1d)' } }, returns: ['timestamp', 'open', 'high', 'low', 'close', 'volume'] },
|
|
92
|
-
'info': { description: 'Get detailed information for a specific token', options: { token: { type: 'string', required: true, description: 'Token address' }, chain: { type: 'string', default: 'solana' }, timeframe: { type: 'string', default: '1d', enum: ['5m', '1h', '6h', '12h', '1d', '7d'] } }, returns: ['token_address', 'token_symbol', 'token_name', 'chain', 'price_usd', 'volume_usd', 'market_cap', 'holder_count', 'liquidity_usd'] },
|
|
93
|
-
'screener': { description: 'Discover and filter tokens', options: { chain: { type: 'string', default: 'solana' }, chains: { type: 'array' }, timeframe: { type: 'string', default: '24h', enum: ['5m', '10m', '1h', '6h', '24h', '7d', '30d'] }, 'smart-money': { type: 'boolean', description: 'Filter for Smart Money only' }, search: { type: 'string', description: 'Filter results by token symbol or name (client-side)' }, limit: { type: 'number' }, sort: { type: 'string' } }, returns: ['token_address', 'token_symbol', 'token_name', 'chain', 'price_usd', 'volume_usd', 'market_cap', 'holder_count', 'smart_money_holders'] },
|
|
94
|
-
'holders': { description: 'Token holder analysis', options: { token: { type: 'string', required: true }, chain: { type: 'string', default: 'solana' }, 'smart-money': { type: 'boolean' }, limit: { type: 'number' } }, returns: ['address', 'address_label', 'token_amount', 'total_outflow', 'total_inflow', 'balance_change_24h', 'balance_change_7d', 'balance_change_30d', 'ownership_percentage', 'value_usd'] },
|
|
95
|
-
'flows': { description: 'Token flow metrics', options: { token: { type: 'string', required: true }, chain: { type: 'string', default: 'solana' }, date: { type: 'string', required: true, description: 'Date or date range' }, days: { type: 'number', default: 30 }, limit: { type: 'number' } }, returns: ['date', 'price_usd', 'token_amount', 'value_usd', 'holders_count', 'total_inflows_count', 'total_outflows_count'] },
|
|
96
|
-
'dex-trades': { description: 'DEX trading activity', options: { token: { type: 'string', required: true }, chain: { type: 'string', default: 'solana' }, 'smart-money': { type: 'boolean' }, days: { type: 'number', default: 30 }, limit: { type: 'number' } }, returns: ['tx_hash', 'wallet_address', 'side', 'amount', 'price_usd', 'value_usd', 'timestamp'] },
|
|
97
|
-
'pnl': { description: 'PnL leaderboard', options: { token: { type: 'string', required: true }, chain: { type: 'string', default: 'solana' }, days: { type: 'number', default: 30 }, limit: { type: 'number' }, sort: { type: 'string' } }, returns: ['wallet_address', 'realized_pnl_usd', 'unrealized_pnl_usd', 'total_pnl_usd', 'labels'] },
|
|
98
|
-
'who-bought-sold': { description: 'Recent buyers and sellers', options: { token: { type: 'string', required: true }, chain: { type: 'string', default: 'solana' }, date: { type: 'string', required: true, description: 'Date or date range' }, days: { type: 'number', default: 30 }, limit: { type: 'number' } }, returns: ['address', 'address_label', 'bought_token_volume', 'sold_token_volume', 'token_trade_volume', 'bought_volume_usd', 'sold_volume_usd', 'trade_volume_usd'] },
|
|
99
|
-
'flow-intelligence': { description: 'Detailed flow intelligence by label', options: { token: { type: 'string', required: true }, chain: { type: 'string', default: 'solana' }, days: { type: 'number', default: 30 } }, returns: ['public_figure_net_flow_usd', 'public_figure_wallet_count', 'top_pnl_net_flow_usd', 'top_pnl_wallet_count', 'whale_net_flow_usd', 'whale_wallet_count', 'smart_trader_net_flow_usd', 'smart_trader_wallet_count', 'exchange_net_flow_usd', 'exchange_wallet_count', 'fresh_wallets_net_flow_usd', 'fresh_wallets_wallet_count'] },
|
|
100
|
-
'transfers': { description: 'Token transfer history', options: { token: { type: 'string', required: true }, chain: { type: 'string', default: 'solana' }, days: { type: 'number', default: 30 }, limit: { type: 'number' }, from: { type: 'string', description: 'Filter by sender address' }, to: { type: 'string', description: 'Filter by recipient address' }, enrich: { type: 'boolean', description: 'Enrich addresses with Nansen labels' } }, returns: ['tx_hash', 'from', 'to', 'amount', 'value_usd', 'timestamp'] },
|
|
101
|
-
'jup-dca': { description: 'Jupiter DCA orders for token', options: { token: { type: 'string', required: true }, limit: { type: 'number' } }, returns: ['wallet_address', 'input_token', 'output_token', 'total_input', 'executed', 'remaining'] },
|
|
102
|
-
'perp-trades': { description: 'Perp trades by token symbol', options: { symbol: { type: 'string', required: true, description: 'Token symbol (e.g., BTC, ETH)' }, days: { type: 'number', default: 30 }, limit: { type: 'number' } }, returns: ['wallet_address', 'side', 'size', 'price', 'value_usd', 'pnl_usd', 'timestamp'] },
|
|
103
|
-
'perp-positions': { description: 'Open perp positions by token symbol', options: { symbol: { type: 'string', required: true }, limit: { type: 'number' } }, returns: ['wallet_address', 'side', 'size', 'entry_price', 'mark_price', 'unrealized_pnl', 'leverage'] },
|
|
104
|
-
'perp-pnl-leaderboard': { description: 'Perp PnL leaderboard by token', options: { symbol: { type: 'string', required: true }, days: { type: 'number', default: 30 }, limit: { type: 'number' } }, returns: ['wallet_address', 'realized_pnl', 'unrealized_pnl', 'total_pnl', 'trade_count'] }
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
'search': {
|
|
108
|
-
description: 'Search for tokens and entities across Nansen',
|
|
109
|
-
options: {
|
|
110
|
-
query: { type: 'string', required: true, description: 'Search query (token name, symbol, address, or entity)' },
|
|
111
|
-
type: { type: 'string', default: 'any', enum: ['token', 'entity', 'any'], description: 'Result type filter' },
|
|
112
|
-
chain: { type: 'string', description: 'Filter by chain (e.g., ethereum, solana)' },
|
|
113
|
-
limit: { type: 'number', default: 25, description: 'Max results (1-50)' }
|
|
114
|
-
},
|
|
115
|
-
returns: ['tokens[name, symbol, chain, address, price, volume_24h, market_cap, rank]', 'entities[name, tags, rank]', 'total_results']
|
|
116
|
-
},
|
|
117
|
-
'perp': {
|
|
118
|
-
description: 'Perpetual futures analytics',
|
|
119
|
-
subcommands: {
|
|
120
|
-
'screener': { description: 'Screen perpetual futures contracts', options: { days: { type: 'number', default: 30 }, limit: { type: 'number' }, sort: { type: 'string' }, filters: { type: 'object' } }, returns: ['token_symbol', 'volume_usd', 'open_interest', 'funding_rate', 'price_change_24h'] },
|
|
121
|
-
'leaderboard': { description: 'Perpetual futures PnL leaderboard', options: { days: { type: 'number', default: 30 }, limit: { type: 'number' }, sort: { type: 'string' }, filters: { type: 'object' } }, returns: ['address', 'address_label', 'realized_pnl', 'unrealized_pnl', 'total_pnl', 'trade_count', 'win_rate'] }
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
'portfolio': {
|
|
125
|
-
description: 'Portfolio analytics',
|
|
126
|
-
subcommands: {
|
|
127
|
-
'defi': { description: 'DeFi holdings across protocols', options: { wallet: { type: 'string', required: true, description: 'Wallet address' } }, returns: ['protocol', 'chain', 'position_type', 'token_symbol', 'balance', 'balance_usd'] }
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
'points': {
|
|
131
|
-
description: 'Nansen Points analytics',
|
|
132
|
-
subcommands: {
|
|
133
|
-
'leaderboard': { description: 'Points leaderboard', options: { tier: { type: 'string', description: 'Filter by tier' }, limit: { type: 'number' } }, returns: ['rank', 'address', 'address_label', 'points', 'tier'] }
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
'trade': {
|
|
139
|
-
description: 'DEX trading commands',
|
|
140
|
-
subcommands: {
|
|
141
|
-
'quote': {
|
|
142
|
-
description: 'Get a DEX swap quote (chain, tokens, amount)',
|
|
143
|
-
options: {
|
|
144
|
-
chain: { type: 'string', default: 'ethereum', description: 'Blockchain' },
|
|
145
|
-
from: { type: 'string', required: true, description: 'Token to sell (address or symbol)' },
|
|
146
|
-
to: { type: 'string', required: true, description: 'Token to buy (address or symbol)' },
|
|
147
|
-
amount: { type: 'string', required: true, description: 'Amount to swap' },
|
|
148
|
-
wallet: { type: 'string', description: 'Wallet name, or "walletconnect"/"wc" for WalletConnect (EVM only)' }
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
'execute': {
|
|
152
|
-
description: 'Sign and broadcast a quoted trade',
|
|
153
|
-
options: {
|
|
154
|
-
chain: { type: 'string', default: 'ethereum', description: 'Blockchain' },
|
|
155
|
-
wallet: { type: 'string', description: 'Wallet name, or "walletconnect"/"wc" for WalletConnect (EVM only)' }
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
globalOptions: {
|
|
162
|
-
pretty: { type: 'boolean', description: 'Format JSON output for readability' },
|
|
163
|
-
table: { type: 'boolean', description: 'Format output as human-readable table' },
|
|
164
|
-
fields: { type: 'string', description: 'Comma-separated list of fields to include in output' },
|
|
165
|
-
'no-retry': { type: 'boolean', description: 'Disable automatic retry on rate limits/errors' },
|
|
166
|
-
retries: { type: 'number', default: 3, description: 'Max retry attempts' },
|
|
167
|
-
format: { type: 'string', enum: ['json', 'csv'], description: 'Output format (default: json)' },
|
|
168
|
-
'x402-payment-signature': { type: 'string', description: 'Pre-signed x402 payment signature header' }
|
|
169
|
-
},
|
|
170
|
-
chains: ['ethereum', 'solana', 'base', 'bnb', 'arbitrum', 'polygon', 'optimism', 'avalanche', 'linea', 'scroll', 'mantle', 'ronin', 'sei', 'plasma', 'sonic', 'monad', 'hyperevm', 'iotaevm'],
|
|
171
|
-
smartMoneyLabels: ['Fund', 'Smart Trader', '30D Smart Trader', '90D Smart Trader', '180D Smart Trader', 'Smart HL Perps Trader']
|
|
172
|
-
};
|
|
20
|
+
const schemaDefinition = require('./schema.json');
|
|
21
|
+
|
|
22
|
+
// SCHEMA is the static definition with version injected at runtime.
|
|
23
|
+
// The schema.json file is the source of truth for command metadata (returns, options, etc.)
|
|
24
|
+
// and should be updated whenever the API changes — do not edit returns arrays here.
|
|
25
|
+
export const SCHEMA = { version: VERSION, ...schemaDefinition };
|
|
26
|
+
|
|
27
|
+
// ============= Pagination =============
|
|
28
|
+
|
|
29
|
+
export function buildPagination(options) {
|
|
30
|
+
if (!options.limit && !options.page) return undefined;
|
|
31
|
+
return {
|
|
32
|
+
page: Math.max(1, parseInt(options.page, 10) || 1),
|
|
33
|
+
per_page: options.limit,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
173
36
|
|
|
174
37
|
// ============= Field Filtering =============
|
|
175
38
|
|
|
@@ -460,13 +323,17 @@ export function formatOutput(data, { pretty = false, table = false, csv = false
|
|
|
460
323
|
|
|
461
324
|
// Format error data (returns object, does not exit)
|
|
462
325
|
export function formatError(error) {
|
|
463
|
-
|
|
326
|
+
const details = error.details ?? error.data ?? null;
|
|
327
|
+
const result = {
|
|
464
328
|
success: false,
|
|
465
329
|
error: error.message,
|
|
466
330
|
code: error.code || 'UNKNOWN',
|
|
467
331
|
status: error.status || null,
|
|
468
|
-
details: error.data || null
|
|
469
332
|
};
|
|
333
|
+
if (details != null && !(typeof details === 'object' && !Array.isArray(details) && Object.keys(details).length === 0)) {
|
|
334
|
+
result.details = details;
|
|
335
|
+
}
|
|
336
|
+
return result;
|
|
470
337
|
}
|
|
471
338
|
|
|
472
339
|
/**
|
|
@@ -753,7 +620,7 @@ export async function compareWallets(api, params = {}) {
|
|
|
753
620
|
|
|
754
621
|
export const BANNER = '';
|
|
755
622
|
|
|
756
|
-
export const HELP = `Nansen CLI v${VERSION} —
|
|
623
|
+
export const HELP = `Nansen CLI v${VERSION} — designed for AI agents.
|
|
757
624
|
|
|
758
625
|
USAGE: nansen <command> [subcommand] [options]
|
|
759
626
|
|
|
@@ -1002,7 +869,7 @@ export function buildCommands(deps = {}) {
|
|
|
1002
869
|
const chains = options.chains || [chain];
|
|
1003
870
|
const filters = options.filters || {};
|
|
1004
871
|
const orderBy = parseSort(options.sort, options['order-by']);
|
|
1005
|
-
const pagination = options
|
|
872
|
+
const pagination = buildPagination(options);
|
|
1006
873
|
|
|
1007
874
|
// Add smart money label filter if specified
|
|
1008
875
|
if (options.labels) {
|
|
@@ -1016,7 +883,7 @@ export function buildCommands(deps = {}) {
|
|
|
1016
883
|
const handlers = {
|
|
1017
884
|
'netflow': () => apiInstance.smartMoneyNetflow({ chains, filters, orderBy, pagination }),
|
|
1018
885
|
'dex-trades': () => apiInstance.smartMoneyDexTrades({ chains, filters, orderBy, pagination }),
|
|
1019
|
-
'perp-trades': () => apiInstance.smartMoneyPerpTrades({ filters, orderBy, pagination }),
|
|
886
|
+
'perp-trades': () => apiInstance.smartMoneyPerpTrades({ filters, orderBy, pagination, onlyNewPositions: options['only-new-positions'] ?? flags['only-new-positions'] }),
|
|
1020
887
|
'holdings': () => apiInstance.smartMoneyHoldings({ chains, filters, orderBy, pagination }),
|
|
1021
888
|
'dcas': () => apiInstance.smartMoneyDcas({ filters, orderBy, pagination }),
|
|
1022
889
|
'historical-holdings': () => apiInstance.smartMoneyHistoricalHoldings({ chains, filters, orderBy, pagination, days }),
|
|
@@ -1053,7 +920,7 @@ export function buildCommands(deps = {}) {
|
|
|
1053
920
|
}
|
|
1054
921
|
const filters = options.filters || {};
|
|
1055
922
|
const orderBy = parseSort(options.sort, options['order-by']);
|
|
1056
|
-
const pagination = options
|
|
923
|
+
const pagination = buildPagination(options);
|
|
1057
924
|
const days = options.days ? parseInt(options.days) : 30;
|
|
1058
925
|
|
|
1059
926
|
const handlers = {
|
|
@@ -1065,7 +932,7 @@ export function buildCommands(deps = {}) {
|
|
|
1065
932
|
},
|
|
1066
933
|
'pnl': () => {
|
|
1067
934
|
const date = parseDateOption(options.date, days);
|
|
1068
|
-
return apiInstance.addressPnl({ address, chain, date, days, pagination });
|
|
935
|
+
return apiInstance.addressPnl({ address, chain, date, days, filters, orderBy, pagination });
|
|
1069
936
|
},
|
|
1070
937
|
'search': () => apiInstance.entitySearch({ query: options.query }),
|
|
1071
938
|
'historical-balances': () => apiInstance.addressHistoricalBalances({ address, chain, filters, orderBy, pagination, days }),
|
|
@@ -1139,7 +1006,7 @@ export function buildCommands(deps = {}) {
|
|
|
1139
1006
|
const timeframe = options.timeframe || '24h';
|
|
1140
1007
|
const filters = options.filters || {};
|
|
1141
1008
|
const orderBy = parseSort(options.sort, options['order-by']);
|
|
1142
|
-
const pagination = options
|
|
1009
|
+
const pagination = buildPagination(options);
|
|
1143
1010
|
const days = options.days ? parseInt(options.days) : 30;
|
|
1144
1011
|
|
|
1145
1012
|
// Convenience filter for smart money only
|
|
@@ -1245,7 +1112,7 @@ export function buildCommands(deps = {}) {
|
|
|
1245
1112
|
const subcommand = args[0] || 'help';
|
|
1246
1113
|
const filters = options.filters || {};
|
|
1247
1114
|
const orderBy = parseSort(options.sort, options['order-by']);
|
|
1248
|
-
const pagination = options
|
|
1115
|
+
const pagination = buildPagination(options);
|
|
1249
1116
|
const days = options.days ? parseInt(options.days) : 30;
|
|
1250
1117
|
|
|
1251
1118
|
const handlers = {
|
|
@@ -1277,7 +1144,7 @@ export function buildCommands(deps = {}) {
|
|
|
1277
1144
|
'points': async (args, apiInstance, flags, options) => {
|
|
1278
1145
|
const subcommand = args[0] || 'help';
|
|
1279
1146
|
const tier = options.tier;
|
|
1280
|
-
const pagination = options
|
|
1147
|
+
const pagination = buildPagination(options);
|
|
1281
1148
|
|
|
1282
1149
|
const handlers = {
|
|
1283
1150
|
'leaderboard': () => apiInstance.pointsLeaderboard({ tier, pagination }),
|
|
@@ -1342,7 +1209,7 @@ WALLET:
|
|
|
1342
1209
|
Defaults to the default local wallet if omitted.
|
|
1343
1210
|
|
|
1344
1211
|
SYMBOLS:
|
|
1345
|
-
Common tokens resolve automatically: SOL, ETH,
|
|
1212
|
+
Common tokens resolve automatically: SOL, ETH, USDC, USDT, WETH
|
|
1346
1213
|
Raw addresses are also accepted.`);
|
|
1347
1214
|
return;
|
|
1348
1215
|
}
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Nansen CLI - Command-line interface for Nansen API
|
|
4
|
-
* Designed for AI agents
|
|
5
|
-
*
|
|
4
|
+
* Designed for AI agents.
|
|
5
|
+
*
|
|
6
6
|
* Usage: nansen <command> [options]
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* Research commands return JSON; operational commands print human-readable text.
|
|
9
9
|
* Use --pretty for human-readable formatting.
|
|
10
10
|
*
|
|
11
11
|
* Core logic lives in cli.js for testability.
|