nansen-cli 1.9.3 → 1.10.1

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/src/trading.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Nansen CLI - Trading Commands
3
3
  * Quote and execute DEX swaps via the Nansen Trading API.
4
- * Supports Solana and EVM chains (Ethereum, Base, BSC).
4
+ * Supports Solana and Base.
5
5
  * Zero external dependencies — uses Node.js built-in crypto only.
6
6
  */
7
7
 
@@ -19,21 +19,17 @@ const TRADING_API_URL = process.env.NANSEN_TRADING_API_URL || 'https://trading-a
19
19
 
20
20
  const CHAIN_MAP = {
21
21
  solana: { index: '501', type: 'solana', chainId: 501, name: 'Solana', explorer: 'https://solscan.io/tx/' },
22
- ethereum: { index: '1', type: 'evm', chainId: 1, name: 'Ethereum', explorer: 'https://etherscan.io/tx/' },
23
22
  base: { index: '8453', type: 'evm', chainId: 8453, name: 'Base', explorer: 'https://basescan.org/tx/' },
24
- bsc: { index: '56', type: 'evm', chainId: 56, name: 'BSC', explorer: 'https://bscscan.com/tx/' },
25
23
  };
26
24
 
27
25
  // Extend when adding new EVM chains (e.g. arbitrum WETH, polygon WMATIC)
