xflows 1.0.2 → 1.2.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.
Files changed (3) hide show
  1. package/README.md +104 -0
  2. package/dist/index.js +183 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -15,9 +15,17 @@ A command-line interface for the [Wanchain XFlows](https://docs.wanchain.org/dev
15
15
  - [RPC Endpoints](#rpc-endpoints)
16
16
  - [Commands](#commands)
17
17
  - [Wallet Management](#wallet-management)
18
+ - [`wallet create`](#wallet-create----create-a-new-wallet)
19
+ - [`wallet list`](#wallet-list----list-all-saved-wallets)
20
+ - [`wallet show`](#wallet-show----show-wallet-details)
21
+ - [`wallet balance`](#wallet-balance----check-native-token-balance)
22
+ - [`wallet token-balance`](#wallet-token-balance----check-erc20-token-balance)
23
+ - [`wallet delete`](#wallet-delete----delete-a-wallet)
18
24
  - [Query Commands](#query-commands)
19
25
  - [Quote](#quote)
20
26
  - [Send Transaction](#send-transaction)
27
+ - [Transfer (Native Token)](#transfer-native-token)
28
+ - [Transfer Token (ERC20)](#transfer-token-erc20)
21
29
  - [Transaction Status](#transaction-status)
22
30
  - [RPC List](#rpc-list)
23
31
  - [Complete Workflow Example](#complete-workflow-example)
@@ -333,6 +341,32 @@ xflows wallet balance --name alice --chain-id 1 --rpc https://my-rpc.example.com
333
341
  | `--password <pw>` | No | Password for encrypted wallets |
334
342
  | `--rpc <url>` | No | Override default RPC endpoint |
335
343
 
344
+ #### `wallet token-balance` -- Check ERC20 token balance
345
+
346
+ ```bash
347
+ # Check USDC balance on Ethereum
348
+ xflows wallet token-balance --name alice --chain-id 1 \
349
+ --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
350
+
351
+ # Check USDT balance on BSC (auto-detect decimals)
352
+ xflows wallet token-balance --name alice --chain-id 56 \
353
+ --token 0x55d398326f99059fF775485246999027B3197955
354
+
355
+ # Check with explicit decimals and custom RPC
356
+ xflows wallet token-balance --name alice --chain-id 1 \
357
+ --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
358
+ --decimals 6 --rpc https://my-rpc.example.com
359
+ ```
360
+
361
+ | Flag | Required | Description |
362
+ |------|----------|-------------|
363
+ | `--name <name>` | Yes | Wallet name |
364
+ | `--chain-id <id>` | Yes | Chain ID to query balance on |
365
+ | `--token <addr>` | Yes | ERC20 token contract address |
366
+ | `--decimals <n>` | No | Token decimals (auto-detected if omitted) |
367
+ | `--password <pw>` | No | Password for encrypted wallets |
368
+ | `--rpc <url>` | No | Override default RPC endpoint |
369
+
336
370
  #### `wallet delete` -- Delete a wallet
337
371
 
338
372
  ```bash
@@ -511,6 +545,76 @@ xflows send \
511
545
  7. Waits for on-chain confirmation
512
546
  8. Prints the transaction hash and a ready-to-use `xflows status` command for tracking
513
547
 
548
+ ### Transfer (Native Token)
549
+
550
+ Send native tokens (ETH, BNB, WAN, etc.) on the same chain. This is a simple transfer, not a cross-chain bridge operation.
551
+
552
+ ```bash
553
+ # Send 0.1 ETH on Ethereum
554
+ xflows transfer --wallet alice --chain-id 1 --to 0xRecipient --amount 0.1
555
+
556
+ # Send 1.5 BNB on BSC with encrypted wallet
557
+ xflows transfer --wallet alice --password mysecret --chain-id 56 --to 0xRecipient --amount 1.5
558
+
559
+ # Dry run (preview without sending)
560
+ xflows transfer --wallet alice --chain-id 1 --to 0xRecipient --amount 0.1 --dry-run
561
+ ```
562
+
563
+ | Flag | Required | Description |
564
+ |------|----------|-------------|
565
+ | `--wallet <name>` | Yes | Wallet name to use for signing |
566
+ | `--chain-id <id>` | Yes | Chain ID to send on |
567
+ | `--to <address>` | Yes | Recipient address |
568
+ | `--amount <amount>` | Yes | Amount to send (human-readable, e.g., `0.1`) |
569
+ | `--password <pw>` | No | Password for encrypted wallet |
570
+ | `--rpc <url>` | No | Override default RPC endpoint |
571
+ | `--gas-limit <limit>` | No | Custom gas limit |
572
+ | `--dry-run` | No | Build but do not send the transaction |
573
+
574
+ ### Transfer Token (ERC20)
575
+
576
+ Send ERC20 tokens on the same chain. Token decimals are auto-detected from the contract, or can be specified manually.
577
+
578
+ ```bash
579
+ # Send 100 USDC on Ethereum (auto-detect decimals)
580
+ xflows transfer-token --wallet alice --chain-id 1 \
581
+ --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
582
+ --to 0xRecipient --amount 100
583
+
584
+ # Send with explicit decimals
585
+ xflows transfer-token --wallet alice --chain-id 1 \
586
+ --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
587
+ --to 0xRecipient --amount 100 --decimals 6
588
+
589
+ # Send 50 USDT on BSC with encrypted wallet
590
+ xflows transfer-token --wallet alice --password mysecret --chain-id 56 \
591
+ --token 0x55d398326f99059fF775485246999027B3197955 \
592
+ --to 0xRecipient --amount 50
593
+
594
+ # Dry run (preview without sending)
595
+ xflows transfer-token --wallet alice --chain-id 1 \
596
+ --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
597
+ --to 0xRecipient --amount 100 --dry-run
598
+ ```
599
+
600
+ | Flag | Required | Description |
601
+ |------|----------|-------------|
602
+ | `--wallet <name>` | Yes | Wallet name to use for signing |
603
+ | `--chain-id <id>` | Yes | Chain ID to send on |
604
+ | `--token <address>` | Yes | ERC20 token contract address |
605
+ | `--to <address>` | Yes | Recipient address |
606
+ | `--amount <amount>` | Yes | Amount to send (human-readable, e.g., `100`) |
607
+ | `--decimals <n>` | No | Token decimals (auto-detected if omitted) |
608
+ | `--password <pw>` | No | Password for encrypted wallet |
609
+ | `--rpc <url>` | No | Override default RPC endpoint |
610
+ | `--gas-limit <limit>` | No | Custom gas limit |
611
+ | `--dry-run` | No | Build but do not send the transaction |
612
+
613
+ **Features:**
614
+ - Auto-detects token decimals and symbol from the contract
615
+ - Checks token balance before sending to provide a clear error message
616
+ - Supports Wanchain gas price enforcement
617
+
514
618
  ### Transaction Status
515
619
 
516
620
  Check the current state of a cross-chain transaction.
package/dist/index.js CHANGED
@@ -3955,6 +3955,9 @@ function parseUnits(value, unit) {
3955
3955
  }
3956
3956
  return FixedNumber.fromString(value, { decimals, width: 512 }).value;
3957
3957
  }
3958
+ function parseEther(ether) {
3959
+ return parseUnits(ether, 18);
3960
+ }
3958
3961
  // node_modules/ethers/lib.esm/utils/uuid.js
3959
3962
  function uuidV4(randomBytes) {
3960
3963
  const bytes = getBytes(randomBytes, "randomBytes");
@@ -18657,7 +18660,7 @@ import * as readline from "readline";
18657
18660
  // package.json
18658
18661
  var package_default = {
18659
18662
  name: "xflows",
18660
- version: "1.0.2",
18663
+ version: "1.2.0",
18661
18664
  description: "CLI tool for Wanchain XFlows cross-chain bridge - wallet management, quote queries, and cross-chain transactions",
18662
18665
  type: "module",
18663
18666
  bin: {
@@ -18826,14 +18829,18 @@ function printJson(data) {
18826
18829
  }
18827
18830
  var ERC20_ABI = [
18828
18831
  "function approve(address spender, uint256 amount) returns (bool)",
18829
- "function allowance(address owner, address spender) view returns (uint256)"
18832
+ "function allowance(address owner, address spender) view returns (uint256)",
18833
+ "function transfer(address to, uint256 amount) returns (bool)",
18834
+ "function balanceOf(address owner) view returns (uint256)",
18835
+ "function decimals() view returns (uint8)",
18836
+ "function symbol() view returns (string)"
18830
18837
  ];
18831
18838
  var program2 = new Command;
18832
18839
  program2.name("xflows").version(VERSION).description(`XFlows Cross-Chain Bridge CLI Tool
18833
18840
 
18834
18841
  ` + `A command-line interface for Wanchain XFlows cross-chain bridge.
18835
18842
  ` + `Supports wallet management, quote queries, cross-chain transactions,
18836
- ` + `and all XFlows API query endpoints.
18843
+ ` + `same-chain native/ERC20 transfers, and all XFlows API query endpoints.
18837
18844
 
18838
18845
  ` + `Wallet files are stored in ~/.xflows/wallets/
18839
18846
 
@@ -18842,6 +18849,8 @@ program2.name("xflows").version(VERSION).description(`XFlows Cross-Chain Bridge
18842
18849
  ` + ` xflows wallet create --name secureWallet --encrypt
18843
18850
  ` + ` xflows chains
18844
18851
  ` + ` xflows tokens --chain-id 1
18852
+ ` + ` xflows transfer --wallet myWallet --chain-id 1 --to 0x... --amount 0.1
18853
+ ` + ` xflows transfer-token --wallet myWallet --chain-id 1 --token 0x... --to 0x... --amount 100
18845
18854
  ` + ` xflows quote --from-chain 1 --to-chain 56 --from-token 0x0...0 --to-token 0x0...0 --from-address 0x... --to-address 0x... --amount 1.0
18846
18855
  ` + ` xflows send --wallet myWallet --from-chain 1 --to-chain 56 --from-token 0x0...0 --to-token 0x0...0 --to-address 0x... --amount 1.0
18847
18856
  ` + " xflows status --hash 0x... --from-chain 1 --to-chain 56 --from-token 0x0...0 --to-token 0x0...0 --from-address 0x... --to-address 0x... --amount 1.0");
@@ -18949,6 +18958,42 @@ walletCmd.command("balance").description(`Check native token balance on a specif
18949
18958
  process.exit(1);
18950
18959
  }
18951
18960
  });
18961
+ walletCmd.command("token-balance").description(`Check ERC20 token balance on a specific chain
18962
+
18963
+ ` + `Examples:
18964
+ ` + ` # Check USDC balance on Ethereum
18965
+ ` + " xflows wallet token-balance --name alice --chain-id 1 \\\n" + ` --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
18966
+
18967
+ ` + ` # Check USDT balance on BSC with explicit decimals
18968
+ ` + " xflows wallet token-balance --name alice --chain-id 56 \\\n" + " --token 0x55d398326f99059fF775485246999027B3197955 --decimals 18").requiredOption("--name <name>", "Wallet name").requiredOption("--chain-id <chainId>", "Chain ID to check balance on").requiredOption("--token <address>", "ERC20 token contract address").option("--decimals <decimals>", "Token decimals (auto-detected if omitted)").option("--password <password>", "Password to decrypt encrypted wallet").option("--rpc <url>", "Custom RPC URL (overrides default)").action(async (opts) => {
18969
+ try {
18970
+ const wallet = loadWallet(opts.name, opts.password);
18971
+ const provider = opts.rpc ? new JsonRpcProvider(opts.rpc) : getProvider2(opts.chainId);
18972
+ const tokenContract = new Contract(opts.token, ERC20_ABI, provider);
18973
+ let decimals;
18974
+ if (opts.decimals !== undefined) {
18975
+ decimals = Number(opts.decimals);
18976
+ } else {
18977
+ try {
18978
+ decimals = Number(await tokenContract.decimals());
18979
+ } catch {
18980
+ throw new Error("Could not auto-detect token decimals. Please provide --decimals manually.");
18981
+ }
18982
+ }
18983
+ let symbol = "TOKEN";
18984
+ try {
18985
+ symbol = await tokenContract.symbol();
18986
+ } catch {}
18987
+ const balance = await tokenContract.balanceOf(wallet.address);
18988
+ console.log(`Address: ${wallet.address}`);
18989
+ console.log(`Chain: ${opts.chainId}`);
18990
+ console.log(`Token: ${opts.token} (${symbol})`);
18991
+ console.log(`Balance: ${formatUnits(balance, decimals)}`);
18992
+ } catch (e) {
18993
+ console.error(`Error: ${e.message}`);
18994
+ process.exit(1);
18995
+ }
18996
+ });
18952
18997
  walletCmd.command("delete").description("Delete a saved wallet").requiredOption("--name <name>", "Wallet name to delete").option("--force", "Skip confirmation", false).action(async (opts) => {
18953
18998
  const walletDir = getWalletDir();
18954
18999
  const filePath = path.join(walletDir, `${opts.name}.json`);
@@ -19181,6 +19226,141 @@ You can track the cross-chain status with:`);
19181
19226
  process.exit(1);
19182
19227
  }
19183
19228
  });
19229
+ program2.command("transfer").description(`Send native tokens (ETH/BNB/WAN/etc.) on the same chain
19230
+
19231
+ ` + `This is a simple same-chain transfer, NOT a cross-chain bridge operation.
19232
+
19233
+ ` + `Examples:
19234
+ ` + ` # Send 0.1 ETH on Ethereum
19235
+ ` + ` xflows transfer --wallet alice --chain-id 1 --to 0xRecipient --amount 0.1
19236
+
19237
+ ` + ` # Send 1.5 BNB on BSC with encrypted wallet
19238
+ ` + " xflows transfer --wallet alice --password mysecret --chain-id 56 --to 0xRecipient --amount 1.5").requiredOption("--wallet <name>", "Wallet name to use for signing").requiredOption("--chain-id <chainId>", "Chain ID to send on").requiredOption("--to <address>", "Recipient address").requiredOption("--amount <amount>", "Amount to send (human-readable, e.g., 0.1)").option("--password <password>", "Password to decrypt encrypted wallet").option("--rpc <url>", "Custom RPC URL (overrides default)").option("--gas-limit <limit>", "Custom gas limit").option("--dry-run", "Only build the transaction, don't send it", false).action(async (opts) => {
19239
+ try {
19240
+ const wallet = loadWallet(opts.wallet, opts.password);
19241
+ const provider = opts.rpc ? new JsonRpcProvider(opts.rpc) : getProvider2(opts.chainId);
19242
+ const signer = wallet.connect(provider);
19243
+ const txRequest = {
19244
+ to: opts.to,
19245
+ value: parseEther(opts.amount)
19246
+ };
19247
+ if (opts.gasLimit) {
19248
+ txRequest.gasLimit = BigInt(opts.gasLimit);
19249
+ }
19250
+ const isWanchain = opts.chainId === "888";
19251
+ if (isWanchain) {
19252
+ const feeData = await provider.getFeeData();
19253
+ const minBaseFee = parseUnits("1", "gwei");
19254
+ if (feeData.gasPrice && feeData.gasPrice < minBaseFee) {
19255
+ txRequest.gasPrice = minBaseFee;
19256
+ console.log("Wanchain: enforcing minimum gasPrice of 1 gwei");
19257
+ } else if (feeData.maxFeePerGas) {
19258
+ const maxFee = feeData.maxFeePerGas < minBaseFee ? minBaseFee : feeData.maxFeePerGas;
19259
+ txRequest.gasPrice = maxFee;
19260
+ console.log(`Wanchain: using gasPrice ${formatUnits(maxFee, "gwei")} gwei`);
19261
+ }
19262
+ }
19263
+ if (opts.dryRun) {
19264
+ console.log("[Dry Run] Transaction details:");
19265
+ printJson({
19266
+ from: wallet.address,
19267
+ to: opts.to,
19268
+ value: txRequest.value.toString(),
19269
+ chainId: opts.chainId
19270
+ });
19271
+ return;
19272
+ }
19273
+ console.log(`Sending ${opts.amount} native token to ${opts.to} on chain ${opts.chainId}...`);
19274
+ const sentTx = await signer.sendTransaction(txRequest);
19275
+ console.log(`Transaction hash: ${sentTx.hash}`);
19276
+ console.log("Waiting for confirmation...");
19277
+ const receipt = await sentTx.wait();
19278
+ console.log(`Transaction confirmed in block ${receipt?.blockNumber}`);
19279
+ console.log(`Gas used: ${receipt?.gasUsed.toString()}`);
19280
+ } catch (e) {
19281
+ console.error(`Error: ${e.message}`);
19282
+ process.exit(1);
19283
+ }
19284
+ });
19285
+ program2.command("transfer-token").description(`Send ERC20 tokens on the same chain
19286
+
19287
+ ` + `This is a simple same-chain ERC20 transfer, NOT a cross-chain bridge operation.
19288
+
19289
+ ` + `Examples:
19290
+ ` + ` # Send 100 USDC on Ethereum (6 decimals)
19291
+ ` + " xflows transfer-token --wallet alice --chain-id 1 \\\n" + " --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \\\n" + ` --to 0xRecipient --amount 100 --decimals 6
19292
+
19293
+ ` + ` # Send 50 USDT on BSC (auto-detect decimals)
19294
+ ` + " xflows transfer-token --wallet alice --chain-id 56 \\\n" + " --token 0x55d398326f99059fF775485246999027B3197955 \\\n" + " --to 0xRecipient --amount 50").requiredOption("--wallet <name>", "Wallet name to use for signing").requiredOption("--chain-id <chainId>", "Chain ID to send on").requiredOption("--token <address>", "ERC20 token contract address").requiredOption("--to <address>", "Recipient address").requiredOption("--amount <amount>", "Amount to send (human-readable, e.g., 100)").option("--decimals <decimals>", "Token decimals (auto-detected from contract if omitted)").option("--password <password>", "Password to decrypt encrypted wallet").option("--rpc <url>", "Custom RPC URL (overrides default)").option("--gas-limit <limit>", "Custom gas limit").option("--dry-run", "Only build the transaction, don't send it", false).action(async (opts) => {
19295
+ try {
19296
+ const wallet = loadWallet(opts.wallet, opts.password);
19297
+ const provider = opts.rpc ? new JsonRpcProvider(opts.rpc) : getProvider2(opts.chainId);
19298
+ const signer = wallet.connect(provider);
19299
+ const tokenContract = new Contract(opts.token, ERC20_ABI, signer);
19300
+ let decimals;
19301
+ if (opts.decimals !== undefined) {
19302
+ decimals = Number(opts.decimals);
19303
+ } else {
19304
+ try {
19305
+ decimals = Number(await tokenContract.decimals());
19306
+ console.log(`Token decimals: ${decimals}`);
19307
+ } catch {
19308
+ throw new Error("Could not auto-detect token decimals. Please provide --decimals manually.");
19309
+ }
19310
+ }
19311
+ let symbol = "TOKEN";
19312
+ try {
19313
+ symbol = await tokenContract.symbol();
19314
+ } catch {}
19315
+ const amount = parseUnits(opts.amount, decimals);
19316
+ const balance = await tokenContract.balanceOf(wallet.address);
19317
+ if (balance < amount) {
19318
+ console.error(`Insufficient ${symbol} balance: ${formatUnits(balance, decimals)} < ${opts.amount}`);
19319
+ process.exit(1);
19320
+ }
19321
+ if (opts.dryRun) {
19322
+ console.log("[Dry Run] Transaction details:");
19323
+ printJson({
19324
+ from: wallet.address,
19325
+ to: opts.to,
19326
+ token: opts.token,
19327
+ symbol,
19328
+ amount: opts.amount,
19329
+ amountWei: amount.toString(),
19330
+ decimals,
19331
+ chainId: opts.chainId
19332
+ });
19333
+ return;
19334
+ }
19335
+ console.log(`Sending ${opts.amount} ${symbol} to ${opts.to} on chain ${opts.chainId}...`);
19336
+ const txOverrides = {};
19337
+ if (opts.gasLimit) {
19338
+ txOverrides.gasLimit = BigInt(opts.gasLimit);
19339
+ }
19340
+ const isWanchain = opts.chainId === "888";
19341
+ if (isWanchain) {
19342
+ const feeData = await provider.getFeeData();
19343
+ const minBaseFee = parseUnits("1", "gwei");
19344
+ if (feeData.gasPrice && feeData.gasPrice < minBaseFee) {
19345
+ txOverrides.gasPrice = minBaseFee;
19346
+ console.log("Wanchain: enforcing minimum gasPrice of 1 gwei");
19347
+ } else if (feeData.maxFeePerGas) {
19348
+ const maxFee = feeData.maxFeePerGas < minBaseFee ? minBaseFee : feeData.maxFeePerGas;
19349
+ txOverrides.gasPrice = maxFee;
19350
+ console.log(`Wanchain: using gasPrice ${formatUnits(maxFee, "gwei")} gwei`);
19351
+ }
19352
+ }
19353
+ const sentTx = await tokenContract.transfer(opts.to, amount, txOverrides);
19354
+ console.log(`Transaction hash: ${sentTx.hash}`);
19355
+ console.log("Waiting for confirmation...");
19356
+ const receipt = await sentTx.wait();
19357
+ console.log(`Transaction confirmed in block ${receipt?.blockNumber}`);
19358
+ console.log(`Gas used: ${receipt?.gasUsed.toString()}`);
19359
+ } catch (e) {
19360
+ console.error(`Error: ${e.message}`);
19361
+ process.exit(1);
19362
+ }
19363
+ });
19184
19364
  program2.command("status").description(`Check cross-chain transaction status
19185
19365
 
19186
19366
  ` + `Status codes:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xflows",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "CLI tool for Wanchain XFlows cross-chain bridge - wallet management, quote queries, and cross-chain transactions",
5
5
  "type": "module",
6
6
  "bin": {