nansen-cli 1.6.0 → 1.8.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/AGENTS.md +176 -0
- package/CLAUDE.md +16 -19
- package/README.md +179 -110
- package/SKILL.md +25 -21
- package/TODO.md +17 -0
- package/package.json +3 -1
- package/scripts/check-changeset.js +28 -0
- package/src/api.js +81 -60
- package/src/cli.js +401 -354
- package/src/crypto.js +215 -0
- package/src/ens.js +163 -0
- package/src/trading.js +1081 -0
- package/src/transfer.js +723 -0
- package/src/update-check.js +35 -0
- package/src/wallet.js +764 -0
- package/src/x402-evm.js +207 -0
- package/src/x402-svm.js +474 -0
- package/src/x402.js +205 -0
- package/vitest.e2e.config.js +10 -0
package/SKILL.md
CHANGED
|
@@ -12,21 +12,40 @@ compatibility: Requires Node.js 18+. Needs NANSEN_API_KEY environment variable o
|
|
|
12
12
|
|
|
13
13
|
Command-line interface for the [Nansen API](https://docs.nansen.ai) - onchain analytics for crypto investors and AI agents.
|
|
14
14
|
|
|
15
|
+
## CLI vs Direct API
|
|
16
|
+
|
|
17
|
+
If your agent has HTTP access (curl, fetch), you can skip the CLI and hit the [Nansen REST API](https://docs.nansen.ai) directly with `apiKey` header auth. The CLI is most useful for terminal-native agents (Claude Code, Codex, Cursor) that benefit from `--pretty`, `--table`, `--fields`, built-in retries, and schema introspection.
|
|
18
|
+
|
|
15
19
|
## Setup
|
|
16
20
|
|
|
17
21
|
```bash
|
|
18
22
|
# Install globally
|
|
19
23
|
npm install -g nansen-cli
|
|
20
24
|
|
|
21
|
-
# Authenticate
|
|
22
|
-
|
|
25
|
+
# Authenticate — pick the method that works for your context:
|
|
26
|
+
|
|
27
|
+
# Option A: Non-interactive (best for agents — no prompts, no wasted credits)
|
|
28
|
+
mkdir -p ~/.nansen && echo '{"apiKey":"YOUR_KEY","baseUrl":"https://api.nansen.ai"}' > ~/.nansen/config.json && chmod 600 ~/.nansen/config.json
|
|
23
29
|
|
|
24
|
-
#
|
|
30
|
+
# Option B: Environment variable (good for CI/scripts)
|
|
25
31
|
export NANSEN_API_KEY=your-api-key
|
|
32
|
+
|
|
33
|
+
# Option C: Interactive login (burns 1 credit to validate)
|
|
34
|
+
nansen login
|
|
26
35
|
```
|
|
27
36
|
|
|
28
37
|
Get your API key at [app.nansen.ai/api](https://app.nansen.ai/api).
|
|
29
38
|
|
|
39
|
+
### Verify Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Free check (no API key needed):
|
|
43
|
+
nansen schema | head -1
|
|
44
|
+
|
|
45
|
+
# Full check (uses 1 credit):
|
|
46
|
+
nansen token screener --chain solana --limit 1
|
|
47
|
+
```
|
|
48
|
+
|
|
30
49
|
## Commands
|
|
31
50
|
|
|
32
51
|
### Smart Money
|
|
@@ -82,7 +101,7 @@ nansen portfolio defi --wallet 0x123...
|
|
|
82
101
|
|
|
83
102
|
## Supported Chains
|
|
84
103
|
|
|
85
|
-
ethereum, solana, base, bnb, arbitrum, polygon, optimism, avalanche, linea, scroll,
|
|
104
|
+
ethereum, solana, base, bnb, arbitrum, polygon, optimism, avalanche, linea, scroll, mantle, ronin, sei, plasma, sonic, monad, hyperevm, iotaevm
|
|
86
105
|
|
|
87
106
|
## Smart Money Labels
|
|
88
107
|
|
|
@@ -96,24 +115,9 @@ nansen schema --pretty
|
|
|
96
115
|
nansen schema smart-money --pretty
|
|
97
116
|
```
|
|
98
117
|
|
|
99
|
-
##
|
|
100
|
-
|
|
101
|
-
### Chain/Token-Specific Limitations
|
|
102
|
-
- `token holders --smart-money` — Fails with `UNSUPPORTED_FILTER` for tokens without smart money tracking (e.g., WCT on Optimism). Not all tokens have smart money data. Do not retry.
|
|
103
|
-
- `token flow-intelligence` — May return all-zero flows for tokens without significant smart money activity. This is normal, not an error.
|
|
104
|
-
|
|
105
|
-
### Credit Management
|
|
106
|
-
- `profiler labels` and `profiler balance` consume credits. Budget ~20 calls per session.
|
|
107
|
-
- `Insufficient credits` (403, code `CREDITS_EXHAUSTED`) is a hard stop — no retry will help.
|
|
108
|
-
- Check your Nansen dashboard for credit balance: [app.nansen.ai](https://app.nansen.ai).
|
|
109
|
-
- Run balance checks in batches of 3-4 to avoid burning credits on rate-limit retries.
|
|
118
|
+
## Troubleshooting
|
|
110
119
|
|
|
111
|
-
|
|
112
|
-
| Code | Meaning | Action |
|
|
113
|
-
|------|---------|--------|
|
|
114
|
-
| `UNSUPPORTED_FILTER` | Filter not available for this token/chain | Remove the filter and retry, or skip this token |
|
|
115
|
-
| `CREDITS_EXHAUSTED` | API credits depleted | Stop all API calls. Check dashboard. |
|
|
116
|
-
| `RATE_LIMITED` | Too many requests (429) | Wait and retry (automatic with default retry) |
|
|
120
|
+
See [AGENTS.md — Troubleshooting](AGENTS.md#troubleshooting) for the full troubleshooting guide, including error codes, known endpoint quirks, and pagination gotchas.
|
|
117
121
|
|
|
118
122
|
## Examples
|
|
119
123
|
|
package/TODO.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
> **Built by agents, for agents.** We prioritize improvements that create the best possible AI agent experience.
|
|
4
4
|
|
|
5
|
+
## P0 - Trading Agent Support
|
|
6
|
+
|
|
7
|
+
### Wallet Management
|
|
8
|
+
- [ ] `nansen wallet create` — generate a local wallet (per chain), store key securely on disk
|
|
9
|
+
- [ ] `nansen wallet address` — print the wallet address for funding
|
|
10
|
+
- [ ] `nansen wallet balance` — check wallet balance
|
|
11
|
+
|
|
12
|
+
### Trading Execution
|
|
13
|
+
- [x] `nansen quote` — get a quote for a DEX swap (chain, tokens, amount)
|
|
14
|
+
- [x] `nansen execute` — sign and submit a trade via Nansen API (takes quote-id)
|
|
15
|
+
- [ ] ⚠️ EVM transaction signing — requires thorough security review before production use
|
|
16
|
+
|
|
17
|
+
> These commands are required for `nansen-trading-agent` — the autonomous trading sub-agent.
|
|
18
|
+
> Wallet commands should keep the agent self-contained with zero external dependencies.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
5
22
|
## P2 - Nice to Have
|
|
6
23
|
|
|
7
24
|
### Test Coverage Gaps
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nansen-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.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,10 +9,12 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"start": "node src/index.js",
|
|
12
|
+
"pretest": "node scripts/check-changeset.js",
|
|
12
13
|
"test": "vitest run",
|
|
13
14
|
"test:watch": "vitest",
|
|
14
15
|
"test:coverage": "vitest run --coverage",
|
|
15
16
|
"test:live": "NANSEN_LIVE_TEST=1 vitest run",
|
|
17
|
+
"test:swap": "vitest run --config vitest.e2e.config.js",
|
|
16
18
|
"changeset": "changeset",
|
|
17
19
|
"changeset:version": "changeset version",
|
|
18
20
|
"changeset:publish": "changeset publish"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Non-blocking check: warns if the current branch has no new changeset file
|
|
5
|
+
* compared to main. Runs as a pretest hook so agents and humans see a reminder.
|
|
6
|
+
* Always exits 0 — this is a nudge, not a gate.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const branch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
|
|
13
|
+
if (branch === "main") process.exit(0);
|
|
14
|
+
|
|
15
|
+
const newChangesets = execSync(
|
|
16
|
+
"git diff main --name-only --diff-filter=A -- .changeset/*.md",
|
|
17
|
+
{ encoding: "utf8" }
|
|
18
|
+
).trim();
|
|
19
|
+
|
|
20
|
+
if (!newChangesets) {
|
|
21
|
+
console.error(
|
|
22
|
+
"\x1b[33m[changeset] No new changeset file found on this branch. " +
|
|
23
|
+
"If this PR changes user-facing behavior, add one: npx changeset\x1b[0m"
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// Not a git repo, main doesn't exist, etc. — skip silently.
|
|
28
|
+
}
|
package/src/api.js
CHANGED
|
@@ -320,6 +320,11 @@ function loadConfig() {
|
|
|
320
320
|
config = { apiKey: null, baseUrl: 'https://api.nansen.ai' };
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
// Ensure baseUrl default (config file from older versions may omit it)
|
|
324
|
+
if (!config.baseUrl) {
|
|
325
|
+
config.baseUrl = 'https://api.nansen.ai';
|
|
326
|
+
}
|
|
327
|
+
|
|
323
328
|
// Env vars override individual fields
|
|
324
329
|
if (process.env.NANSEN_API_KEY) {
|
|
325
330
|
config.apiKey = process.env.NANSEN_API_KEY;
|
|
@@ -386,6 +391,17 @@ function parseRetryAfter(headerValue) {
|
|
|
386
391
|
return null;
|
|
387
392
|
}
|
|
388
393
|
|
|
394
|
+
/**
|
|
395
|
+
* Build a date range from today back N days
|
|
396
|
+
* @param {number} days - Number of days back from today
|
|
397
|
+
* @returns {{from: string, to: string}} Date range with YYYY-MM-DD strings
|
|
398
|
+
*/
|
|
399
|
+
export function buildDateRange(days) {
|
|
400
|
+
const to = new Date().toISOString().split('T')[0];
|
|
401
|
+
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
402
|
+
return { from, to };
|
|
403
|
+
}
|
|
404
|
+
|
|
389
405
|
export class NansenAPI {
|
|
390
406
|
constructor(apiKey = config.apiKey, baseUrl = config.baseUrl, options = {}) {
|
|
391
407
|
this.apiKey = apiKey || null;
|
|
@@ -489,7 +505,41 @@ export class NansenAPI {
|
|
|
489
505
|
} else if (code === ErrorCode.CREDITS_EXHAUSTED) {
|
|
490
506
|
message = message.replace(/\.+$/, '') + '. No retry will help. Check your Nansen dashboard for credit balance.';
|
|
491
507
|
} else if (code === ErrorCode.PAYMENT_REQUIRED) {
|
|
492
|
-
|
|
508
|
+
// Try x402 auto-payment with fallback across payment networks
|
|
509
|
+
if (!this.defaultHeaders['Payment-Signature']) {
|
|
510
|
+
try {
|
|
511
|
+
const { createPaymentSignatures } = await import('./x402.js');
|
|
512
|
+
for await (const { signature, network } of createPaymentSignatures(response, url)) {
|
|
513
|
+
const paidResponse = await fetch(url, {
|
|
514
|
+
method: 'POST',
|
|
515
|
+
headers: {
|
|
516
|
+
'Content-Type': 'application/json',
|
|
517
|
+
'X-Client-Type': 'nansen-cli',
|
|
518
|
+
'X-Client-Version': packageVersion,
|
|
519
|
+
'Payment-Signature': signature,
|
|
520
|
+
...this.defaultHeaders,
|
|
521
|
+
...options.headers,
|
|
522
|
+
},
|
|
523
|
+
body: JSON.stringify(NansenAPI.cleanBody(body)),
|
|
524
|
+
});
|
|
525
|
+
if (paidResponse.ok) {
|
|
526
|
+
const chain = network.startsWith('solana:') ? 'Solana' : 'Base';
|
|
527
|
+
console.error(`[x402] Paid via ${chain} USDC`);
|
|
528
|
+
// Check remaining balance and warn if low
|
|
529
|
+
try {
|
|
530
|
+
const { checkX402Balance } = await import('./x402.js');
|
|
531
|
+
const balance = await checkX402Balance(network);
|
|
532
|
+
if (balance !== null && balance < 0.25) {
|
|
533
|
+
console.error(`[x402] Warning: USDC balance low ($${balance.toFixed(2)}). Fund your wallet to avoid interruptions.`);
|
|
534
|
+
}
|
|
535
|
+
} catch { /* balance check is best-effort */ }
|
|
536
|
+
return await paidResponse.json();
|
|
537
|
+
}
|
|
538
|
+
// This payment option was rejected, try next
|
|
539
|
+
}
|
|
540
|
+
} catch { /* x402 auto-pay unavailable, fall through */ }
|
|
541
|
+
}
|
|
542
|
+
message = 'Payment required. To access this endpoint:\n • Set an API key: nansen login --api-key <key> (get one at https://app.nansen.ai/api)\n • Or pay per call: nansen wallet create, fund with USDC on Base or Solana (from $0.01/call, min $0.05 balance)\n • Docs: https://docs.x402.org';
|
|
493
543
|
const paymentHeader = response.headers.get('payment-required');
|
|
494
544
|
if (paymentHeader) {
|
|
495
545
|
try {
|
|
@@ -585,11 +635,9 @@ export class NansenAPI {
|
|
|
585
635
|
|
|
586
636
|
async smartMoneyHistoricalHoldings(params = {}) {
|
|
587
637
|
const { chains = ['solana'], filters = {}, orderBy, pagination, days = 30 } = params;
|
|
588
|
-
const to = new Date().toISOString().split('T')[0];
|
|
589
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
590
638
|
return this.request('/api/v1/smart-money/historical-holdings', {
|
|
591
639
|
chains,
|
|
592
|
-
date_range:
|
|
640
|
+
date_range: buildDateRange(days),
|
|
593
641
|
filters,
|
|
594
642
|
order_by: orderBy,
|
|
595
643
|
pagination
|
|
@@ -632,11 +680,7 @@ export class NansenAPI {
|
|
|
632
680
|
const validation = validateAddress(address, chain);
|
|
633
681
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
634
682
|
}
|
|
635
|
-
const dateRange = date || (
|
|
636
|
-
const to = new Date().toISOString().split('T')[0];
|
|
637
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
638
|
-
return { from, to };
|
|
639
|
-
})();
|
|
683
|
+
const dateRange = date || buildDateRange(days);
|
|
640
684
|
return this.request('/api/v1/profiler/address/transactions', {
|
|
641
685
|
address,
|
|
642
686
|
chain,
|
|
@@ -653,13 +697,7 @@ export class NansenAPI {
|
|
|
653
697
|
const validation = validateAddress(address, chain);
|
|
654
698
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
655
699
|
}
|
|
656
|
-
|
|
657
|
-
let dateRange = date;
|
|
658
|
-
if (!dateRange) {
|
|
659
|
-
const to = new Date().toISOString().split('T')[0];
|
|
660
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
661
|
-
dateRange = { from, to };
|
|
662
|
-
}
|
|
700
|
+
const dateRange = date || buildDateRange(days);
|
|
663
701
|
return this.request('/api/v1/profiler/address/pnl', {
|
|
664
702
|
address,
|
|
665
703
|
chain,
|
|
@@ -695,12 +733,10 @@ export class NansenAPI {
|
|
|
695
733
|
const validation = validateAddress(address, chain);
|
|
696
734
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
697
735
|
}
|
|
698
|
-
const to = new Date().toISOString().split('T')[0];
|
|
699
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
700
736
|
return this.request('/api/v1/profiler/address/historical-balances', {
|
|
701
737
|
address,
|
|
702
738
|
chain,
|
|
703
|
-
date:
|
|
739
|
+
date: buildDateRange(days),
|
|
704
740
|
filters,
|
|
705
741
|
order_by: orderBy,
|
|
706
742
|
pagination
|
|
@@ -727,12 +763,10 @@ export class NansenAPI {
|
|
|
727
763
|
const validation = validateAddress(address, chain);
|
|
728
764
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
729
765
|
}
|
|
730
|
-
const to = new Date().toISOString().split('T')[0];
|
|
731
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
732
766
|
return this.request('/api/v1/profiler/address/counterparties', {
|
|
733
767
|
address,
|
|
734
768
|
chain,
|
|
735
|
-
date:
|
|
769
|
+
date: buildDateRange(days),
|
|
736
770
|
filters,
|
|
737
771
|
order_by: orderBy,
|
|
738
772
|
pagination
|
|
@@ -745,12 +779,10 @@ export class NansenAPI {
|
|
|
745
779
|
const validation = validateAddress(address, chain);
|
|
746
780
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
747
781
|
}
|
|
748
|
-
const to = new Date().toISOString().split('T')[0];
|
|
749
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
750
782
|
return this.request('/api/v1/profiler/address/pnl-summary', {
|
|
751
783
|
address,
|
|
752
784
|
chain,
|
|
753
|
-
date:
|
|
785
|
+
date: buildDateRange(days),
|
|
754
786
|
order_by: orderBy,
|
|
755
787
|
pagination
|
|
756
788
|
});
|
|
@@ -769,11 +801,9 @@ export class NansenAPI {
|
|
|
769
801
|
|
|
770
802
|
async addressPerpTrades(params = {}) {
|
|
771
803
|
const { address, filters = {}, orderBy, pagination, days = 30 } = params;
|
|
772
|
-
const to = new Date().toISOString().split('T')[0];
|
|
773
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
774
804
|
return this.request('/api/v1/profiler/perp-trades', {
|
|
775
805
|
address,
|
|
776
|
-
date:
|
|
806
|
+
date: buildDateRange(days),
|
|
777
807
|
filters,
|
|
778
808
|
order_by: orderBy,
|
|
779
809
|
pagination
|
|
@@ -815,11 +845,7 @@ export class NansenAPI {
|
|
|
815
845
|
const validation = validateTokenAddress(tokenAddress, chain);
|
|
816
846
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
817
847
|
}
|
|
818
|
-
const dateRange = date || (
|
|
819
|
-
const to = new Date().toISOString().split('T')[0];
|
|
820
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
821
|
-
return { from, to };
|
|
822
|
-
})();
|
|
848
|
+
const dateRange = date || buildDateRange(days);
|
|
823
849
|
return this.request('/api/v1/tgm/flows', {
|
|
824
850
|
token_address: tokenAddress,
|
|
825
851
|
chain,
|
|
@@ -836,9 +862,6 @@ export class NansenAPI {
|
|
|
836
862
|
const validation = validateTokenAddress(tokenAddress, chain);
|
|
837
863
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
838
864
|
}
|
|
839
|
-
const to = new Date().toISOString().split('T')[0];
|
|
840
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
841
|
-
|
|
842
865
|
// Apply smart money filter via filters object
|
|
843
866
|
if (onlySmartMoney) {
|
|
844
867
|
filters.include_smart_money_labels = filters.include_smart_money_labels ||
|
|
@@ -848,7 +871,7 @@ export class NansenAPI {
|
|
|
848
871
|
return this.request('/api/v1/tgm/dex-trades', {
|
|
849
872
|
token_address: tokenAddress,
|
|
850
873
|
chain,
|
|
851
|
-
date:
|
|
874
|
+
date: buildDateRange(days),
|
|
852
875
|
filters,
|
|
853
876
|
order_by: orderBy,
|
|
854
877
|
pagination
|
|
@@ -861,12 +884,10 @@ export class NansenAPI {
|
|
|
861
884
|
const validation = validateTokenAddress(tokenAddress, chain);
|
|
862
885
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
863
886
|
}
|
|
864
|
-
const to = new Date().toISOString().split('T')[0];
|
|
865
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
866
887
|
return this.request('/api/v1/tgm/pnl-leaderboard', {
|
|
867
888
|
token_address: tokenAddress,
|
|
868
889
|
chain,
|
|
869
|
-
date:
|
|
890
|
+
date: buildDateRange(days),
|
|
870
891
|
filters,
|
|
871
892
|
order_by: orderBy,
|
|
872
893
|
pagination
|
|
@@ -879,11 +900,7 @@ export class NansenAPI {
|
|
|
879
900
|
const validation = validateTokenAddress(tokenAddress, chain);
|
|
880
901
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
881
902
|
}
|
|
882
|
-
const dateRange = date || (
|
|
883
|
-
const to = new Date().toISOString().split('T')[0];
|
|
884
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
885
|
-
return { from, to };
|
|
886
|
-
})();
|
|
903
|
+
const dateRange = date || buildDateRange(days);
|
|
887
904
|
return this.request('/api/v1/tgm/who-bought-sold', {
|
|
888
905
|
token_address: tokenAddress,
|
|
889
906
|
chain,
|
|
@@ -912,12 +929,10 @@ export class NansenAPI {
|
|
|
912
929
|
const validation = validateTokenAddress(tokenAddress, chain);
|
|
913
930
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
914
931
|
}
|
|
915
|
-
const to = new Date().toISOString().split('T')[0];
|
|
916
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
917
932
|
return this.request('/api/v1/tgm/transfers', {
|
|
918
933
|
token_address: tokenAddress,
|
|
919
934
|
chain,
|
|
920
|
-
date:
|
|
935
|
+
date: buildDateRange(days),
|
|
921
936
|
filters,
|
|
922
937
|
order_by: orderBy,
|
|
923
938
|
pagination
|
|
@@ -941,11 +956,9 @@ export class NansenAPI {
|
|
|
941
956
|
|
|
942
957
|
async tokenPerpTrades(params = {}) {
|
|
943
958
|
const { tokenSymbol, filters = {}, orderBy, pagination, days = 30 } = params;
|
|
944
|
-
const to = new Date().toISOString().split('T')[0];
|
|
945
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
946
959
|
return this.request('/api/v1/tgm/perp-trades', {
|
|
947
960
|
token_symbol: tokenSymbol,
|
|
948
|
-
date:
|
|
961
|
+
date: buildDateRange(days),
|
|
949
962
|
filters,
|
|
950
963
|
order_by: orderBy,
|
|
951
964
|
pagination
|
|
@@ -964,11 +977,9 @@ export class NansenAPI {
|
|
|
964
977
|
|
|
965
978
|
async tokenPerpPnlLeaderboard(params = {}) {
|
|
966
979
|
const { tokenSymbol, filters = {}, orderBy, pagination, days = 30 } = params;
|
|
967
|
-
const to = new Date().toISOString().split('T')[0];
|
|
968
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
969
980
|
return this.request('/api/v1/tgm/perp-pnl-leaderboard', {
|
|
970
981
|
token_symbol: tokenSymbol,
|
|
971
|
-
date:
|
|
982
|
+
date: buildDateRange(days),
|
|
972
983
|
filters,
|
|
973
984
|
order_by: orderBy,
|
|
974
985
|
pagination
|
|
@@ -987,6 +998,20 @@ export class NansenAPI {
|
|
|
987
998
|
});
|
|
988
999
|
}
|
|
989
1000
|
|
|
1001
|
+
async tokenOhlcv(params = {}) {
|
|
1002
|
+
const { tokenAddress, chain = 'solana', timeframe, pagination } = params;
|
|
1003
|
+
if (tokenAddress) {
|
|
1004
|
+
const validation = validateTokenAddress(tokenAddress, chain);
|
|
1005
|
+
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
1006
|
+
}
|
|
1007
|
+
return this.request('/api/v1/tgm/token-ohlcv', {
|
|
1008
|
+
token_address: tokenAddress,
|
|
1009
|
+
chain,
|
|
1010
|
+
timeframe,
|
|
1011
|
+
pagination
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
|
|
990
1015
|
async tokenInformation(params = {}) {
|
|
991
1016
|
const { tokenAddress, chain = 'solana', timeframe = '1d' } = params;
|
|
992
1017
|
if (tokenAddress) {
|
|
@@ -1004,10 +1029,8 @@ export class NansenAPI {
|
|
|
1004
1029
|
|
|
1005
1030
|
async perpScreener(params = {}) {
|
|
1006
1031
|
const { filters = {}, orderBy, pagination, days = 30 } = params;
|
|
1007
|
-
const to = new Date().toISOString().split('T')[0];
|
|
1008
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
1009
1032
|
return this.request('/api/v1/perp-screener', {
|
|
1010
|
-
date:
|
|
1033
|
+
date: buildDateRange(days),
|
|
1011
1034
|
filters,
|
|
1012
1035
|
order_by: orderBy,
|
|
1013
1036
|
pagination
|
|
@@ -1016,10 +1039,8 @@ export class NansenAPI {
|
|
|
1016
1039
|
|
|
1017
1040
|
async perpLeaderboard(params = {}) {
|
|
1018
1041
|
const { filters = {}, orderBy, pagination, days = 30 } = params;
|
|
1019
|
-
const to = new Date().toISOString().split('T')[0];
|
|
1020
|
-
const from = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
|
1021
1042
|
return this.request('/api/v1/perp-leaderboard', {
|
|
1022
|
-
date:
|
|
1043
|
+
date: buildDateRange(days),
|
|
1023
1044
|
filters,
|
|
1024
1045
|
order_by: orderBy,
|
|
1025
1046
|
pagination
|