28
26
  const WRAPPED_NATIVE_TOKENS = {
29
- ethereum: { address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', symbol: 'WETH', nativeSymbol: 'ETH' },
30
27
  base: { address: '0x4200000000000000000000000000000000000006', symbol: 'WETH', nativeSymbol: 'ETH' },
31
- bsc: { address: '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c', symbol: 'WBNB', nativeSymbol: 'BNB' },
32
28
  };
33
29
 
34
30
  // Common token symbol → address lookup per chain.
35
31
  // Native sentinels: Solana uses native mint, EVM uses 0xeee…eee.
36
- // Wrapped-native addresses (WETH, WBNB) are derived from WRAPPED_NATIVE_TOKENS
32
+ // Wrapped-native addresses (WETH) are derived from WRAPPED_NATIVE_TOKENS
37
33
  // to avoid duplication — keep that map as the single source of truth.
38
34
  const EVM_NATIVE = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
39
35
  const TOKEN_SYMBOLS = {
@@ -43,12 +39,6 @@ const TOKEN_SYMBOLS = {
43
39
  USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
44
40
  USDT: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
45
41
  },
46
- ethereum: {
47
- ETH: EVM_NATIVE,
48
- WETH: WRAPPED_NATIVE_TOKENS.ethereum.address,
49
- USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
50
- USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7',
51
- },
52
42
  base: {
53
43
  ETH: EVM_NATIVE,
54
44
  WETH: WRAPPED_NATIVE_TOKENS.base.address,
@@ -57,12 +47,6 @@ const TOKEN_SYMBOLS = {
57
47
  // (like Circle did with USDC), this address will need updating.
58
48
  USDT: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',
59
49
  },
60
- bsc: {
61
- BNB: EVM_NATIVE,
62
- WBNB: WRAPPED_NATIVE_TOKENS.bsc.address,
63
- USDC: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d',
64
- USDT: '0x55d398326f99059ff775485246999027b3197955',
65
- },
66
50
  };
67
51
 
68
52
  /**
@@ -80,9 +64,7 @@ export function resolveTokenAddress(symbolOrAddress, chainName) {
80
64
 
81
65
  // Default public RPC endpoints (used for nonce fetching)
82
66
  const EVM_RPC_URLS = {
83
- ethereum: process.env.NANSEN_RPC_ETHEREUM || 'https://eth.llamarpc.com',
84
67
  base: process.env.NANSEN_RPC_BASE || 'https://mainnet.base.org',
85
- bsc: process.env.NANSEN_RPC_BSC || 'https://bsc-dataseed.binance.org',
86
68
  };
87
69
 
88
70
  function getQuotesDir() {
@@ -321,7 +303,7 @@ export function signSolanaTransaction(transactionBase64, privateKeyHex) {
321
303
  *
322
304
  * @param {object} txData - Transaction fields from quote.transaction { to, data, value, gas, gasPrice }
323
305
  * @param {string} privateKeyHex - 64-char hex (32-byte secp256k1 private key)
324
- * @param {string} chain - Chain name (ethereum, base, bsc)
306
+ * @param {string} chain - Chain name
325
307
  * @param {number} nonce - Account nonce
326
308
  * @returns {string} 0x-prefixed signed transaction hex
327
309
  */
@@ -794,12 +776,17 @@ export function buildTradingCommands(deps = {}) {
794
776
  errorOutput(`
795
777
  Usage: nansen trade quote --chain <chain> --from <token> --to <token> --amount <baseUnits>
796
778
 
779
+ PREREQUISITE:
780
+ A wallet must be configured before using this command (the trading API builds
781
+ a transaction specific to your sender address).
782
+ Set one up with: nansen wallet create
783
+
797
784
  OPTIONS:
798
- --chain <chain> Chain: solana, ethereum, base, bsc
785
+ --chain <chain> Chain: solana, base
799
786
  --from <symbol|address> Input token (symbol like SOL, USDC or address)
800
787
  --to <symbol|address> Output token (symbol like USDC, ETH or address)
801
788
  --amount <units> Amount in BASE UNITS (e.g. lamports, wei)
802
- --wallet <name> Wallet name (default: default wallet)
789
+ --wallet <name> Wallet name (default: default wallet). Use "walletconnect" or "wc" for WalletConnect (EVM only).
803
790
  --slippage <pct> Slippage as decimal (e.g. 0.03 for 3%). Default: 0.03
804
791
  --auto-slippage Enable auto slippage calculation
805
792
  --max-auto-slippage <pct> Max auto slippage when auto-slippage enabled
@@ -844,11 +831,15 @@ EXAMPLES:
844
831
  const wallet = showWallet(walletName);
845
832
  walletAddress = chainType === 'solana' ? wallet.solana : wallet.evm;
846
833
  } else {
847
- walletAddress = getDefaultAddress(chainType);
834
+ try {
835
+ walletAddress = getDefaultAddress(chainType);
836
+ } catch {
837
+ // No wallet configured — fall through to the check below
838
+ }
848
839
  }
849
840
 
850
841
  if (!walletAddress) {
851
- errorOutput('No wallet found. Create one with: nansen wallet create');
842
+ errorOutput('No wallet found. A wallet address is required for quotes because the trading API builds a transaction specific to the sender.\nCreate one with: nansen wallet create');
852
843
  exit(1);
853
844
  return;
854
845
  }
package/src/transfer.js CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  import crypto from 'crypto';
8
8
  import { base58Encode, exportWallet, getWalletConfig, verifyPassword } from './wallet.js';
9
- import { keccak256, signSecp256k1, rlpEncode, bigIntToMinBuf } from './crypto.js';
9
+ import { keccak256, signSecp256k1, rlpEncode } from './crypto.js';
10
10
  import { getWalletConnectAddress, sendTransactionViaWalletConnect } from './walletconnect-trading.js';
11
11
  import { EVM_CHAIN_IDS } from './chain-ids.js';
12
12
 
@@ -217,7 +217,6 @@ async function buildEvmTransaction({ to, amount, token, privateKey, chain, max =
217
217
  const safeReserve = l2GasCost * 3n;
218
218
  if (ethBalance <= safeReserve) throw new Error(`Insufficient balance: ${ethBalance} wei (need > ${safeReserve} for gas + L1 fees)`);
219
219
  txValue = ethBalance - safeReserve;
220
- amount = txValue;
221
220
  stderr(` Max send: ${formatAmount(txValue, 18)} ETH (reserved ${formatAmount(safeReserve, 18)} for gas)`);
222
221
  } else {
223
222
  txValue = amount;
@@ -375,7 +374,7 @@ async function buildSolanaTransaction({ to, amount, amountStr, token, privateKey
375
374
  }
376
375
  } catch (e) {
377
376
  if (e.message.includes('Insufficient')) throw e;
378
- throw new Error(`Source token account not found. Do you hold this token?`);
377
+ throw new Error(`Source token account not found. Do you hold this token?`, { cause: e });
379
378
  }
380
379
 
381
380
  // TransferChecked instruction data: [12, amount u64 LE, decimals u8]
@@ -568,7 +567,7 @@ async function validateErc20Token(rpcUrl, tokenAddress) {
568
567
  return decimals;
569
568
  } catch (e) {
570
569
  if (e.message.includes('not a valid')) throw e;
571
- throw new Error(`Contract ${tokenAddress} does not implement ERC-20 decimals() — may not be a valid token`);
570
+ throw new Error(`Contract ${tokenAddress} does not implement ERC-20 decimals() — may not be a valid token`, { cause: e });
572
571
  }
573
572
  }
574
573
 
@@ -626,7 +625,7 @@ export async function sendTokens({ to, amount, chain, token = null, wallet = nul
626
625
  } else if (max && token) {
627
626
  // Max SPL: full token balance
628
627
  const rpcUrl = CHAIN_RPCS.solana;
629
- const { tokenProgram, decimals } = await getTokenInfo(rpcUrl, token);
628
+ const { tokenProgram, decimals: _decimals } = await getTokenInfo(rpcUrl, token);
630
629
  const sourceATA = deriveATA(walletData.solana.address, token, tokenProgram);
631
630
  const sourceAtaAddr = base58Encode(sourceATA);
632
631
  const ataInfo = await rpcCall(rpcUrl, 'getTokenAccountBalance', [sourceAtaAddr]);
@@ -721,7 +720,7 @@ async function sendTokensViaWalletConnect({ to, amount, chain, token, max, dryRu
721
720
  const wcAddress = await getWalletConnectAddress();
722
721
  if (!wcAddress) throw new Error('No WalletConnect session active. Run: walletconnect connect');
723
722
 
724
- let txTo, txValue, txData, decimals = 18;
723
+ let txTo, txValue, txData;
725
724
 
726
725
  if (token) {
727
726
  // Validate ERC-20 contract
@@ -730,7 +729,7 @@ async function sendTokensViaWalletConnect({ to, amount, chain, token, max, dryRu
730
729
  throw new Error(`Address ${token} is not a contract — not a valid ERC-20 token`);
731
730
  }
732
731
  const decResult = await rpcCall(rpcUrl, 'eth_call', [{ to: token, data: '0x313ce567' }, 'latest']);
733
- decimals = parseInt(decResult, 16);
732
+ const decimals = parseInt(decResult, 16);
734
733
 
735
734
  if (max) {
736
735
  // Max ERC-20: full token balance
@@ -809,14 +808,11 @@ async function sendTokensViaWalletConnect({ to, amount, chain, token, max, dryRu
809
808
  chainId,
810
809
  });
811
810
 
812
- let txHash;
813
- if (wcResult.txHash) {
814
- txHash = wcResult.txHash;
815
- } else if (wcResult.signedTransaction) {
816
- txHash = await broadcastTransaction(wcResult.signedTransaction, chain);
817
- } else {
811
+ const txHash = await (async () => {
812
+ if (wcResult.txHash) return wcResult.txHash;
813
+ if (wcResult.signedTransaction) return broadcastTransaction(wcResult.signedTransaction, chain);
818
814
  throw new Error('No transaction hash or signed transaction returned from WalletConnect');
819
- }
815
+ })();
820
816
 
821
817
  // Wait for confirmation
822
818
  const confirmation = await waitForEvmConfirmation(rpcUrl, txHash);
package/src/wallet.js CHANGED
@@ -26,7 +26,7 @@ const SCRYPT_P = 1;
26
26
  const SCRYPT_KEYLEN = 32;
27
27
  const SALT_LEN = 16;
28
28
  const IV_LEN = 12;
29
- const AUTH_TAG_LEN = 16;
29
+ const _AUTH_TAG_LEN = 16;
30
30
 
31
31
  import { keccak256 } from './crypto.js';
32
32
 
@@ -481,7 +481,7 @@ export function getDefaultAddress(chainType = 'evm') {
481
481
  * Build wallet command handlers for integration into CLI.
482
482
  */
483
483
  export function buildWalletCommands(deps = {}) {
484
- const { log = console.log, promptFn, exit = process.exit } = deps;
484
+ const { log = console.log, promptFn: _promptFn, exit = process.exit } = deps;
485
485
 
486
486
  return {
487
487
  'wallet': async (args, apiInstance, flags, options) => {
@@ -11,7 +11,7 @@ import { execFile } from 'child_process';
11
11
  */
12
12
  export function wcExec(cmd, args, timeoutMs = 10000) {
13
13
  return new Promise((resolve, reject) => {
14
- execFile(cmd, args, { timeout: timeoutMs }, (err, stdout, stderr) => {
14
+ execFile(cmd, args, { timeout: timeoutMs }, (err, stdout, _stderr) => {
15
15
  if (err) {
16
16
  reject(new Error(err.message));
17
17
  return;
package/src/x402-svm.js CHANGED
@@ -30,11 +30,11 @@ export function base58Encode(buf) {
30
30
  // ============= Constants =============
31
31
 
32
32
  const TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';
33
- const TOKEN_2022_PROGRAM = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb';
33
+ const _TOKEN_2022_PROGRAM = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb';
34
34
  const COMPUTE_BUDGET_PROGRAM = 'ComputeBudget111111111111111111111111111111';
35
35
  const MEMO_PROGRAM = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr';
36
36
  const ATA_PROGRAM = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';
37
- const SYSTEM_PROGRAM = '11111111111111111111111111111111';
37
+ const _SYSTEM_PROGRAM = '11111111111111111111111111111111';
38
38
 
39
39
  const DEFAULT_COMPUTE_UNIT_LIMIT = 20000;
40
40
  const DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;
@@ -186,7 +186,7 @@ function modInverse(a, mod) {
186
186
  * Build a Solana MessageV0 from accounts and instructions.
187
187
  * Simplified builder for x402 payment transactions.
188
188
  */
189
- function buildMessageV0({ feePayer, instructions, recentBlockhash, accounts }) {
189
+ function buildMessageV0({ feePayer, instructions, recentBlockhash, accounts: _accounts }) {
190
190
  // All unique accounts in order: feePayer first, then signers, then rest
191
191
  const accountMap = new Map();
192
192
  const feePayerKey = feePayer;
package/src/x402.js CHANGED
@@ -154,7 +154,7 @@ export async function createPaymentSignature(response, url, options = {}) {
154
154
  */
155
155
  export async function checkX402Balance(network) {
156
156
  try {
157
- const { listWallets, exportWallet } = await import('./wallet.js');
157
+ const { listWallets, exportWallet: _exportWallet } = await import('./wallet.js');
158
158
  const wallets = listWallets();
159
159
  if (!wallets.defaultWallet) return null;
160
160