xflows 1.0.2 → 1.1.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 +72 -0
  2. package/dist/index.js +147 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -18,6 +18,8 @@ A command-line interface for the [Wanchain XFlows](https://docs.wanchain.org/dev
18
18
  - [Query Commands](#query-commands)
19
19
  - [Quote](#quote)
20
20
  - [Send Transaction](#send-transaction)
21
+ - [Transfer (Native Token)](#transfer-native-token)
22
+ - [Transfer Token (ERC20)](#transfer-token-erc20)
21
23
  - [Transaction Status](#transaction-status)
22
24
  - [RPC List](#rpc-list)
23
25
  - [Complete Workflow Example](#complete-workflow-example)
@@ -511,6 +513,76 @@ xflows send \
511
513
  7. Waits for on-chain confirmation
512
514
  8. Prints the transaction hash and a ready-to-use `xflows status` command for tracking
513
515
 
516
+ ### Transfer (Native Token)
517
+
518
+ Send native tokens (ETH, BNB, WAN, etc.) on the same chain. This is a simple transfer, not a cross-chain bridge operation.
519
+
520
+ ```bash
521
+ # Send 0.1 ETH on Ethereum
522
+ xflows transfer --wallet alice --chain-id 1 --to 0xRecipient --amount 0.1
523
+
524
+ # Send 1.5 BNB on BSC with encrypted wallet
525
+ xflows transfer --wallet alice --password mysecret --chain-id 56 --to 0xRecipient --amount 1.5
526
+
527
+ # Dry run (preview without sending)
528
+ xflows transfer --wallet alice --chain-id 1 --to 0xRecipient --amount 0.1 --dry-run
529
+ ```
530
+
531
+ | Flag | Required | Description |
532
+ |------|----------|-------------|
533
+ | `--wallet <name>` | Yes | Wallet name to use for signing |
534
+ | `--chain-id <id>` | Yes | Chain ID to send on |
535
+ | `--to <address>` | Yes | Recipient address |
536
+ | `--amount <amount>` | Yes | Amount to send (human-readable, e.g., `0.1`) |
537
+ | `--password <pw>` | No | Password for encrypted wallet |
538
+ | `--rpc <url>` | No | Override default RPC endpoint |
539
+ | `--gas-limit <limit>` | No | Custom gas limit |
540
+ | `--dry-run` | No | Build but do not send the transaction |
541
+
542
+ ### Transfer Token (ERC20)
543
+
544
+ Send ERC20 tokens on the same chain. Token decimals are auto-detected from the contract, or can be specified manually.
545
+
546
+ ```bash
547
+ # Send 100 USDC on Ethereum (auto-detect decimals)
548
+ xflows transfer-token --wallet alice --chain-id 1 \
549
+ --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
550
+ --to 0xRecipient --amount 100
551
+
552
+ # Send with explicit decimals
553
+ xflows transfer-token --wallet alice --chain-id 1 \
554
+ --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
555
+ --to 0xRecipient --amount 100 --decimals 6
556
+
557
+ # Send 50 USDT on BSC with encrypted wallet
558
+ xflows transfer-token --wallet alice --password mysecret --chain-id 56 \
559
+ --token 0x55d398326f99059fF775485246999027B3197955 \
560
+ --to 0xRecipient --amount 50
561
+
562
+ # Dry run (preview without sending)
563
+ xflows transfer-token --wallet alice --chain-id 1 \
564
+ --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
565
+ --to 0xRecipient --amount 100 --dry-run
566
+ ```
567
+
568
+ | Flag | Required | Description |
569
+ |------|----------|-------------|
570
+ | `--wallet <name>` | Yes | Wallet name to use for signing |
571
+ | `--chain-id <id>` | Yes | Chain ID to send on |
572
+ | `--token <address>` | Yes | ERC20 token contract address |
573
+ | `--to <address>` | Yes | Recipient address |
574
+ | `--amount <amount>` | Yes | Amount to send (human-readable, e.g., `100`) |
575
+ | `--decimals <n>` | No | Token decimals (auto-detected if omitted) |
576
+ | `--password <pw>` | No | Password for encrypted wallet |
577
+ | `--rpc <url>` | No | Override default RPC endpoint |
578
+ | `--gas-limit <limit>` | No | Custom gas limit |
579
+ | `--dry-run` | No | Build but do not send the transaction |
580
+
581
+ **Features:**
582
+ - Auto-detects token decimals and symbol from the contract
583
+ - Checks token balance before sending to provide a clear error message
584
+ - Supports Wanchain gas price enforcement
585
+
514
586
  ### Transaction Status
515
587
 
516
588
  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.1.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");
@@ -19181,6 +19190,141 @@ You can track the cross-chain status with:`);
19181
19190
  process.exit(1);
19182
19191
  }
19183
19192
  });
19193
+ program2.command("transfer").description(`Send native tokens (ETH/BNB/WAN/etc.) on the same chain
19194
+
19195
+ ` + `This is a simple same-chain transfer, NOT a cross-chain bridge operation.
19196
+
19197
+ ` + `Examples:
19198
+ ` + ` # Send 0.1 ETH on Ethereum
19199
+ ` + ` xflows transfer --wallet alice --chain-id 1 --to 0xRecipient --amount 0.1
19200
+
19201
+ ` + ` # Send 1.5 BNB on BSC with encrypted wallet
19202
+ ` + " 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) => {
19203
+ try {
19204
+ const wallet = loadWallet(opts.wallet, opts.password);
19205
+ const provider = opts.rpc ? new JsonRpcProvider(opts.rpc) : getProvider2(opts.chainId);
19206
+ const signer = wallet.connect(provider);
19207
+ const txRequest = {
19208
+ to: opts.to,
19209
+ value: parseEther(opts.amount)
19210
+ };
19211
+ if (opts.gasLimit) {
19212
+ txRequest.gasLimit = BigInt(opts.gasLimit);
19213
+ }
19214
+ const isWanchain = opts.chainId === "888";
19215
+ if (isWanchain) {
19216
+ const feeData = await provider.getFeeData();
19217
+ const minBaseFee = parseUnits("1", "gwei");
19218
+ if (feeData.gasPrice && feeData.gasPrice < minBaseFee) {
19219
+ txRequest.gasPrice = minBaseFee;
19220
+ console.log("Wanchain: enforcing minimum gasPrice of 1 gwei");
19221
+ } else if (feeData.maxFeePerGas) {
19222
+ const maxFee = feeData.maxFeePerGas < minBaseFee ? minBaseFee : feeData.maxFeePerGas;
19223
+ txRequest.gasPrice = maxFee;
19224
+ console.log(`Wanchain: using gasPrice ${formatUnits(maxFee, "gwei")} gwei`);
19225
+ }
19226
+ }
19227
+ if (opts.dryRun) {
19228
+ console.log("[Dry Run] Transaction details:");
19229
+ printJson({
19230
+ from: wallet.address,
19231
+ to: opts.to,
19232
+ value: txRequest.value.toString(),
19233
+ chainId: opts.chainId
19234
+ });
19235
+ return;
19236
+ }
19237
+ console.log(`Sending ${opts.amount} native token to ${opts.to} on chain ${opts.chainId}...`);
19238
+ const sentTx = await signer.sendTransaction(txRequest);
19239
+ console.log(`Transaction hash: ${sentTx.hash}`);
19240
+ console.log("Waiting for confirmation...");
19241
+ const receipt = await sentTx.wait();
19242
+ console.log(`Transaction confirmed in block ${receipt?.blockNumber}`);
19243
+ console.log(`Gas used: ${receipt?.gasUsed.toString()}`);
19244
+ } catch (e) {
19245
+ console.error(`Error: ${e.message}`);
19246
+ process.exit(1);
19247
+ }
19248
+ });
19249
+ program2.command("transfer-token").description(`Send ERC20 tokens on the same chain
19250
+
19251
+ ` + `This is a simple same-chain ERC20 transfer, NOT a cross-chain bridge operation.
19252
+
19253
+ ` + `Examples:
19254
+ ` + ` # Send 100 USDC on Ethereum (6 decimals)
19255
+ ` + " xflows transfer-token --wallet alice --chain-id 1 \\\n" + " --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \\\n" + ` --to 0xRecipient --amount 100 --decimals 6
19256
+
19257
+ ` + ` # Send 50 USDT on BSC (auto-detect decimals)
19258
+ ` + " 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) => {
19259
+ try {
19260
+ const wallet = loadWallet(opts.wallet, opts.password);
19261
+ const provider = opts.rpc ? new JsonRpcProvider(opts.rpc) : getProvider2(opts.chainId);
19262
+ const signer = wallet.connect(provider);
19263
+ const tokenContract = new Contract(opts.token, ERC20_ABI, signer);
19264
+ let decimals;
19265
+ if (opts.decimals !== undefined) {
19266
+ decimals = Number(opts.decimals);
19267
+ } else {
19268
+ try {
19269
+ decimals = Number(await tokenContract.decimals());
19270
+ console.log(`Token decimals: ${decimals}`);
19271
+ } catch {
19272
+ throw new Error("Could not auto-detect token decimals. Please provide --decimals manually.");
19273
+ }
19274
+ }
19275
+ let symbol = "TOKEN";
19276
+ try {
19277
+ symbol = await tokenContract.symbol();
19278
+ } catch {}
19279
+ const amount = parseUnits(opts.amount, decimals);
19280
+ const balance = await tokenContract.balanceOf(wallet.address);
19281
+ if (balance < amount) {
19282
+ console.error(`Insufficient ${symbol} balance: ${formatUnits(balance, decimals)} < ${opts.amount}`);
19283
+ process.exit(1);
19284
+ }
19285
+ if (opts.dryRun) {
19286
+ console.log("[Dry Run] Transaction details:");
19287
+ printJson({
19288
+ from: wallet.address,
19289
+ to: opts.to,
19290
+ token: opts.token,
19291
+ symbol,
19292
+ amount: opts.amount,
19293
+ amountWei: amount.toString(),
19294
+ decimals,
19295
+ chainId: opts.chainId
19296
+ });
19297
+ return;
19298
+ }
19299
+ console.log(`Sending ${opts.amount} ${symbol} to ${opts.to} on chain ${opts.chainId}...`);
19300
+ const txOverrides = {};
19301
+ if (opts.gasLimit) {
19302
+ txOverrides.gasLimit = BigInt(opts.gasLimit);
19303
+ }
19304
+ const isWanchain = opts.chainId === "888";
19305
+ if (isWanchain) {
19306
+ const feeData = await provider.getFeeData();
19307
+ const minBaseFee = parseUnits("1", "gwei");
19308
+ if (feeData.gasPrice && feeData.gasPrice < minBaseFee) {
19309
+ txOverrides.gasPrice = minBaseFee;
19310
+ console.log("Wanchain: enforcing minimum gasPrice of 1 gwei");
19311
+ } else if (feeData.maxFeePerGas) {
19312
+ const maxFee = feeData.maxFeePerGas < minBaseFee ? minBaseFee : feeData.maxFeePerGas;
19313
+ txOverrides.gasPrice = maxFee;
19314
+ console.log(`Wanchain: using gasPrice ${formatUnits(maxFee, "gwei")} gwei`);
19315
+ }
19316
+ }
19317
+ const sentTx = await tokenContract.transfer(opts.to, amount, txOverrides);
19318
+ console.log(`Transaction hash: ${sentTx.hash}`);
19319
+ console.log("Waiting for confirmation...");
19320
+ const receipt = await sentTx.wait();
19321
+ console.log(`Transaction confirmed in block ${receipt?.blockNumber}`);
19322
+ console.log(`Gas used: ${receipt?.gasUsed.toString()}`);
19323
+ } catch (e) {
19324
+ console.error(`Error: ${e.message}`);
19325
+ process.exit(1);
19326
+ }
19327
+ });
19184
19328
  program2.command("status").description(`Check cross-chain transaction status
19185
19329
 
19186
19330
  ` + `Status codes:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xflows",
3
- "version": "1.0.2",
3
+ "version": "1.1.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": {