nansen-cli 1.17.0 → 1.19.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 +41 -0
- package/package.json +5 -3
- package/skills/nansen-dca-tracker/SKILL.md +38 -0
- package/skills/nansen-defi-positions/SKILL.md +37 -0
- package/skills/nansen-exit-signals/SKILL.md +39 -0
- package/skills/nansen-fund-tracker/SKILL.md +35 -0
- package/skills/nansen-general-search/SKILL.md +34 -0
- package/skills/nansen-holder-analysis/SKILL.md +38 -0
- package/skills/nansen-perp-screener/SKILL.md +32 -0
- package/skills/nansen-perp-trader-profile/SKILL.md +39 -0
- package/skills/nansen-polymarket-deep-dive/SKILL.md +50 -0
- package/skills/nansen-polymarket-insider-scan/SKILL.md +62 -0
- package/skills/nansen-polymarket-trader-profile/SKILL.md +43 -0
- package/skills/nansen-portfolio-tracker/SKILL.md +36 -0
- package/skills/nansen-prediction-markets/SKILL.md +47 -0
- package/skills/nansen-sm-cross-chain-flows/SKILL.md +27 -0
- package/skills/nansen-smart-alerts/SKILL.md +137 -0
- package/skills/nansen-smart-money-alpha/SKILL.md +43 -0
- package/skills/nansen-smart-money-tracker/SKILL.md +71 -0
- package/skills/nansen-smart-money-trend/SKILL.md +30 -0
- package/skills/nansen-token-research/SKILL.md +90 -0
- package/skills/nansen-token-screener/SKILL.md +54 -0
- package/skills/nansen-token-transfer-analysis/SKILL.md +40 -0
- package/skills/nansen-trading/SKILL.md +100 -0
- package/skills/nansen-wallet-batch/SKILL.md +26 -0
- package/skills/nansen-wallet-clustering/REFERENCE.md +43 -0
- package/skills/nansen-wallet-clustering/SKILL.md +46 -0
- package/skills/nansen-wallet-deep-dive/SKILL.md +45 -0
- package/skills/nansen-wallet-keychain-migration/SKILL.md +183 -0
- package/skills/nansen-wallet-manager/SKILL.md +140 -0
- package/skills/nansen-wallet-profiler/SKILL.md +98 -0
- package/skills/nansen-web-fetcher/SKILL.md +50 -0
- package/skills/nansen-web-searcher/SKILL.md +39 -0
- package/src/api.js +76 -3
- package/src/cli.js +176 -14
- package/src/commands/alerts.js +717 -0
- package/src/schema.json +164 -1
- package/src/telemetry.js +237 -0
- package/src/update-check.js +2 -2
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nansen-wallet-deep-dive
|
|
3
|
+
description: "Who is this wallet and what have they been doing? Identity labels, balance, PnL summary, recent transactions, perp positions, and counterparties."
|
|
4
|
+
metadata:
|
|
5
|
+
openclaw:
|
|
6
|
+
requires:
|
|
7
|
+
env:
|
|
8
|
+
- NANSEN_API_KEY
|
|
9
|
+
bins:
|
|
10
|
+
- nansen
|
|
11
|
+
primaryEnv: NANSEN_API_KEY
|
|
12
|
+
install:
|
|
13
|
+
- kind: node
|
|
14
|
+
package: nansen-cli
|
|
15
|
+
bins: [nansen]
|
|
16
|
+
allowed-tools: Bash(nansen:*)
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Wallet Analysis
|
|
20
|
+
|
|
21
|
+
**Answers:** "Who is this wallet and what have they been doing?"
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ADDR=<address> CHAIN=ethereum
|
|
25
|
+
|
|
26
|
+
nansen research profiler labels --address $ADDR --chain $CHAIN
|
|
27
|
+
# → label, category (e.g. "Smart Trader", "Fund", "Public Figure", ENS names)
|
|
28
|
+
|
|
29
|
+
nansen research profiler balance --address $ADDR --chain $CHAIN
|
|
30
|
+
# → token_symbol, token_name, token_amount, price_usd, value_usd per holding
|
|
31
|
+
|
|
32
|
+
nansen research profiler pnl-summary --address $ADDR --chain $CHAIN --days 30
|
|
33
|
+
# → realized_pnl_usd, realized_pnl_percent, win_rate, traded_token_count, traded_times, top5_tokens
|
|
34
|
+
|
|
35
|
+
nansen research profiler transactions --address $ADDR --chain $CHAIN --limit 20
|
|
36
|
+
# → block_timestamp, method, tokens_sent, tokens_received, volume_usd, source_type
|
|
37
|
+
|
|
38
|
+
nansen research profiler perp-positions --address $ADDR
|
|
39
|
+
# → asset_positions, margin_summary_account_value_usd, margin_summary_total_margin_used_usd
|
|
40
|
+
|
|
41
|
+
nansen research profiler counterparties --address $ADDR --chain $CHAIN --days 30
|
|
42
|
+
# → counterparty_address, counterparty_address_label, interaction_count, total_volume_usd, volume_in/out_usd
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
perp-positions returns Hyperliquid data — returns empty if the wallet has no open perps.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nansen-wallet-keychain-migration
|
|
3
|
+
description: Migrate an existing nansen-cli wallet from insecure password storage (env files, .credentials) to the new secure keychain-backed flow.
|
|
4
|
+
metadata:
|
|
5
|
+
openclaw:
|
|
6
|
+
requires:
|
|
7
|
+
env:
|
|
8
|
+
- NANSEN_API_KEY
|
|
9
|
+
bins:
|
|
10
|
+
- nansen
|
|
11
|
+
primaryEnv: NANSEN_API_KEY
|
|
12
|
+
install:
|
|
13
|
+
- kind: node
|
|
14
|
+
package: nansen-cli
|
|
15
|
+
bins: [nansen]
|
|
16
|
+
allowed-tools: Bash(nansen:*)
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Wallet Migration — Old Flow to Secure Keychain
|
|
20
|
+
|
|
21
|
+
Use this skill when a user already has a nansen-cli wallet set up with the
|
|
22
|
+
**old** password storage method and wants to migrate to the new secure flow.
|
|
23
|
+
|
|
24
|
+
## When to use
|
|
25
|
+
|
|
26
|
+
- User mentions they stored their password in `~/.nansen/.env`, a `.env` file, or `memory.md`
|
|
27
|
+
- User gets the stderr warning: `⚠ Password loaded from insecure .credentials file`
|
|
28
|
+
- User asks to "secure my wallet" or "migrate to keychain"
|
|
29
|
+
- User created a wallet before the keychain update was released
|
|
30
|
+
|
|
31
|
+
## Detect current state
|
|
32
|
+
|
|
33
|
+
`wallet show` only displays addresses and does NOT load or check the password.
|
|
34
|
+
To detect the actual password situation, check for stored password sources:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# 1. Check if a wallet exists at all
|
|
38
|
+
nansen wallet list 2>&1
|
|
39
|
+
|
|
40
|
+
# 2. Check for insecure password stores
|
|
41
|
+
ls -la ~/.nansen/.env 2>/dev/null && echo "FOUND: ~/.nansen/.env (insecure)"
|
|
42
|
+
ls -la ~/.nansen/wallets/.credentials 2>/dev/null && echo "FOUND: .credentials file (insecure)"
|
|
43
|
+
|
|
44
|
+
# 3. Try an operation that requires the password (without setting env var)
|
|
45
|
+
nansen wallet export default 2>&1
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Interpret the `export` output:
|
|
49
|
+
- `⚠ Password loaded from ~/.nansen/wallets/.credentials` on stderr → needs migration (Path B)
|
|
50
|
+
- Export succeeds silently → password is in keychain, no migration needed
|
|
51
|
+
- `PASSWORD_REQUIRED` JSON error → password not persisted anywhere (Path C or D)
|
|
52
|
+
|
|
53
|
+
## Migration paths
|
|
54
|
+
|
|
55
|
+
### Path A: Password in `~/.nansen/.env` (old skill pattern)
|
|
56
|
+
|
|
57
|
+
The previous wallet skill told agents to write the password to `~/.nansen/.env`.
|
|
58
|
+
|
|
59
|
+
**Step 1 — Ask the human for their password:**
|
|
60
|
+
|
|
61
|
+
> "Your wallet password is currently stored in ~/.nansen/.env, which is insecure.
|
|
62
|
+
> I can migrate it to your OS keychain. Please confirm the password you used when
|
|
63
|
+
> creating the wallet, or I can read it from ~/.nansen/.env if you authorize it."
|
|
64
|
+
|
|
65
|
+
**Step 2 — Migrate:**
|
|
66
|
+
|
|
67
|
+
The `source` and `nansen wallet secure` MUST run in the same shell so the env
|
|
68
|
+
var is available to the node process:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
source ~/.nansen/.env 2>/dev/null && nansen wallet secure
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Step 3 — Verify the password actually decrypts the wallet:**
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Unset env var to prove keychain works, then export to verify decryption
|
|
78
|
+
unset NANSEN_WALLET_PASSWORD
|
|
79
|
+
nansen wallet export default 2>&1
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
If export succeeds (shows private keys), the migration worked. If it shows
|
|
83
|
+
`Incorrect password`, the wrong password was migrated — run `nansen wallet
|
|
84
|
+
forget-password` and retry with the correct password.
|
|
85
|
+
|
|
86
|
+
**Step 4 — Clean up the insecure file:**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
rm -f ~/.nansen/.env
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Path B: Password in `.credentials` file (auto-saved fallback)
|
|
93
|
+
|
|
94
|
+
This happens when `wallet create` couldn't access the OS keychain (containers, CI).
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
nansen wallet secure
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If the keychain is still unavailable (e.g. containerized Linux without D-Bus),
|
|
101
|
+
`nansen wallet secure` will explain the situation and suggest alternatives.
|
|
102
|
+
|
|
103
|
+
After migrating, verify decryption works:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
nansen wallet export default 2>&1
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Path C: Password only in `NANSEN_WALLET_PASSWORD` env var
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Persist the env var password to keychain
|
|
113
|
+
nansen wallet secure
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Then verify without the env var:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
unset NANSEN_WALLET_PASSWORD
|
|
120
|
+
nansen wallet export default 2>&1
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Path D: Password lost entirely
|
|
124
|
+
|
|
125
|
+
The password cannot be recovered. The wallet's private keys are encrypted with
|
|
126
|
+
AES-256-GCM and the password is not stored anywhere recoverable.
|
|
127
|
+
|
|
128
|
+
**Tell the human:**
|
|
129
|
+
|
|
130
|
+
> "Your wallet password cannot be recovered. If you have funds in this wallet,
|
|
131
|
+
> they may be inaccessible. You can create a new wallet and transfer any remaining
|
|
132
|
+
> accessible funds."
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Create a fresh wallet (human must provide a new password)
|
|
136
|
+
NANSEN_WALLET_PASSWORD="<new_password_from_user>" nansen wallet create --name new-wallet
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Post-migration verification
|
|
140
|
+
|
|
141
|
+
After any migration, confirm the password was migrated correctly by proving
|
|
142
|
+
the keychain password can actually decrypt the wallet:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Unset env var to prove keychain works
|
|
146
|
+
unset NANSEN_WALLET_PASSWORD
|
|
147
|
+
|
|
148
|
+
# This MUST succeed — it proves the keychain password decrypts the wallet
|
|
149
|
+
nansen wallet export default 2>&1
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
If export shows `Incorrect password`, the wrong password was saved to the
|
|
153
|
+
keychain. Fix with:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
nansen wallet forget-password
|
|
157
|
+
NANSEN_WALLET_PASSWORD="<correct_password>" nansen wallet secure
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If `stderr` still shows the `.credentials` warning, the keychain migration did
|
|
161
|
+
not succeed — check if the OS keychain service is running (`secret-tool` on Linux,
|
|
162
|
+
`security` on macOS).
|
|
163
|
+
|
|
164
|
+
## Forget password (all stores)
|
|
165
|
+
|
|
166
|
+
If the user wants to remove their persisted password entirely:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
nansen wallet forget-password
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
This clears the password from both OS keychain and `.credentials` file. Future
|
|
173
|
+
wallet operations will require `NANSEN_WALLET_PASSWORD` env var or re-running
|
|
174
|
+
`nansen wallet secure`.
|
|
175
|
+
|
|
176
|
+
## Critical rules for agents
|
|
177
|
+
|
|
178
|
+
- **NEVER generate a password** — always ask the human
|
|
179
|
+
- **NEVER store the password** in files, memory, logs, or conversation history
|
|
180
|
+
- **NEVER use `--human` flag** — interactive prompts break agents
|
|
181
|
+
- If the human authorizes reading `~/.nansen/.env`, read it in the same command
|
|
182
|
+
(`source ~/.nansen/.env && nansen wallet secure`) — do not echo or log the value
|
|
183
|
+
- **ALWAYS verify after migration** with `nansen wallet export default` — `wallet show` does NOT prove the password works (it never loads the password)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nansen-wallet-manager
|
|
3
|
+
description: Wallet management — create, list, show, export, send, delete. Use when creating wallets, checking balances, or sending tokens.
|
|
4
|
+
metadata:
|
|
5
|
+
openclaw:
|
|
6
|
+
requires:
|
|
7
|
+
env:
|
|
8
|
+
- NANSEN_API_KEY
|
|
9
|
+
bins:
|
|
10
|
+
- nansen
|
|
11
|
+
primaryEnv: NANSEN_API_KEY
|
|
12
|
+
install:
|
|
13
|
+
- kind: node
|
|
14
|
+
package: nansen-cli
|
|
15
|
+
bins: [nansen]
|
|
16
|
+
allowed-tools: Bash(nansen:*)
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Wallet
|
|
20
|
+
|
|
21
|
+
## Auth Setup
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Save API key (non-interactive)
|
|
25
|
+
nansen login --api-key <key>
|
|
26
|
+
# Or via env var:
|
|
27
|
+
NANSEN_API_KEY=<key> nansen login
|
|
28
|
+
|
|
29
|
+
# Verify
|
|
30
|
+
nansen research profiler labels --address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --chain ethereum
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Wallet Creation (Two-Step Agent Flow)
|
|
34
|
+
|
|
35
|
+
Wallet creation requires a password from the **human user**. The agent must NOT generate or store the password itself.
|
|
36
|
+
|
|
37
|
+
> **Step 1 (Agent → Human):** Ask the user to provide a wallet password (minimum 12 characters).
|
|
38
|
+
>
|
|
39
|
+
> **Step 2 (Agent executes):** Run the create command with the password the user gave you.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
NANSEN_WALLET_PASSWORD="<password_from_user>" nansen wallet create
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
After creation, the CLI automatically saves the password:
|
|
46
|
+
- **OS keychain** (macOS Keychain, Linux secret-tool, Windows Credential Manager) — secure, preferred
|
|
47
|
+
- **~/.nansen/wallets/.credentials file** — insecure fallback when no keychain is available (e.g. containers, CI)
|
|
48
|
+
|
|
49
|
+
**All future wallet operations retrieve the password automatically** — no env var or human input needed.
|
|
50
|
+
|
|
51
|
+
If the `.credentials` file fallback is used, the CLI prints a warning on every operation. To migrate to secure storage later, run `nansen wallet secure`.
|
|
52
|
+
|
|
53
|
+
### Password resolution order (automatic)
|
|
54
|
+
|
|
55
|
+
1. `NANSEN_WALLET_PASSWORD` env var (if set)
|
|
56
|
+
2. OS keychain (saved automatically on wallet create)
|
|
57
|
+
3. `~/.nansen/wallets/.credentials` file (insecure fallback, with warning)
|
|
58
|
+
4. Structured JSON error with instructions (if none available)
|
|
59
|
+
|
|
60
|
+
### Critical rules for agents
|
|
61
|
+
|
|
62
|
+
- **NEVER generate a password yourself** — always ask the human user
|
|
63
|
+
- **NEVER store the password** in files, memory, logs, or conversation history
|
|
64
|
+
- **NEVER use `--human` flag** — that enables interactive prompts which agents cannot handle
|
|
65
|
+
- After wallet creation, you do NOT need the password for future operations — the keychain handles it
|
|
66
|
+
- If you get a `PASSWORD_REQUIRED` error, ask the user to provide their password again
|
|
67
|
+
|
|
68
|
+
## Create
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Ask the user for a password first, then:
|
|
72
|
+
NANSEN_WALLET_PASSWORD="<password_from_user>" nansen wallet create
|
|
73
|
+
# Or with a custom name:
|
|
74
|
+
NANSEN_WALLET_PASSWORD="<password_from_user>" nansen wallet create --name trading
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## List & Show
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
nansen wallet list
|
|
81
|
+
nansen wallet show <name>
|
|
82
|
+
nansen wallet default <name>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Send
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Send native token (SOL, ETH) — password auto-resolved from keychain
|
|
89
|
+
nansen wallet send --to <addr> --amount 1.5 --chain solana
|
|
90
|
+
|
|
91
|
+
# Send entire balance
|
|
92
|
+
nansen wallet send --to <addr> --chain evm --max
|
|
93
|
+
|
|
94
|
+
# Dry run (preview, no broadcast)
|
|
95
|
+
nansen wallet send --to <addr> --amount 1.0 --chain evm --dry-run
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Export & Delete
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Password auto-resolved from keychain
|
|
102
|
+
nansen wallet export <name>
|
|
103
|
+
nansen wallet delete <name>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Forget Password
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Remove saved password from all stores (keychain + .credentials file)
|
|
110
|
+
nansen wallet forget-password
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Migrate to Secure Storage
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
nansen wallet secure
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For detailed migration steps (from `~/.nansen/.env`, `.credentials`, or env-var-only setups), see the **nansen-wallet-migration** skill.
|
|
120
|
+
|
|
121
|
+
## Flags
|
|
122
|
+
|
|
123
|
+
| Flag | Purpose |
|
|
124
|
+
|------|---------|
|
|
125
|
+
| `--to` | Recipient address |
|
|
126
|
+
| `--amount` | Amount to send |
|
|
127
|
+
| `--chain` | `evm` or `solana` |
|
|
128
|
+
| `--max` | Send entire balance |
|
|
129
|
+
| `--dry-run` | Preview without broadcasting |
|
|
130
|
+
| `--human` | Enable interactive prompts (human terminal use only — agents must NOT use this) |
|
|
131
|
+
| `--unsafe-no-password` | Skip encryption (keys stored in plaintext — NOT recommended) |
|
|
132
|
+
|
|
133
|
+
## Environment Variables
|
|
134
|
+
|
|
135
|
+
| Var | Purpose |
|
|
136
|
+
|-----|---------|
|
|
137
|
+
| `NANSEN_WALLET_PASSWORD` | Wallet encryption password — only needed for initial `wallet create`. After that, the OS keychain handles it. |
|
|
138
|
+
| `NANSEN_API_KEY` | API key (also set via `nansen login --api-key <key>`) |
|
|
139
|
+
| `NANSEN_EVM_RPC` | Custom EVM RPC endpoint |
|
|
140
|
+
| `NANSEN_SOLANA_RPC` | Custom Solana RPC endpoint |
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nansen-wallet-profiler
|
|
3
|
+
description: Wallet profiler — balance, PnL, labels, transactions, counterparties, related wallets, batch, trace, compare. Use when analysing a specific wallet address or comparing wallets.
|
|
4
|
+
metadata:
|
|
5
|
+
openclaw:
|
|
6
|
+
requires:
|
|
7
|
+
env:
|
|
8
|
+
- NANSEN_API_KEY
|
|
9
|
+
bins:
|
|
10
|
+
- nansen
|
|
11
|
+
primaryEnv: NANSEN_API_KEY
|
|
12
|
+
install:
|
|
13
|
+
- kind: node
|
|
14
|
+
package: nansen-cli
|
|
15
|
+
bins: [nansen]
|
|
16
|
+
allowed-tools: Bash(nansen:*)
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Wallet Profiler
|
|
20
|
+
|
|
21
|
+
All commands: `nansen research profiler <sub> [options]`
|
|
22
|
+
|
|
23
|
+
`--address` and `--chain` required for most commands.
|
|
24
|
+
|
|
25
|
+
## Balance & Identity
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
nansen research profiler balance --address <addr> --chain ethereum
|
|
29
|
+
nansen research profiler labels --address <addr> --chain ethereum
|
|
30
|
+
nansen research profiler search --query "Vitalik"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## PnL
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
nansen research profiler pnl --address <addr> --chain ethereum --days 30
|
|
37
|
+
nansen research profiler pnl-summary --address <addr> --chain ethereum
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Transactions & History
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
nansen research profiler transactions --address <addr> --chain ethereum --limit 20
|
|
44
|
+
nansen research profiler historical-balances --address <addr> --chain solana --days 30
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Relationships
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
nansen research profiler related-wallets --address <addr> --chain ethereum
|
|
51
|
+
nansen research profiler counterparties --address <addr> --chain ethereum --days 30
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Perps (no --chain)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
nansen research profiler perp-positions --address <addr>
|
|
58
|
+
nansen research profiler perp-trades --address <addr> --days 7
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Batch, Trace & Compare
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Batch — profile multiple wallets at once
|
|
65
|
+
nansen research profiler batch \
|
|
66
|
+
--addresses "0xabc,0xdef" --chain ethereum \
|
|
67
|
+
--include labels,balance,pnl
|
|
68
|
+
|
|
69
|
+
# Trace — BFS multi-hop counterparty trace (makes N*width API calls)
|
|
70
|
+
nansen research profiler trace --address <addr> --chain ethereum --depth 2 --width 5
|
|
71
|
+
|
|
72
|
+
# Compare — shared counterparties and tokens between two wallets
|
|
73
|
+
nansen research profiler compare --addresses "0xabc,0xdef" --chain ethereum
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Flags
|
|
77
|
+
|
|
78
|
+
| Flag | Purpose |
|
|
79
|
+
|------|---------|
|
|
80
|
+
| `--address` | Wallet address (required) |
|
|
81
|
+
| `--chain` | Required except for perps and search |
|
|
82
|
+
| `--days` | Lookback period (default 30) |
|
|
83
|
+
| `--limit` | Number of results |
|
|
84
|
+
| `--include` | Batch fields: `labels,balance,pnl` |
|
|
85
|
+
| `--depth` | Trace depth 1-5 (default 2) |
|
|
86
|
+
| `--width` | Trace width — keep low to save credits |
|
|
87
|
+
| `--fields` | Select specific fields |
|
|
88
|
+
| `--table` | Human-readable table output |
|
|
89
|
+
| `--format csv` | CSV export |
|
|
90
|
+
|
|
91
|
+
## Notes
|
|
92
|
+
|
|
93
|
+
- `pnl-summary` has no pagination support (returns aggregate stats, not a list).
|
|
94
|
+
- `perp-positions` has no pagination support.
|
|
95
|
+
- `labels` has no pagination support — the API ignores `per_page` and always returns all labels for the address. `--limit` is not available for this sub-command.
|
|
96
|
+
- `transactions` caps at per_page=100 (API limit).
|
|
97
|
+
- `trace` makes many API calls — use `--width` conservatively.
|
|
98
|
+
- `batch` accepts `--file <path>` with one address per line as alternative to `--addresses`.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nansen-web-fetcher
|
|
3
|
+
description: Fetch and analyze content from one or more URLs using AI (Gemini 2.5 Flash). Use when you have specific URLs and need to extract or summarize their content. Pairs well with `nansen web search` results.
|
|
4
|
+
metadata:
|
|
5
|
+
openclaw:
|
|
6
|
+
requires:
|
|
7
|
+
env:
|
|
8
|
+
- NANSEN_API_KEY
|
|
9
|
+
bins:
|
|
10
|
+
- nansen
|
|
11
|
+
primaryEnv: NANSEN_API_KEY
|
|
12
|
+
install:
|
|
13
|
+
- kind: node
|
|
14
|
+
package: nansen-cli
|
|
15
|
+
bins: [nansen]
|
|
16
|
+
allowed-tools: Bash(nansen:*)
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Web Fetch
|
|
20
|
+
|
|
21
|
+
Fetch and analyze content from one or more URLs using Gemini 2.5 Flash with URL context.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
nansen web fetch https://nansen.ai --question "What products does Nansen offer?"
|
|
25
|
+
nansen web fetch --url https://example.com --url https://other.com --question "Compare these two sites"
|
|
26
|
+
nansen web fetch https://docs.uniswap.org/contracts/v4/overview --question "What changed in v4?"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Positional args and `--url` flags can be combined — all become URLs to fetch.
|
|
30
|
+
|
|
31
|
+
| Flag | Values | Default | Purpose |
|
|
32
|
+
|------|--------|---------|---------|
|
|
33
|
+
| `--url` | URL | — | URL to fetch (repeatable for multiple URLs, up to 20) |
|
|
34
|
+
| `--question` | string | **required** | Question to answer about the URL content |
|
|
35
|
+
| `--pretty` | flag | off | Human-readable JSON |
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
- `analysis` — AI-generated answer to your question
|
|
39
|
+
- `retrieved_urls` — URLs successfully fetched
|
|
40
|
+
- `failed_urls` — URLs that could not be retrieved
|
|
41
|
+
|
|
42
|
+
**Tip:** Combine with `web search` — search first to find relevant URLs, then fetch to get full content.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Find and analyze in two steps
|
|
46
|
+
nansen web search "uniswap v4 launch" --num-results 3 --fields link
|
|
47
|
+
nansen web fetch https://blog.uniswap.org/... --question "What are the key changes?"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Note:** 30s timeout. Paywalled or bot-blocked pages may appear in `failed_urls`.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nansen-web-searcher
|
|
3
|
+
description: Search the web for one or more queries in parallel. Use when you need current information, news, prices, or any web content to complement on-chain Nansen data.
|
|
4
|
+
metadata:
|
|
5
|
+
openclaw:
|
|
6
|
+
requires:
|
|
7
|
+
env:
|
|
8
|
+
- NANSEN_API_KEY
|
|
9
|
+
bins:
|
|
10
|
+
- nansen
|
|
11
|
+
primaryEnv: NANSEN_API_KEY
|
|
12
|
+
install:
|
|
13
|
+
- kind: node
|
|
14
|
+
package: nansen-cli
|
|
15
|
+
bins: [nansen]
|
|
16
|
+
allowed-tools: Bash(nansen:*)
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Web Search
|
|
20
|
+
|
|
21
|
+
Search the web for one or more queries in parallel via the Serper API.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
nansen web search "bitcoin price"
|
|
25
|
+
nansen web search "solana ecosystem news" --num-results 5
|
|
26
|
+
nansen web search --query "ethereum ETF" --query "bitcoin ETF" --num-results 3
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Positional args and `--query` flags can be combined — all become queries.
|
|
30
|
+
|
|
31
|
+
| Flag | Values | Default | Purpose |
|
|
32
|
+
|------|--------|---------|---------|
|
|
33
|
+
| `--query` | string | — | Query string (repeatable for multiple queries) |
|
|
34
|
+
| `--num-results` | 1–20 | 10 | Results per query |
|
|
35
|
+
| `--pretty` | flag | off | Human-readable JSON |
|
|
36
|
+
|
|
37
|
+
Returns `results[]` — one entry per query, each with `organic[]` (title, link, snippet, date) and optional `knowledge_graph`.
|
|
38
|
+
|
|
39
|
+
**Note:** Some domains are excluded from results (paywalled/unfetchable sites like bloomberg.com, twitter.com). Use `nansen web fetch` to retrieve content from specific URLs.
|
package/src/api.js
CHANGED
|
@@ -7,9 +7,15 @@ import fs from 'fs';
|
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { EVM_CHAINS } from './chain-ids.js';
|
|
10
|
+
import { getAnonymousId, TELEMETRY_DISABLED } from './telemetry.js';
|
|
10
11
|
|
|
11
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
13
|
|
|
14
|
+
function telemetryHeaders() {
|
|
15
|
+
if (TELEMETRY_DISABLED) return {};
|
|
16
|
+
return { 'X-Anonymous-Id': getAnonymousId() };
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
const { version: packageVersion } = JSON.parse(
|
|
14
20
|
fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')
|
|
15
21
|
);
|
|
@@ -442,6 +448,7 @@ export class NansenAPI {
|
|
|
442
448
|
'Content-Type': 'application/json',
|
|
443
449
|
'X-Client-Type': 'nansen-cli',
|
|
444
450
|
'X-Client-Version': packageVersion,
|
|
451
|
+
...telemetryHeaders(),
|
|
445
452
|
'Payment-Signature': signature,
|
|
446
453
|
...this.defaultHeaders,
|
|
447
454
|
...options.headers,
|
|
@@ -493,11 +500,12 @@ export class NansenAPI {
|
|
|
493
500
|
...(!isGet && { 'Content-Type': 'application/json' }),
|
|
494
501
|
'X-Client-Type': 'nansen-cli',
|
|
495
502
|
'X-Client-Version': packageVersion,
|
|
503
|
+
...telemetryHeaders(),
|
|
496
504
|
...(this.apiKey ? { 'apikey': this.apiKey } : {}),
|
|
497
505
|
...this.defaultHeaders,
|
|
498
506
|
...options.headers
|
|
499
507
|
},
|
|
500
|
-
...(!isGet && { body: JSON.stringify(NansenAPI.cleanBody(body)) })
|
|
508
|
+
...(!isGet && method !== 'DELETE' && { body: JSON.stringify(NansenAPI.cleanBody(body)) })
|
|
501
509
|
});
|
|
502
510
|
} catch (err) {
|
|
503
511
|
// Network-level errors - retry these too
|
|
@@ -538,12 +546,20 @@ export class NansenAPI {
|
|
|
538
546
|
}
|
|
539
547
|
|
|
540
548
|
if (!response.ok) {
|
|
541
|
-
let message = data.message || data.error
|
|
549
|
+
let message = data.message || data.error
|
|
550
|
+
|| (typeof data.detail === 'string' ? data.detail : data.detail?.message)
|
|
551
|
+
|| `API error: ${response.status}`;
|
|
552
|
+
// nansen-api proxy stringifies nested error dicts via Python str(), producing
|
|
553
|
+
// "{'message': 'actual error', ...}". Extract the inner message if present.
|
|
554
|
+
const nestedMatch = typeof message === 'string' && message.match(/['"]message['"]\s*:\s*['"](.*?)['"]/);
|
|
555
|
+
if (nestedMatch) message = nestedMatch[1];
|
|
542
556
|
const code = statusToErrorCode(response.status, data);
|
|
543
557
|
const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'));
|
|
544
558
|
|
|
545
559
|
// Enhance messages for specific error codes
|
|
546
|
-
if (code === ErrorCode.
|
|
560
|
+
if (code === ErrorCode.UNAUTHORIZED) {
|
|
561
|
+
message = this.apiKey ? message : 'Not logged in. Run: nansen login';
|
|
562
|
+
} else if (code === ErrorCode.UNSUPPORTED_FILTER) {
|
|
547
563
|
message = message.replace(/\.+$/, '') + '. This filter is not supported for this token/chain combination. Do not retry.';
|
|
548
564
|
} else if (code === ErrorCode.CREDITS_EXHAUSTED) {
|
|
549
565
|
message = message.replace(/\.+$/, '') + '. No retry will help. Check your Nansen dashboard for credit balance.';
|
|
@@ -819,6 +835,31 @@ export class NansenAPI {
|
|
|
819
835
|
return this.request('/api/v1/search/general', body);
|
|
820
836
|
}
|
|
821
837
|
|
|
838
|
+
async webSearch(params = {}) {
|
|
839
|
+
const { queries, numResults = 10 } = params;
|
|
840
|
+
if (!queries || queries.length === 0) {
|
|
841
|
+
throw new NansenError('At least one query is required', ErrorCode.MISSING_PARAM);
|
|
842
|
+
}
|
|
843
|
+
return this.request('/api/v1/search/web-search', {
|
|
844
|
+
queries,
|
|
845
|
+
num_results: numResults,
|
|
846
|
+
}, { cache: false });
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
async webFetch(params = {}) {
|
|
850
|
+
const { urls, question } = params;
|
|
851
|
+
if (!urls || urls.length === 0) {
|
|
852
|
+
throw new NansenError('At least one URL is required', ErrorCode.MISSING_PARAM);
|
|
853
|
+
}
|
|
854
|
+
if (!question) {
|
|
855
|
+
throw new NansenError('A question is required', ErrorCode.MISSING_PARAM);
|
|
856
|
+
}
|
|
857
|
+
return this.request('/api/v1/search/web-fetch', {
|
|
858
|
+
urls,
|
|
859
|
+
question,
|
|
860
|
+
}, { cache: false });
|
|
861
|
+
}
|
|
862
|
+
|
|
822
863
|
async addressHistoricalBalances(params = {}) {
|
|
823
864
|
const { address, chain = 'ethereum', filters = {}, orderBy, pagination, days = 30 } = params;
|
|
824
865
|
if (address) {
|
|
@@ -1264,6 +1305,38 @@ export class NansenAPI {
|
|
|
1264
1305
|
wallet_address: walletAddress
|
|
1265
1306
|
});
|
|
1266
1307
|
}
|
|
1308
|
+
|
|
1309
|
+
// ============= Smart Alert Endpoints =============
|
|
1310
|
+
|
|
1311
|
+
async alertsList(params = {}) {
|
|
1312
|
+
const defined = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== undefined));
|
|
1313
|
+
const qs = Object.keys(defined).length > 0 ? '?' + new URLSearchParams(defined).toString() : '';
|
|
1314
|
+
return this.request(`/api/v1/smart-alert/list${qs}`, {}, { method: 'GET' });
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
async alertsCreate(params = {}) {
|
|
1318
|
+
return this.request('/api/v1/smart-alert', params);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
async alertsUpdate(params = {}) {
|
|
1322
|
+
return this.request('/api/v1/smart-alert', params, { method: 'PATCH' });
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
async alertsToggle(params = {}) {
|
|
1326
|
+
return this.request('/api/v1/smart-alert/toggle', params, { method: 'PATCH' });
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
async alertsGet(id) {
|
|
1330
|
+
// TODO: replace with GET /api/v1/smart-alert/{id} once a get-by-id endpoint exists.
|
|
1331
|
+
// Fetching the full list does not scale for users with many alerts.
|
|
1332
|
+
const result = await this.alertsList();
|
|
1333
|
+
const alerts = Array.isArray(result) ? result : result?.alerts ?? result?.data ?? [];
|
|
1334
|
+
return alerts.find(a => a.id === id) ?? null;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
async alertsDelete(alertId) {
|
|
1338
|
+
return this.request(`/api/v1/smart-alert/${encodeURIComponent(alertId)}`, {}, { method: 'DELETE' });
|
|
1339
|
+
}
|
|
1267
1340
|
}
|
|
1268
1341
|
|
|
1269
1342
|
export default NansenAPI;
|