nansen-cli 1.38.0 → 1.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.40.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#509](https://github.com/nansen-ai/nansen-cli/pull/509) [`430c300`](https://github.com/nansen-ai/nansen-cli/commit/430c3003d28a44bd1bfb123eef9290a7350a7e1e) Thanks [@kome12](https://github.com/kome12)! - `trade execute` now revokes an existing on-chain ERC-20 allowance before
8
+ re-approving when it is more than 10x the current trade's scoped amount, such
9
+ as a legacy unlimited approval or an allowance granted by another app. Most
10
+ trades are unaffected. Opt out with `--no-revoke-excessive-allowance`.
11
+
12
+ After each revoke or reapproval, the CLI reads the resulting allowance back
13
+ on-chain and fails closed (instead of proceeding to the swap) if it doesn't
14
+ match what was expected or can't be read.
15
+
16
+ ### Patch Changes
17
+
18
+ - [#498](https://github.com/nansen-ai/nansen-cli/pull/498) [`a964dd1`](https://github.com/nansen-ai/nansen-cli/commit/a964dd19c826f5231d2651547212d8169a74e7fe) Thanks [@crazywriter1](https://github.com/crazywriter1)! - Use `pending` nonce block tag for EVM sends: back-to-back transfers no longer risk reusing the same nonce when mempool transactions are queued.
19
+
20
+ - [#493](https://github.com/nansen-ai/nansen-cli/pull/493) [`bc89fef`](https://github.com/nansen-ai/nansen-cli/commit/bc89fef74489da3df32a12079effbdfa899373fd) Thanks [@crazywriter1](https://github.com/crazywriter1)! - Validate `--slippage-bps` on `limit-order create`: values outside 0-10000 now fail with a clear error before any auth/API call.
21
+
22
+ ## 1.39.0
23
+
24
+ ### Minor Changes
25
+
26
+ - [#495](https://github.com/nansen-ai/nansen-cli/pull/495) [`3306897`](https://github.com/nansen-ai/nansen-cli/commit/3306897c1aaae594f4401fd4656b2451ab375d78) Thanks [@kome12](https://github.com/kome12)! - Add EVM swap-outcome verification to `trade execute`. Before broadcasting a swap on an EVM chain (Base), the CLI now simulates the transaction and confirms the wallet's balance changes match the quote — the input is spent within your maximum, at least the expected output is received, and no other token or NFT leaves the wallet — refusing to sign when they don't. This runs on top of the existing pre-broadcast checks and needs a simulation-capable RPC (`NANSEN_BASE_SIM_RPC`); when none is available it degrades with a warning rather than blocking the trade. Skip it with `--no-verify-outcome`. Solana is unaffected.
27
+
28
+ ### Patch Changes
29
+
30
+ - [#495](https://github.com/nansen-ai/nansen-cli/pull/495) [`e8cf217`](https://github.com/nansen-ai/nansen-cli/commit/e8cf217feaa9e7c8f68f4f3c3c2a49adcda07101) Thanks [@kome12](https://github.com/kome12)! - Harden swap-outcome verification error handling: a revert reported by the simulation endpoint as a top-level JSON-RPC error (rather than a per-call status) now fails closed (blocks the swap) instead of degrading, and a non-2xx simulation response (e.g. HTTP 401 "Invalid API key") now degrades with the real status and message instead of a misleading "returned no call result" warning.
31
+
32
+ - [#499](https://github.com/nansen-ai/nansen-cli/pull/499) [`de0bcc5`](https://github.com/nansen-ai/nansen-cli/commit/de0bcc562bcd20a80edd3ab2f486870b80629c83) Thanks [@gulshngill](https://github.com/gulshngill)! - Fix `profiler labels`: call `/api/v1/profiler/address/labels` with its v1 request body — the beta endpoint previously used was removed from the Nansen API. `profiler batch --include labels` now returns the label array itself instead of the raw `{pagination, data}` envelope.
33
+
34
+ - [#506](https://github.com/nansen-ai/nansen-cli/pull/506) [`f407edb`](https://github.com/nansen-ai/nansen-cli/commit/f407edb19444d6b5a1a631d29b4c4fb9bd280708) Thanks [@gulshngill](https://github.com/gulshngill)! - Add a canonical MCP setup section to the README — endpoint `https://mcp.nansen.ai/ra/mcp`, `NANSEN-API-KEY` auth, per-client setup paths for Claude Code, Claude Tag, and generic or stdio-only clients, plus a pointer to the connection docs for Claude Desktop and Cursor — and point the out-of-credits and low-credit warnings at the credits tab of the billing page, `app.nansen.ai/api?tab=api`, instead of the bare `app.nansen.ai/api`.
35
+
36
+ - [#500](https://github.com/nansen-ai/nansen-cli/pull/500) [`9ccf8a2`](https://github.com/nansen-ai/nansen-cli/commit/9ccf8a20841a9ca01a2627ccf5de2575bf016a46) Thanks [@gulshngill](https://github.com/gulshngill)! - Document global pagination options in `nansen schema`.
37
+
3
38
  ## 1.38.0
4
39
 
5
40
  ### Minor Changes
package/README.md CHANGED
@@ -51,6 +51,61 @@ nansen schema [command] [--pretty] # full command reference (no API key neede
51
51
 
52
52
  Run `nansen schema --pretty` for the full subcommand and field reference.
53
53
 
54
+ ## MCP
55
+
56
+ Connect any MCP client to Nansen's streamable HTTP server:
57
+
58
+ - **Endpoint:** `https://mcp.nansen.ai/ra/mcp`
59
+ - **Authentication:** `NANSEN-API-KEY` header
60
+ - **API key:** [app.nansen.ai/auth/agent-setup](https://app.nansen.ai/auth/agent-setup)
61
+
62
+ **Claude Desktop and Cursor:** setup instructions for both — the Claude Desktop `.dxt` bundle and the Cursor install deep link — are in the connection docs: [docs.nansen.ai/mcp/connecting](https://docs.nansen.ai/mcp/connecting).
63
+
64
+ **One-command (Claude Code):**
65
+
66
+ ```bash
67
+ claude mcp add --transport http nansen https://mcp.nansen.ai/ra/mcp --header "NANSEN-API-KEY: <your-key>"
68
+ ```
69
+
70
+ **Manual (any streamable-HTTP client):** for example, add this to Cursor's `~/.cursor/mcp.json`:
71
+
72
+ ```json
73
+ {
74
+ "mcpServers": {
75
+ "nansen": {
76
+ "url": "https://mcp.nansen.ai/ra/mcp",
77
+ "headers": {
78
+ "NANSEN-API-KEY": "<your-key>"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ **Manual (stdio-only clients):** use `mcp-remote` as a bridge. Keep the header as one argument with no space after the colon:
86
+
87
+ ```json
88
+ {
89
+ "mcpServers": {
90
+ "nansen": {
91
+ "command": "npx",
92
+ "args": [
93
+ "-y",
94
+ "mcp-remote@latest",
95
+ "https://mcp.nansen.ai/ra/mcp",
96
+ "--header",
97
+ "NANSEN-API-KEY:${NANSEN_API_KEY}"
98
+ ],
99
+ "env": {
100
+ "NANSEN_API_KEY": "<your-key>"
101
+ }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ **Claude Tag (Claude in Slack):** an admin must attach a plugin whose `.mcp.json` points at `https://mcp.nansen.ai/ra/mcp` and add a custom credential allowing the host `mcp.nansen.ai`. See the [Claude Tag custom-connections documentation](https://claude.com/docs/claude-tag/admins/connections/custom). Per-user fallback: use Claude Code or Claude Desktop.
108
+
54
109
  ## Trading
55
110
 
56
111
  DEX swaps on `solana` and `base`. Two-step: quote then execute.
@@ -216,7 +271,7 @@ nansen research smart-money netflow --chain solana --fields token_symbol,net_flo
216
271
 
217
272
  | Code | Action |
218
273
  |------|--------|
219
- | `CREDITS_EXHAUSTED` | Stop all API calls immediately. `details.credits.remaining` is your actual balance. Top up at [app.nansen.ai/api](https://app.nansen.ai/api). |
274
+ | `CREDITS_EXHAUSTED` | Stop all API calls immediately. `details.credits.remaining` is your actual balance. Top up at [app.nansen.ai/api?tab=api](https://app.nansen.ai/api?tab=api). |
220
275
  | `UNAUTHORIZED` | Wrong or missing key. Re-auth. |
221
276
  | `RATE_LIMITED` | Auto-retried by CLI. `details.rateLimit.resetSeconds` is how long the window needs to drain. |
222
277
  | `UNSUPPORTED_FILTER` | Remove the filter and retry. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nansen-cli",
3
- "version": "1.38.0",
3
+ "version": "1.40.0",
4
4
  "description": "AI-agent CLI for Nansen API analytics, DEX swaps, and cross-chain trading",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -19,7 +19,7 @@ allowed-tools: Bash(nansen:*)
19
19
  ADDRESSES="0xaddr1,0xaddr2,0xaddr3,..." CHAIN=ethereum
20
20
  nansen research profiler batch --addresses "$ADDRESSES" --chain $CHAIN --include labels,balance
21
21
  # → .data.{total, completed, results[]: {address, chain, labels[], balance, error}}
22
- # labels[]: {label, category ("smart_money","fund","social","behavioral","others"), fullname}
22
+ # labels[]: {label, category ("smart_money","fund","social","behavioral","others"), kind[]}
23
23
  # balance: {data[]: {token_symbol, token_amount, price_usd, value_usd}}
24
24
  ```
25
25
  Check .error per result — invalid addresses return an error message, not a crash. Skip those.
@@ -92,7 +92,7 @@ nansen research profiler compare --addresses "0xabc,0xdef" --chain ethereum
92
92
 
93
93
  - `pnl-summary` has no pagination support (returns aggregate stats, not a list).
94
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.
95
+ - `labels` supports pagination — `--limit`/`--page` are honoured and the response is `{pagination: {page, per_page, is_last_page}, data[]: {label, category, kind[]}}`.
96
96
  - `transactions` caps at per_page=100 (API limit).
97
97
  - `trace` makes many API calls — use `--width` conservatively.
98
98
  - `batch` accepts `--file <path>` with one address per line as alternative to `--addresses`.
package/src/api.js CHANGED
@@ -393,7 +393,7 @@ function requireValidToken(tokenAddress, chain) {
393
393
  if (!v.valid) throw new NansenError(v.error, v.code);
394
394
  }
395
395
 
396
- function loadConfig() {
396
+ export function loadConfig() {
397
397
  // Base config from files, then env vars override individual fields
398
398
  let config = null;
399
399
 
@@ -908,8 +908,9 @@ export class NansenAPI {
908
908
  async addressLabels(params = {}) {
909
909
  const { address, chain = 'ethereum', pagination = { page: 1, per_page: 100 } } = params;
910
910
  if (address) requireValidAddress(address, chain);
911
- return this.request('/api/beta/profiler/address/labels', {
912
- parameters: { address, chain },
911
+ return this.request('/api/v1/profiler/address/labels', {
912
+ address,
913
+ chain,
913
914
  pagination
914
915
  });
915
916
  }
package/src/cli.js CHANGED
@@ -190,7 +190,7 @@ export function parseArgs(args) {
190
190
  const key = arg.slice(2);
191
191
  const next = args[i + 1];
192
192
 
193
- if (key === 'pretty' || key === 'help' || key === 'version' || key === 'table' || key === 'no-retry' || key === 'cache' || key === 'no-cache' || key === 'stream' || key === 'enrich' || key === 'full' || key === 'human' || key === 'enabled' || key === 'disabled' || key === 'expert' || key === 'json' || key === 'offline') {
193
+ if (key === 'pretty' || key === 'help' || key === 'version' || key === 'table' || key === 'no-retry' || key === 'cache' || key === 'no-cache' || key === 'stream' || key === 'enrich' || key === 'full' || key === 'human' || key === 'enabled' || key === 'disabled' || key === 'expert' || key === 'json' || key === 'offline' || key === 'no-simulate' || key === 'no-verify-outcome' || key === 'no-revoke-excessive-allowance') {
194
194
  result.flags[key] = true;
195
195
  } else if (next && (!next.startsWith('-') || /^-\d/.test(next))) {
196
196
  // Try to parse as JSON first (for objects/arrays/booleans),
@@ -489,7 +489,9 @@ async function enrichTransfers(result, apiInstance, chain) {
489
489
  for (const addr of addrs) {
490
490
  try {
491
491
  const labelsResult = await apiInstance.addressLabels({ address: addr, chain });
492
- labelMap[addr] = labelsResult?.labels || labelsResult?.data?.results || [];
492
+ labelMap[addr] = Array.isArray(labelsResult?.data)
493
+ ? labelsResult.data.map(item => item.label)
494
+ : labelsResult?.labels || [];
493
495
  } catch {
494
496
  labelMap[addr] = [];
495
497
  }
@@ -568,7 +570,10 @@ export async function batchProfile(api, params = {}) {
568
570
  }
569
571
  try {
570
572
  if (include.includes('labels')) {
571
- entry.labels = await api.addressLabels({ address, chain });
573
+ const labelsResult = await api.addressLabels({ address, chain });
574
+ entry.labels = Array.isArray(labelsResult?.data)
575
+ ? labelsResult.data
576
+ : labelsResult?.labels || [];
572
577
  }
573
578
  if (include.includes('balance')) {
574
579
  entry.balance = await api.addressBalance({ address, chain });
@@ -401,6 +401,17 @@ export function parseExpiry(expiryStr) {
401
401
  throw new Error(`Invalid expiry format: "${expiryStr}". Use "24h", "7d", "30d", or epoch ms.`);
402
402
  }
403
403
 
404
+ // Whole integer bps in [0, 10000], matching bridge parseSlippageBps.
405
+ // Number() would accept "1.5", "1e2", "0x10", and boolean true.
406
+ function parseSlippageBps(raw) {
407
+ const s = String(raw).trim();
408
+ const bad = 'Error: --slippage-bps must be a whole integer between 0 and 10000 basis points.';
409
+ if (!/^\d+$/.test(s)) throw new Error(bad);
410
+ const n = parseInt(s, 10);
411
+ if (!Number.isInteger(n) || n < 0 || n > 10000) throw new Error(bad);
412
+ return n;
413
+ }
414
+
404
415
  // ============= Order Formatting =============
405
416
 
406
417
  function formatOrderStatus(status) {
@@ -501,7 +512,7 @@ export function buildLimitOrderCommands(deps = {}) {
501
512
  const triggerPrice = options['trigger-price'];
502
513
  const triggerCondition = options['trigger-condition'];
503
514
  const triggerMintRaw = options['trigger-mint'];
504
- const slippageBps = options['slippage-bps'] != null ? Number(options['slippage-bps']) : undefined;
515
+ const slippageBpsRaw = options['slippage-bps'];
505
516
  const expiresStr = options.expires || '30d';
506
517
  const walletName = options.wallet;
507
518
 
@@ -516,7 +527,7 @@ OPTIONS:
516
527
  --trigger-mint <symbol|addr> Token whose price triggers the order (e.g. SOL)
517
528
  --trigger-condition <cond> "above" or "below"
518
529
  --trigger-price <usd> Trigger price in USD (must be a positive number)
519
- --slippage-bps <bps> Slippage in basis points (100 = 1%), omit for auto
530
+ --slippage-bps <bps> Whole integer bps, 0-10000 (100 = 1%), omit for auto
520
531
  --expires <duration> Expiry duration: "24h", "7d", "30d" (default: 30d)
521
532
  --wallet <name> Wallet name (or "walletconnect"/"wc")
522
533
 
@@ -581,6 +592,18 @@ EXAMPLES:
581
592
  return;
582
593
  }
583
594
 
595
+ // Same bounds as update / bridge: whole-integer bps in 0–10000.
596
+ let slippageBps;
597
+ if (slippageBpsRaw != null) {
598
+ try {
599
+ slippageBps = parseSlippageBps(slippageBpsRaw);
600
+ } catch (err) {
601
+ log(err.message);
602
+ exit(1);
603
+ return;
604
+ }
605
+ }
606
+
584
607
  let expiresAt;
585
608
  try {
586
609
  expiresAt = parseExpiry(expiresStr);
@@ -820,7 +843,7 @@ Usage: nansen trade limit-order update --order <orderId> [--trigger-price <usd>]
820
843
  OPTIONS:
821
844
  --order <id> Order ID to update
822
845
  --trigger-price <usd> New trigger price in USD
823
- --slippage-bps <bps> Slippage in basis points (100 = 1%)
846
+ --slippage-bps <bps> Whole integer bps, 0-10000 (100 = 1%)
824
847
  --wallet <name> Wallet name (or "walletconnect"/"wc")
825
848
 
826
849
  NOTE: Only provided fields are updated. Auto slippage can only be set at creation time
@@ -850,13 +873,13 @@ EXAMPLES:
850
873
  updateBody.triggerPriceUsd = price;
851
874
  }
852
875
  if (slippageBps != null) {
853
- const bps = Number(slippageBps);
854
- if (isNaN(bps) || bps < 0 || bps > 10000) {
855
- log('Error: --slippage-bps must be between 0 and 10000 basis points.');
876
+ try {
877
+ updateBody.slippageBps = parseSlippageBps(slippageBps);
878
+ } catch (err) {
879
+ log(err.message);
856
880
  exit(1);
857
881
  return;
858
882
  }
859
- updateBody.slippageBps = bps;
860
883
  }
861
884
 
862
885
  try {
@@ -118,12 +118,12 @@ export function creditWarning(meta) {
118
118
  const { used, remaining, cost } = credits;
119
119
  if (remaining === null) return null;
120
120
  if (remaining === 0) {
121
- return '⚠️ Out of API credits. Top up at https://app.nansen.ai/api';
121
+ return '⚠️ Out of API credits. Top up at https://app.nansen.ai/api?tab=api';
122
122
  }
123
123
  // The cost header is the authoritative charge; used is the fallback.
124
124
  const charged = cost ?? used;
125
125
  if (charged !== null && charged > 0 && remaining < charged) {
126
- return `⚠️ ${remaining} API credit${remaining === 1 ? '' : 's'} left — less than this call cost (${charged}). Top up at https://app.nansen.ai/api`;
126
+ return `⚠️ ${remaining} API credit${remaining === 1 ? '' : 's'} left — less than this call cost (${charged}). Top up at https://app.nansen.ai/api?tab=api`;
127
127
  }
128
128
  return null;
129
129
  }
package/src/rpc-urls.js CHANGED
@@ -11,6 +11,23 @@
11
11
  * NANSEN_BSC_RPC Custom BNB Smart Chain RPC
12
12
  * NANSEN_XLAYER_RPC Custom X Layer RPC
13
13
  * NANSEN_SOLANA_RPC Custom Solana RPC
14
+ * NANSEN_BASE_SIM_RPC Custom Base simulation RPC (see SIMULATION_RPCS below)
15
+ *
16
+ * Simulation RPCs (SIMULATION_RPCS) are a SEPARATE registry from the cheap
17
+ * defaults above. Swap-outcome verification (src/swap-simulation.js) needs an
18
+ * endpoint that supports state-changing simulation with asset-transfer tracing
19
+ * (`eth_simulateV1` / `debug_traceCall`), which the free public defaults in
20
+ * CHAIN_RPCS deliberately DISABLE. Keeping the two registries apart means only
21
+ * the (pricey) simulation calls hit the trace-capable endpoint; ordinary reads
22
+ * (nonce, balance, allowance, eth_call revert check) stay on the cheap default.
23
+ *
24
+ * The shipped simulation endpoint is a Nansen-hosted service authenticated with
25
+ * the user's existing Nansen API key (no secret in this public package): the
26
+ * trace-capable upstream is reached server-side, so the baked default carries no
27
+ * credential. With no NANSEN_BASE_SIM_RPC override, swap-outcome verification
28
+ * uses this default; if the service is ever unreachable it degrades with a
29
+ * warning rather than blocking the trade. To use your own endpoint (or for local
30
+ * dev/e2e), point NANSEN_BASE_SIM_RPC at any trace-capable RPC in a gitignored .env.
14
31
  *
15
32
  * Backward-compat aliases (deprecated — prefer the forms above):
16
33
  * NANSEN_RPC_BASE Old name for NANSEN_BASE_RPC; trading.js previously read this
@@ -40,3 +57,53 @@ export const CHAIN_RPCS = {
40
57
  polygon: process.env.NANSEN_POLYGON_RPC || DEFAULT_POLYGON_RPC,
41
58
  bnb: process.env.NANSEN_BNB_RPC || DEFAULT_BNB_RPC,
42
59
  };
60
+
61
+ // Zero-config default for the shipped Nansen-hosted simulation endpoint. It
62
+ // authenticates with the user's existing Nansen API key (attached automatically
63
+ // by swap-simulation.js), and the trace-capable upstream is reached server-side —
64
+ // so this URL carries no secret and is safe to bake into a public package. Never
65
+ // embed an RPC URL that carries an inline token here; any embedded secret would
66
+ // leak on publish.
67
+ const DEFAULT_BASE_SIM_RPC = 'https://api.nansen.ai/api/v1/trade/simulate-swap';
68
+
69
+ // Separate registry for swap-outcome simulation (src/swap-simulation.js). These
70
+ // endpoints must support state-changing simulation with asset-transfer tracing
71
+ // (`eth_simulateV1` / `debug_traceCall`), which the CHAIN_RPCS public defaults
72
+ // disable. Only outcome verification reads this registry; every other RPC call
73
+ // stays on the cheap CHAIN_RPCS default. A null entry (no baked default and no
74
+ // override) signals "no sim-capable endpoint" to the caller, which degrades.
75
+ //
76
+ // Intentionally a mutable export: unit tests override an entry in-place (e.g.
77
+ // `SIMULATION_RPCS.base = ...`) to point at a mock or to null out the endpoint,
78
+ // restoring it in afterEach. Runtime code only ever reads it.
79
+ export const SIMULATION_RPCS = {
80
+ base: process.env.NANSEN_BASE_SIM_RPC || DEFAULT_BASE_SIM_RPC,
81
+ };
82
+
83
+ // Nansen hosts the API key may be forwarded to. Kept to an explicit allowlist
84
+ // (not a `*.nansen.ai` wildcard): the key only ever authenticates the sim proxy
85
+ // on api.nansen.ai, and a wildcard would forward it to any subdomain that
86
+ // resolves — including a misconfigured or compromised one. Add new sim hosts
87
+ // here deliberately if one is ever introduced.
88
+ const NANSEN_HOSTED_SIM_HOSTS = new Set(['api.nansen.ai']);
89
+
90
+ /**
91
+ * Whether a simulation URL is a Nansen-hosted endpoint that may receive the
92
+ * user's Nansen API key. The key authenticates the shipped default proxy
93
+ * (DEFAULT_BASE_SIM_RPC); a NANSEN_BASE_SIM_RPC override can point at ANY host
94
+ * (dev node, third-party trace RPC), and forwarding the credential there would
95
+ * leak it. So the key is attached ONLY when this returns true — every other
96
+ * endpoint is called anonymously.
97
+ *
98
+ * Trust is: https + hostname is one of NANSEN_HOSTED_SIM_HOSTS. Anything else
99
+ * (http, other host, unparseable) is untrusted and gets no key.
100
+ */
101
+ export function isNansenHostedUrl(url) {
102
+ try {
103
+ const u = new URL(url);
104
+ if (u.protocol !== 'https:') return false;
105
+ return NANSEN_HOSTED_SIM_HOSTS.has(u.hostname.toLowerCase());
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
package/src/schema.json CHANGED
@@ -1620,7 +1620,15 @@
1620
1620
  },
1621
1621
  "no-simulate": {
1622
1622
  "type": "boolean",
1623
- "description": "Skip the pre-broadcast simulation."
1623
+ "description": "Skip the pre-broadcast simulation (the eth_call revert check)."
1624
+ },
1625
+ "no-verify-outcome": {
1626
+ "type": "boolean",
1627
+ "description": "Skip EVM swap-outcome verification. That check simulates the swap and confirms the wallet's balance changes match the quote (input spent within your max, expected output received, no other token moved) before broadcasting; it needs a simulation-capable endpoint (NANSEN_BASE_SIM_RPC) and degrades with a warning when none is available. No effect on Solana."
1628
+ },
1629
+ "no-revoke-excessive-allowance": {
1630
+ "type": "boolean",
1631
+ "description": "Skip revoking an existing on-chain ERC-20 allowance before re-approving when it exceeds 10x this trade's scoped amount. By default, an oversized or legacy allowance is revoked to zero and a fresh trade-scoped allowance is granted. WalletConnect users will see separate wallet prompts for the revoke and re-approval."
1624
1632
  }
1625
1633
  }
1626
1634
  },
@@ -1686,7 +1694,7 @@
1686
1694
  },
1687
1695
  "slippage-bps": {
1688
1696
  "type": "number",
1689
- "description": "Slippage tolerance in basis points (e.g. 50 = 0.5%)"
1697
+ "description": "Slippage as a whole integer in basis points, 0-10000 (50 = 0.5%), omit for auto"
1690
1698
  },
1691
1699
  "expires": {
1692
1700
  "type": "string",
@@ -1775,7 +1783,7 @@
1775
1783
  },
1776
1784
  "slippage-bps": {
1777
1785
  "type": "number",
1778
- "description": "New slippage in basis points (0-10000)"
1786
+ "description": "New slippage as a whole integer in basis points (0-10000)"
1779
1787
  },
1780
1788
  "wallet": {
1781
1789
  "type": "string",
@@ -1968,6 +1976,15 @@
1968
1976
  "type": "string",
1969
1977
  "description": "Comma-separated list of fields to include in output"
1970
1978
  },
1979
+ "limit": {
1980
+ "type": "number",
1981
+ "description": "Maximum results per page for list-returning research commands; maps to pagination.per_page. General endpoints default to 10 (max 1000), while profiler address endpoints default to 20 (max 100). Supported by smart-money, profiler, token, perp, points, prediction-market, and supported research historical-* commands. Commands that declare their own limit option (search, token top-tokens, trade limit-order list) use those command-specific semantics instead; token ohlcv, profiler perp-positions, and historical-token-flow-summary do not support pagination. profiler labels defaults to 100 when omitted."
1982
+ },
1983
+ "page": {
1984
+ "type": "number",
1985
+ "default": 1,
1986
+ "description": "1-based page number for list-returning research commands; maps to pagination.page. Supported by smart-money, profiler, token, perp, points, prediction-market, and supported research historical-* commands. Trade, wallet, and operational commands ignore it; token ohlcv, profiler perp-positions, and historical-token-flow-summary do not support pagination. profiler labels defaults to page 1 when omitted."
1987
+ },
1971
1988
  "no-retry": {
1972
1989
  "type": "boolean",
1973
1990
  "description": "Disable automatic retry on rate limits/errors"