@pioneer-platform/pioneer-sdk 8.15.40 → 8.15.44

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/dist/index.cjs CHANGED
@@ -4264,8 +4264,8 @@ var EXPLORER_BASE_URLS = {
4264
4264
  tx: "https://blockchair.com/bitcoin-cash/transaction/"
4265
4265
  },
4266
4266
  "bip122:000007d91d1254d60e2dd1ae58038307": {
4267
- address: "https://chainz.cryptoid.info/dash/address.dws?",
4268
- tx: "https://chainz.cryptoid.info/dash/tx.dws?"
4267
+ address: "https://explorer.dash.org/insight/address/",
4268
+ tx: "https://explorer.dash.org/insight/tx/"
4269
4269
  },
4270
4270
  "bip122:4da631f2ac1bed857bd968c67c913978": {
4271
4271
  address: "https://digiexplorer.info/address/",
@@ -4702,6 +4702,7 @@ class SDK {
4702
4702
  assetsMap;
4703
4703
  dashboard;
4704
4704
  nfts;
4705
+ pendingTransactions;
4705
4706
  events;
4706
4707
  pairWallet;
4707
4708
  setContext;
@@ -4781,6 +4782,7 @@ class SDK {
4781
4782
  this.nodes = config.nodes || [];
4782
4783
  this.charts = ["covalent", "zapper"];
4783
4784
  this.nfts = [];
4785
+ this.pendingTransactions = [];
4784
4786
  this.isPioneer = null;
4785
4787
  this.pioneer = null;
4786
4788
  this.context = "";
@@ -5188,6 +5190,29 @@ class SDK {
5188
5190
  let txManager = new TransactionManager(transactionDependencies, this.events);
5189
5191
  let unsignedTx = await txManager.transfer(sendPayload);
5190
5192
  console.log(tag6, "unsignedTx: ", unsignedTx);
5193
+ if (this.assetContext && sendPayload) {
5194
+ this.assetContext.sendAmount = sendPayload.amount;
5195
+ this.assetContext.sendTo = sendPayload.to;
5196
+ this.assetContext.sendMemo = sendPayload.memo;
5197
+ let estimatedFee = "0";
5198
+ if (unsignedTx) {
5199
+ if (unsignedTx.fee) {
5200
+ estimatedFee = typeof unsignedTx.fee === "string" ? unsignedTx.fee : unsignedTx.fee.toString();
5201
+ } else if (unsignedTx.gasPrice && unsignedTx.gasLimit) {
5202
+ const gasPrice = parseFloat(unsignedTx.gasPrice);
5203
+ const gasLimit = parseFloat(unsignedTx.gasLimit);
5204
+ estimatedFee = (gasPrice * gasLimit / 1e9).toFixed(8);
5205
+ } else if (unsignedTx.fee && unsignedTx.fee.amount && Array.isArray(unsignedTx.fee.amount)) {
5206
+ estimatedFee = unsignedTx.fee.amount[0]?.amount || "0";
5207
+ }
5208
+ }
5209
+ this.assetContext.sendFee = estimatedFee;
5210
+ console.log(tag6, "\uD83D\uDCBE Stored transaction details for optimistic update:", {
5211
+ amount: this.assetContext.sendAmount,
5212
+ fee: this.assetContext.sendFee,
5213
+ to: this.assetContext.sendTo
5214
+ });
5215
+ }
5191
5216
  return unsignedTx;
5192
5217
  } catch (e) {
5193
5218
  console.error(e);
@@ -5292,12 +5317,101 @@ class SDK {
5292
5317
  serialized: signedTx
5293
5318
  };
5294
5319
  let txid = await txManager.broadcast(payload);
5320
+ if (txid && !txid.error) {
5321
+ const amount = this.assetContext?.sendAmount || "0";
5322
+ const fee = this.assetContext?.sendFee || "0";
5323
+ const to = this.assetContext?.sendTo || "";
5324
+ const from = this.pubkeyContext?.address || this.pubkeyContext?.master || "";
5325
+ if (amount !== "0" && parseFloat(amount) > 0) {
5326
+ console.log(tag6, "\uD83D\uDCB0 Performing optimistic balance update:", {
5327
+ caip,
5328
+ amount,
5329
+ fee,
5330
+ from,
5331
+ to
5332
+ });
5333
+ this.debitBalance(caip, amount, fee);
5334
+ this.addPendingTransaction({
5335
+ txid,
5336
+ caip,
5337
+ amount,
5338
+ to,
5339
+ from,
5340
+ fee,
5341
+ broadcastTime: Date.now(),
5342
+ status: "pending"
5343
+ });
5344
+ }
5345
+ }
5295
5346
  return txid;
5296
5347
  } catch (e) {
5297
5348
  console.error(e);
5298
5349
  throw e;
5299
5350
  }
5300
5351
  };
5352
+ this.addPendingTransaction = function(txData) {
5353
+ const tag6 = TAG12 + " | addPendingTransaction | ";
5354
+ console.log(tag6, "Adding pending transaction:", txData);
5355
+ this.pendingTransactions.unshift({
5356
+ ...txData,
5357
+ status: txData.status || "pending",
5358
+ addedAt: Date.now()
5359
+ });
5360
+ if (this.pendingTransactions.length > 50) {
5361
+ this.pendingTransactions = this.pendingTransactions.slice(0, 50);
5362
+ }
5363
+ this.events.emit("PENDING_TX_ADDED", txData);
5364
+ this.events.emit("PENDING_TXS_UPDATED", this.pendingTransactions);
5365
+ console.log(tag6, `Pending transactions count: ${this.pendingTransactions.length}`);
5366
+ return txData;
5367
+ };
5368
+ this.debitBalance = function(caip, amount, fee = "0") {
5369
+ const tag6 = TAG12 + " | debitBalance | ";
5370
+ console.log(tag6, "Debiting balance:", { caip, amount, fee });
5371
+ const balanceIndex = this.balances.findIndex((b) => b.caip === caip);
5372
+ if (balanceIndex === -1) {
5373
+ console.warn(tag6, "Balance not found for CAIP:", caip);
5374
+ return null;
5375
+ }
5376
+ const currentBalance = this.balances[balanceIndex];
5377
+ const currentBalanceNum = parseFloat(currentBalance.balance || "0");
5378
+ const amountNum = parseFloat(amount);
5379
+ const feeNum = parseFloat(fee);
5380
+ const totalDebit = amountNum + feeNum;
5381
+ const newBalanceNum = currentBalanceNum - totalDebit;
5382
+ if (newBalanceNum < 0) {
5383
+ console.warn(tag6, "Cannot debit - would result in negative balance:", {
5384
+ current: currentBalanceNum,
5385
+ debit: totalDebit,
5386
+ result: newBalanceNum
5387
+ });
5388
+ return null;
5389
+ }
5390
+ const updatedBalance = {
5391
+ ...currentBalance,
5392
+ balance: newBalanceNum.toFixed(8),
5393
+ valueUsd: newBalanceNum * (parseFloat(currentBalance.priceUsd) || 0),
5394
+ updated: Date.now(),
5395
+ optimistic: true,
5396
+ previousBalance: currentBalanceNum
5397
+ };
5398
+ this.balances[balanceIndex] = updatedBalance;
5399
+ console.log(tag6, "✅ Balance updated:", {
5400
+ previous: currentBalanceNum.toFixed(8),
5401
+ new: newBalanceNum.toFixed(8),
5402
+ deducted: totalDebit.toFixed(8)
5403
+ });
5404
+ this.events.emit("BALANCES_UPDATED", this.balances);
5405
+ this.events.emit("SET_BALANCES", this.balances);
5406
+ try {
5407
+ this.dashboard = this.buildDashboardFromBalances();
5408
+ this.events.emit("SET_DASHBOARD", this.dashboard);
5409
+ console.log(tag6, "✅ Dashboard rebuilt with updated balance");
5410
+ } catch (dashboardError) {
5411
+ console.error(tag6, "Error rebuilding dashboard:", dashboardError);
5412
+ }
5413
+ return updatedBalance;
5414
+ };
5301
5415
  this.swap = async function(swapPayload) {
5302
5416
  let tag6 = `${TAG12} | swap | `;
5303
5417
  try {
@@ -5763,6 +5877,14 @@ class SDK {
5763
5877
  const assetQuery = [];
5764
5878
  for (const networkId of networkIds) {
5765
5879
  const pubkeys = findPubkeysForNetwork(this.pubkeys, networkId, this.paths, tag6);
5880
+ console.log(`\uD83D\uDD0D [DIAGNOSTIC] ${networkId}: Found ${pubkeys.length} pubkeys`);
5881
+ if (networkId.startsWith("bip122:000000000019")) {
5882
+ console.log("\uD83D\uDD0D [BITCOIN DIAGNOSTIC] Bitcoin pubkeys:", pubkeys.map((p) => ({
5883
+ pubkey: p.pubkey?.substring(0, 20) + "...",
5884
+ networks: p.networks,
5885
+ symbol: p.symbol
5886
+ })));
5887
+ }
5766
5888
  const caip = await import_pioneer_caip8.networkIdToCaip(networkId);
5767
5889
  assetQuery.push(...buildAssetQuery(pubkeys, caip));
5768
5890
  }
@@ -5777,7 +5899,18 @@ class SDK {
5777
5899
  console.log(`⏱️ [PERF] Enriching ${marketInfo.data?.length || 0} balances...`);
5778
5900
  const balances = enrichBalancesWithAssetInfo(marketInfo.data, this.assetsMap, import_pioneer_caip8.caipToNetworkId);
5779
5901
  console.log(`⏱️ [PERF] Enrichment completed in ${(performance.now() - enrichStart).toFixed(0)}ms`);
5780
- this.balances = balances;
5902
+ console.log(tag6, `⚙️ Merging balances: ${balances.length} new + ${this.balances.length} existing`);
5903
+ const uniqueBalances = new Map([...this.balances, ...balances].map((balance) => [
5904
+ balance.identifier || `${balance.caip}:${balance.pubkey}`,
5905
+ balance
5906
+ ]));
5907
+ const beforeCount = [...this.balances, ...balances].length;
5908
+ this.balances = Array.from(uniqueBalances.values());
5909
+ const duplicatesRemoved = beforeCount - this.balances.length;
5910
+ if (duplicatesRemoved > 0) {
5911
+ console.log(tag6, `\uD83D\uDD27 Removed ${duplicatesRemoved} duplicate balances`);
5912
+ }
5913
+ console.log(tag6, `✅ Final balance count: ${this.balances.length} unique balances`);
5781
5914
  this.events.emit("SET_BALANCES", this.balances);
5782
5915
  const dashStart = performance.now();
5783
5916
  this.dashboard = this.buildDashboardFromBalances();
@@ -5791,16 +5924,29 @@ class SDK {
5791
5924
  throw e;
5792
5925
  }
5793
5926
  };
5794
- this.getBalances = async function(forceRefresh, caip) {
5927
+ this.getBalances = async function(forceRefreshOrOptions, caip) {
5795
5928
  const tag6 = `${TAG12} | getBalances | `;
5796
5929
  try {
5797
- if (caip) {
5798
- console.log(tag6, `\uD83C\uDFAF Refreshing single asset: ${caip}`);
5799
- const networkId = caip.split("/")[0];
5800
- console.log(tag6, `\uD83D\uDCCD Target network: ${networkId}`);
5930
+ let forceRefresh = false;
5931
+ let networkId;
5932
+ if (typeof forceRefreshOrOptions === "object") {
5933
+ networkId = forceRefreshOrOptions.networkId;
5934
+ forceRefresh = forceRefreshOrOptions.forceRefresh ?? false;
5935
+ console.log(tag6, `\uD83D\uDCCD New signature - networkId: ${networkId}, forceRefresh: ${forceRefresh}`);
5936
+ } else {
5937
+ forceRefresh = forceRefreshOrOptions ?? false;
5938
+ if (caip) {
5939
+ console.log(tag6, `\uD83C\uDFAF Old signature - Refreshing single asset: ${caip}`);
5940
+ networkId = caip.split("/")[0];
5941
+ console.log(tag6, `\uD83D\uDCCD Extracted networkId: ${networkId}`);
5942
+ }
5943
+ }
5944
+ if (networkId) {
5945
+ console.log(tag6, `\uD83C\uDFAF Refreshing specific network: ${networkId}`);
5801
5946
  const results = await this.getBalancesForNetworks([networkId], forceRefresh);
5802
- return results.filter((b) => b.caip === caip || b.networkId === networkId);
5947
+ return results.filter((b) => b.networkId === networkId || b.caip?.startsWith(networkId));
5803
5948
  }
5949
+ console.log(tag6, `\uD83C\uDF10 Refreshing all blockchains (${this.blockchains.length} networks)`);
5804
5950
  return await this.getBalancesForNetworks(this.blockchains, forceRefresh);
5805
5951
  } catch (e) {
5806
5952
  console.error(tag6, "Error in getBalances: ", e);
@@ -5941,7 +6087,7 @@ class SDK {
5941
6087
  "bip122:12a765e31ffd4059bada1e25190f6e98": { address: "https://blockchair.com/litecoin/address/", tx: "https://blockchair.com/litecoin/transaction/" },
5942
6088
  "bip122:00000000001a91e3dace36e2be3bf030": { address: "https://dogechain.info/address/", tx: "https://dogechain.info/tx/" },
5943
6089
  "bip122:000000000000000000651ef99cb9fcbe": { address: "https://blockchair.com/bitcoin-cash/address/", tx: "https://blockchair.com/bitcoin-cash/transaction/" },
5944
- "bip122:000007d91d1254d60e2dd1ae58038307": { address: "https://chainz.cryptoid.info/dash/address.dws?", tx: "https://chainz.cryptoid.info/dash/tx.dws?" },
6090
+ "bip122:000007d91d1254d60e2dd1ae58038307": { address: "https://explorer.dash.org/insight/address/", tx: "https://explorer.dash.org/insight/tx/" },
5945
6091
  "bip122:4da631f2ac1bed857bd968c67c913978": { address: "https://digiexplorer.info/address/", tx: "https://digiexplorer.info/tx/" },
5946
6092
  "bip122:00040fe8ec8471911baa1db1266ea15d": { address: "https://explorer.zcha.in/accounts/", tx: "https://explorer.zcha.in/transactions/" },
5947
6093
  "cosmos:cosmoshub-4": { address: "https://www.mintscan.io/cosmos/address/", tx: "https://www.mintscan.io/cosmos/tx/" },
package/dist/index.es.js CHANGED
@@ -4448,8 +4448,8 @@ var EXPLORER_BASE_URLS = {
4448
4448
  tx: "https://blockchair.com/bitcoin-cash/transaction/"
4449
4449
  },
4450
4450
  "bip122:000007d91d1254d60e2dd1ae58038307": {
4451
- address: "https://chainz.cryptoid.info/dash/address.dws?",
4452
- tx: "https://chainz.cryptoid.info/dash/tx.dws?"
4451
+ address: "https://explorer.dash.org/insight/address/",
4452
+ tx: "https://explorer.dash.org/insight/tx/"
4453
4453
  },
4454
4454
  "bip122:4da631f2ac1bed857bd968c67c913978": {
4455
4455
  address: "https://digiexplorer.info/address/",
@@ -4886,6 +4886,7 @@ class SDK {
4886
4886
  assetsMap;
4887
4887
  dashboard;
4888
4888
  nfts;
4889
+ pendingTransactions;
4889
4890
  events;
4890
4891
  pairWallet;
4891
4892
  setContext;
@@ -4965,6 +4966,7 @@ class SDK {
4965
4966
  this.nodes = config.nodes || [];
4966
4967
  this.charts = ["covalent", "zapper"];
4967
4968
  this.nfts = [];
4969
+ this.pendingTransactions = [];
4968
4970
  this.isPioneer = null;
4969
4971
  this.pioneer = null;
4970
4972
  this.context = "";
@@ -5372,6 +5374,29 @@ class SDK {
5372
5374
  let txManager = new TransactionManager(transactionDependencies, this.events);
5373
5375
  let unsignedTx = await txManager.transfer(sendPayload);
5374
5376
  console.log(tag6, "unsignedTx: ", unsignedTx);
5377
+ if (this.assetContext && sendPayload) {
5378
+ this.assetContext.sendAmount = sendPayload.amount;
5379
+ this.assetContext.sendTo = sendPayload.to;
5380
+ this.assetContext.sendMemo = sendPayload.memo;
5381
+ let estimatedFee = "0";
5382
+ if (unsignedTx) {
5383
+ if (unsignedTx.fee) {
5384
+ estimatedFee = typeof unsignedTx.fee === "string" ? unsignedTx.fee : unsignedTx.fee.toString();
5385
+ } else if (unsignedTx.gasPrice && unsignedTx.gasLimit) {
5386
+ const gasPrice = parseFloat(unsignedTx.gasPrice);
5387
+ const gasLimit = parseFloat(unsignedTx.gasLimit);
5388
+ estimatedFee = (gasPrice * gasLimit / 1e9).toFixed(8);
5389
+ } else if (unsignedTx.fee && unsignedTx.fee.amount && Array.isArray(unsignedTx.fee.amount)) {
5390
+ estimatedFee = unsignedTx.fee.amount[0]?.amount || "0";
5391
+ }
5392
+ }
5393
+ this.assetContext.sendFee = estimatedFee;
5394
+ console.log(tag6, "\uD83D\uDCBE Stored transaction details for optimistic update:", {
5395
+ amount: this.assetContext.sendAmount,
5396
+ fee: this.assetContext.sendFee,
5397
+ to: this.assetContext.sendTo
5398
+ });
5399
+ }
5375
5400
  return unsignedTx;
5376
5401
  } catch (e) {
5377
5402
  console.error(e);
@@ -5476,12 +5501,101 @@ class SDK {
5476
5501
  serialized: signedTx
5477
5502
  };
5478
5503
  let txid = await txManager.broadcast(payload);
5504
+ if (txid && !txid.error) {
5505
+ const amount = this.assetContext?.sendAmount || "0";
5506
+ const fee = this.assetContext?.sendFee || "0";
5507
+ const to = this.assetContext?.sendTo || "";
5508
+ const from = this.pubkeyContext?.address || this.pubkeyContext?.master || "";
5509
+ if (amount !== "0" && parseFloat(amount) > 0) {
5510
+ console.log(tag6, "\uD83D\uDCB0 Performing optimistic balance update:", {
5511
+ caip,
5512
+ amount,
5513
+ fee,
5514
+ from,
5515
+ to
5516
+ });
5517
+ this.debitBalance(caip, amount, fee);
5518
+ this.addPendingTransaction({
5519
+ txid,
5520
+ caip,
5521
+ amount,
5522
+ to,
5523
+ from,
5524
+ fee,
5525
+ broadcastTime: Date.now(),
5526
+ status: "pending"
5527
+ });
5528
+ }
5529
+ }
5479
5530
  return txid;
5480
5531
  } catch (e) {
5481
5532
  console.error(e);
5482
5533
  throw e;
5483
5534
  }
5484
5535
  };
5536
+ this.addPendingTransaction = function(txData) {
5537
+ const tag6 = TAG12 + " | addPendingTransaction | ";
5538
+ console.log(tag6, "Adding pending transaction:", txData);
5539
+ this.pendingTransactions.unshift({
5540
+ ...txData,
5541
+ status: txData.status || "pending",
5542
+ addedAt: Date.now()
5543
+ });
5544
+ if (this.pendingTransactions.length > 50) {
5545
+ this.pendingTransactions = this.pendingTransactions.slice(0, 50);
5546
+ }
5547
+ this.events.emit("PENDING_TX_ADDED", txData);
5548
+ this.events.emit("PENDING_TXS_UPDATED", this.pendingTransactions);
5549
+ console.log(tag6, `Pending transactions count: ${this.pendingTransactions.length}`);
5550
+ return txData;
5551
+ };
5552
+ this.debitBalance = function(caip, amount, fee = "0") {
5553
+ const tag6 = TAG12 + " | debitBalance | ";
5554
+ console.log(tag6, "Debiting balance:", { caip, amount, fee });
5555
+ const balanceIndex = this.balances.findIndex((b2) => b2.caip === caip);
5556
+ if (balanceIndex === -1) {
5557
+ console.warn(tag6, "Balance not found for CAIP:", caip);
5558
+ return null;
5559
+ }
5560
+ const currentBalance = this.balances[balanceIndex];
5561
+ const currentBalanceNum = parseFloat(currentBalance.balance || "0");
5562
+ const amountNum = parseFloat(amount);
5563
+ const feeNum = parseFloat(fee);
5564
+ const totalDebit = amountNum + feeNum;
5565
+ const newBalanceNum = currentBalanceNum - totalDebit;
5566
+ if (newBalanceNum < 0) {
5567
+ console.warn(tag6, "Cannot debit - would result in negative balance:", {
5568
+ current: currentBalanceNum,
5569
+ debit: totalDebit,
5570
+ result: newBalanceNum
5571
+ });
5572
+ return null;
5573
+ }
5574
+ const updatedBalance = {
5575
+ ...currentBalance,
5576
+ balance: newBalanceNum.toFixed(8),
5577
+ valueUsd: newBalanceNum * (parseFloat(currentBalance.priceUsd) || 0),
5578
+ updated: Date.now(),
5579
+ optimistic: true,
5580
+ previousBalance: currentBalanceNum
5581
+ };
5582
+ this.balances[balanceIndex] = updatedBalance;
5583
+ console.log(tag6, "✅ Balance updated:", {
5584
+ previous: currentBalanceNum.toFixed(8),
5585
+ new: newBalanceNum.toFixed(8),
5586
+ deducted: totalDebit.toFixed(8)
5587
+ });
5588
+ this.events.emit("BALANCES_UPDATED", this.balances);
5589
+ this.events.emit("SET_BALANCES", this.balances);
5590
+ try {
5591
+ this.dashboard = this.buildDashboardFromBalances();
5592
+ this.events.emit("SET_DASHBOARD", this.dashboard);
5593
+ console.log(tag6, "✅ Dashboard rebuilt with updated balance");
5594
+ } catch (dashboardError) {
5595
+ console.error(tag6, "Error rebuilding dashboard:", dashboardError);
5596
+ }
5597
+ return updatedBalance;
5598
+ };
5485
5599
  this.swap = async function(swapPayload) {
5486
5600
  let tag6 = `${TAG12} | swap | `;
5487
5601
  try {
@@ -5947,6 +6061,14 @@ class SDK {
5947
6061
  const assetQuery = [];
5948
6062
  for (const networkId of networkIds) {
5949
6063
  const pubkeys = findPubkeysForNetwork(this.pubkeys, networkId, this.paths, tag6);
6064
+ console.log(`\uD83D\uDD0D [DIAGNOSTIC] ${networkId}: Found ${pubkeys.length} pubkeys`);
6065
+ if (networkId.startsWith("bip122:000000000019")) {
6066
+ console.log("\uD83D\uDD0D [BITCOIN DIAGNOSTIC] Bitcoin pubkeys:", pubkeys.map((p) => ({
6067
+ pubkey: p.pubkey?.substring(0, 20) + "...",
6068
+ networks: p.networks,
6069
+ symbol: p.symbol
6070
+ })));
6071
+ }
5950
6072
  const caip = await networkIdToCaip2(networkId);
5951
6073
  assetQuery.push(...buildAssetQuery(pubkeys, caip));
5952
6074
  }
@@ -5961,7 +6083,18 @@ class SDK {
5961
6083
  console.log(`⏱️ [PERF] Enriching ${marketInfo.data?.length || 0} balances...`);
5962
6084
  const balances = enrichBalancesWithAssetInfo(marketInfo.data, this.assetsMap, caipToNetworkId7);
5963
6085
  console.log(`⏱️ [PERF] Enrichment completed in ${(performance.now() - enrichStart).toFixed(0)}ms`);
5964
- this.balances = balances;
6086
+ console.log(tag6, `⚙️ Merging balances: ${balances.length} new + ${this.balances.length} existing`);
6087
+ const uniqueBalances = new Map([...this.balances, ...balances].map((balance) => [
6088
+ balance.identifier || `${balance.caip}:${balance.pubkey}`,
6089
+ balance
6090
+ ]));
6091
+ const beforeCount = [...this.balances, ...balances].length;
6092
+ this.balances = Array.from(uniqueBalances.values());
6093
+ const duplicatesRemoved = beforeCount - this.balances.length;
6094
+ if (duplicatesRemoved > 0) {
6095
+ console.log(tag6, `\uD83D\uDD27 Removed ${duplicatesRemoved} duplicate balances`);
6096
+ }
6097
+ console.log(tag6, `✅ Final balance count: ${this.balances.length} unique balances`);
5965
6098
  this.events.emit("SET_BALANCES", this.balances);
5966
6099
  const dashStart = performance.now();
5967
6100
  this.dashboard = this.buildDashboardFromBalances();
@@ -5975,16 +6108,29 @@ class SDK {
5975
6108
  throw e;
5976
6109
  }
5977
6110
  };
5978
- this.getBalances = async function(forceRefresh, caip) {
6111
+ this.getBalances = async function(forceRefreshOrOptions, caip) {
5979
6112
  const tag6 = `${TAG12} | getBalances | `;
5980
6113
  try {
5981
- if (caip) {
5982
- console.log(tag6, `\uD83C\uDFAF Refreshing single asset: ${caip}`);
5983
- const networkId = caip.split("/")[0];
5984
- console.log(tag6, `\uD83D\uDCCD Target network: ${networkId}`);
6114
+ let forceRefresh = false;
6115
+ let networkId;
6116
+ if (typeof forceRefreshOrOptions === "object") {
6117
+ networkId = forceRefreshOrOptions.networkId;
6118
+ forceRefresh = forceRefreshOrOptions.forceRefresh ?? false;
6119
+ console.log(tag6, `\uD83D\uDCCD New signature - networkId: ${networkId}, forceRefresh: ${forceRefresh}`);
6120
+ } else {
6121
+ forceRefresh = forceRefreshOrOptions ?? false;
6122
+ if (caip) {
6123
+ console.log(tag6, `\uD83C\uDFAF Old signature - Refreshing single asset: ${caip}`);
6124
+ networkId = caip.split("/")[0];
6125
+ console.log(tag6, `\uD83D\uDCCD Extracted networkId: ${networkId}`);
6126
+ }
6127
+ }
6128
+ if (networkId) {
6129
+ console.log(tag6, `\uD83C\uDFAF Refreshing specific network: ${networkId}`);
5985
6130
  const results = await this.getBalancesForNetworks([networkId], forceRefresh);
5986
- return results.filter((b2) => b2.caip === caip || b2.networkId === networkId);
6131
+ return results.filter((b2) => b2.networkId === networkId || b2.caip?.startsWith(networkId));
5987
6132
  }
6133
+ console.log(tag6, `\uD83C\uDF10 Refreshing all blockchains (${this.blockchains.length} networks)`);
5988
6134
  return await this.getBalancesForNetworks(this.blockchains, forceRefresh);
5989
6135
  } catch (e) {
5990
6136
  console.error(tag6, "Error in getBalances: ", e);
@@ -6125,7 +6271,7 @@ class SDK {
6125
6271
  "bip122:12a765e31ffd4059bada1e25190f6e98": { address: "https://blockchair.com/litecoin/address/", tx: "https://blockchair.com/litecoin/transaction/" },
6126
6272
  "bip122:00000000001a91e3dace36e2be3bf030": { address: "https://dogechain.info/address/", tx: "https://dogechain.info/tx/" },
6127
6273
  "bip122:000000000000000000651ef99cb9fcbe": { address: "https://blockchair.com/bitcoin-cash/address/", tx: "https://blockchair.com/bitcoin-cash/transaction/" },
6128
- "bip122:000007d91d1254d60e2dd1ae58038307": { address: "https://chainz.cryptoid.info/dash/address.dws?", tx: "https://chainz.cryptoid.info/dash/tx.dws?" },
6274
+ "bip122:000007d91d1254d60e2dd1ae58038307": { address: "https://explorer.dash.org/insight/address/", tx: "https://explorer.dash.org/insight/tx/" },
6129
6275
  "bip122:4da631f2ac1bed857bd968c67c913978": { address: "https://digiexplorer.info/address/", tx: "https://digiexplorer.info/tx/" },
6130
6276
  "bip122:00040fe8ec8471911baa1db1266ea15d": { address: "https://explorer.zcha.in/accounts/", tx: "https://explorer.zcha.in/transactions/" },
6131
6277
  "cosmos:cosmoshub-4": { address: "https://www.mintscan.io/cosmos/address/", tx: "https://www.mintscan.io/cosmos/tx/" },
package/dist/index.js CHANGED
@@ -4448,8 +4448,8 @@ var EXPLORER_BASE_URLS = {
4448
4448
  tx: "https://blockchair.com/bitcoin-cash/transaction/"
4449
4449
  },
4450
4450
  "bip122:000007d91d1254d60e2dd1ae58038307": {
4451
- address: "https://chainz.cryptoid.info/dash/address.dws?",
4452
- tx: "https://chainz.cryptoid.info/dash/tx.dws?"
4451
+ address: "https://explorer.dash.org/insight/address/",
4452
+ tx: "https://explorer.dash.org/insight/tx/"
4453
4453
  },
4454
4454
  "bip122:4da631f2ac1bed857bd968c67c913978": {
4455
4455
  address: "https://digiexplorer.info/address/",
@@ -4886,6 +4886,7 @@ class SDK {
4886
4886
  assetsMap;
4887
4887
  dashboard;
4888
4888
  nfts;
4889
+ pendingTransactions;
4889
4890
  events;
4890
4891
  pairWallet;
4891
4892
  setContext;
@@ -4965,6 +4966,7 @@ class SDK {
4965
4966
  this.nodes = config.nodes || [];
4966
4967
  this.charts = ["covalent", "zapper"];
4967
4968
  this.nfts = [];
4969
+ this.pendingTransactions = [];
4968
4970
  this.isPioneer = null;
4969
4971
  this.pioneer = null;
4970
4972
  this.context = "";
@@ -5372,6 +5374,29 @@ class SDK {
5372
5374
  let txManager = new TransactionManager(transactionDependencies, this.events);
5373
5375
  let unsignedTx = await txManager.transfer(sendPayload);
5374
5376
  console.log(tag6, "unsignedTx: ", unsignedTx);
5377
+ if (this.assetContext && sendPayload) {
5378
+ this.assetContext.sendAmount = sendPayload.amount;
5379
+ this.assetContext.sendTo = sendPayload.to;
5380
+ this.assetContext.sendMemo = sendPayload.memo;
5381
+ let estimatedFee = "0";
5382
+ if (unsignedTx) {
5383
+ if (unsignedTx.fee) {
5384
+ estimatedFee = typeof unsignedTx.fee === "string" ? unsignedTx.fee : unsignedTx.fee.toString();
5385
+ } else if (unsignedTx.gasPrice && unsignedTx.gasLimit) {
5386
+ const gasPrice = parseFloat(unsignedTx.gasPrice);
5387
+ const gasLimit = parseFloat(unsignedTx.gasLimit);
5388
+ estimatedFee = (gasPrice * gasLimit / 1e9).toFixed(8);
5389
+ } else if (unsignedTx.fee && unsignedTx.fee.amount && Array.isArray(unsignedTx.fee.amount)) {
5390
+ estimatedFee = unsignedTx.fee.amount[0]?.amount || "0";
5391
+ }
5392
+ }
5393
+ this.assetContext.sendFee = estimatedFee;
5394
+ console.log(tag6, "\uD83D\uDCBE Stored transaction details for optimistic update:", {
5395
+ amount: this.assetContext.sendAmount,
5396
+ fee: this.assetContext.sendFee,
5397
+ to: this.assetContext.sendTo
5398
+ });
5399
+ }
5375
5400
  return unsignedTx;
5376
5401
  } catch (e) {
5377
5402
  console.error(e);
@@ -5476,12 +5501,101 @@ class SDK {
5476
5501
  serialized: signedTx
5477
5502
  };
5478
5503
  let txid = await txManager.broadcast(payload);
5504
+ if (txid && !txid.error) {
5505
+ const amount = this.assetContext?.sendAmount || "0";
5506
+ const fee = this.assetContext?.sendFee || "0";
5507
+ const to = this.assetContext?.sendTo || "";
5508
+ const from = this.pubkeyContext?.address || this.pubkeyContext?.master || "";
5509
+ if (amount !== "0" && parseFloat(amount) > 0) {
5510
+ console.log(tag6, "\uD83D\uDCB0 Performing optimistic balance update:", {
5511
+ caip,
5512
+ amount,
5513
+ fee,
5514
+ from,
5515
+ to
5516
+ });
5517
+ this.debitBalance(caip, amount, fee);
5518
+ this.addPendingTransaction({
5519
+ txid,
5520
+ caip,
5521
+ amount,
5522
+ to,
5523
+ from,
5524
+ fee,
5525
+ broadcastTime: Date.now(),
5526
+ status: "pending"
5527
+ });
5528
+ }
5529
+ }
5479
5530
  return txid;
5480
5531
  } catch (e) {
5481
5532
  console.error(e);
5482
5533
  throw e;
5483
5534
  }
5484
5535
  };
5536
+ this.addPendingTransaction = function(txData) {
5537
+ const tag6 = TAG12 + " | addPendingTransaction | ";
5538
+ console.log(tag6, "Adding pending transaction:", txData);
5539
+ this.pendingTransactions.unshift({
5540
+ ...txData,
5541
+ status: txData.status || "pending",
5542
+ addedAt: Date.now()
5543
+ });
5544
+ if (this.pendingTransactions.length > 50) {
5545
+ this.pendingTransactions = this.pendingTransactions.slice(0, 50);
5546
+ }
5547
+ this.events.emit("PENDING_TX_ADDED", txData);
5548
+ this.events.emit("PENDING_TXS_UPDATED", this.pendingTransactions);
5549
+ console.log(tag6, `Pending transactions count: ${this.pendingTransactions.length}`);
5550
+ return txData;
5551
+ };
5552
+ this.debitBalance = function(caip, amount, fee = "0") {
5553
+ const tag6 = TAG12 + " | debitBalance | ";
5554
+ console.log(tag6, "Debiting balance:", { caip, amount, fee });
5555
+ const balanceIndex = this.balances.findIndex((b2) => b2.caip === caip);
5556
+ if (balanceIndex === -1) {
5557
+ console.warn(tag6, "Balance not found for CAIP:", caip);
5558
+ return null;
5559
+ }
5560
+ const currentBalance = this.balances[balanceIndex];
5561
+ const currentBalanceNum = parseFloat(currentBalance.balance || "0");
5562
+ const amountNum = parseFloat(amount);
5563
+ const feeNum = parseFloat(fee);
5564
+ const totalDebit = amountNum + feeNum;
5565
+ const newBalanceNum = currentBalanceNum - totalDebit;
5566
+ if (newBalanceNum < 0) {
5567
+ console.warn(tag6, "Cannot debit - would result in negative balance:", {
5568
+ current: currentBalanceNum,
5569
+ debit: totalDebit,
5570
+ result: newBalanceNum
5571
+ });
5572
+ return null;
5573
+ }
5574
+ const updatedBalance = {
5575
+ ...currentBalance,
5576
+ balance: newBalanceNum.toFixed(8),
5577
+ valueUsd: newBalanceNum * (parseFloat(currentBalance.priceUsd) || 0),
5578
+ updated: Date.now(),
5579
+ optimistic: true,
5580
+ previousBalance: currentBalanceNum
5581
+ };
5582
+ this.balances[balanceIndex] = updatedBalance;
5583
+ console.log(tag6, "✅ Balance updated:", {
5584
+ previous: currentBalanceNum.toFixed(8),
5585
+ new: newBalanceNum.toFixed(8),
5586
+ deducted: totalDebit.toFixed(8)
5587
+ });
5588
+ this.events.emit("BALANCES_UPDATED", this.balances);
5589
+ this.events.emit("SET_BALANCES", this.balances);
5590
+ try {
5591
+ this.dashboard = this.buildDashboardFromBalances();
5592
+ this.events.emit("SET_DASHBOARD", this.dashboard);
5593
+ console.log(tag6, "✅ Dashboard rebuilt with updated balance");
5594
+ } catch (dashboardError) {
5595
+ console.error(tag6, "Error rebuilding dashboard:", dashboardError);
5596
+ }
5597
+ return updatedBalance;
5598
+ };
5485
5599
  this.swap = async function(swapPayload) {
5486
5600
  let tag6 = `${TAG12} | swap | `;
5487
5601
  try {
@@ -5947,6 +6061,14 @@ class SDK {
5947
6061
  const assetQuery = [];
5948
6062
  for (const networkId of networkIds) {
5949
6063
  const pubkeys = findPubkeysForNetwork(this.pubkeys, networkId, this.paths, tag6);
6064
+ console.log(`\uD83D\uDD0D [DIAGNOSTIC] ${networkId}: Found ${pubkeys.length} pubkeys`);
6065
+ if (networkId.startsWith("bip122:000000000019")) {
6066
+ console.log("\uD83D\uDD0D [BITCOIN DIAGNOSTIC] Bitcoin pubkeys:", pubkeys.map((p) => ({
6067
+ pubkey: p.pubkey?.substring(0, 20) + "...",
6068
+ networks: p.networks,
6069
+ symbol: p.symbol
6070
+ })));
6071
+ }
5950
6072
  const caip = await networkIdToCaip2(networkId);
5951
6073
  assetQuery.push(...buildAssetQuery(pubkeys, caip));
5952
6074
  }
@@ -5961,7 +6083,18 @@ class SDK {
5961
6083
  console.log(`⏱️ [PERF] Enriching ${marketInfo.data?.length || 0} balances...`);
5962
6084
  const balances = enrichBalancesWithAssetInfo(marketInfo.data, this.assetsMap, caipToNetworkId7);
5963
6085
  console.log(`⏱️ [PERF] Enrichment completed in ${(performance.now() - enrichStart).toFixed(0)}ms`);
5964
- this.balances = balances;
6086
+ console.log(tag6, `⚙️ Merging balances: ${balances.length} new + ${this.balances.length} existing`);
6087
+ const uniqueBalances = new Map([...this.balances, ...balances].map((balance) => [
6088
+ balance.identifier || `${balance.caip}:${balance.pubkey}`,
6089
+ balance
6090
+ ]));
6091
+ const beforeCount = [...this.balances, ...balances].length;
6092
+ this.balances = Array.from(uniqueBalances.values());
6093
+ const duplicatesRemoved = beforeCount - this.balances.length;
6094
+ if (duplicatesRemoved > 0) {
6095
+ console.log(tag6, `\uD83D\uDD27 Removed ${duplicatesRemoved} duplicate balances`);
6096
+ }
6097
+ console.log(tag6, `✅ Final balance count: ${this.balances.length} unique balances`);
5965
6098
  this.events.emit("SET_BALANCES", this.balances);
5966
6099
  const dashStart = performance.now();
5967
6100
  this.dashboard = this.buildDashboardFromBalances();
@@ -5975,16 +6108,29 @@ class SDK {
5975
6108
  throw e;
5976
6109
  }
5977
6110
  };
5978
- this.getBalances = async function(forceRefresh, caip) {
6111
+ this.getBalances = async function(forceRefreshOrOptions, caip) {
5979
6112
  const tag6 = `${TAG12} | getBalances | `;
5980
6113
  try {
5981
- if (caip) {
5982
- console.log(tag6, `\uD83C\uDFAF Refreshing single asset: ${caip}`);
5983
- const networkId = caip.split("/")[0];
5984
- console.log(tag6, `\uD83D\uDCCD Target network: ${networkId}`);
6114
+ let forceRefresh = false;
6115
+ let networkId;
6116
+ if (typeof forceRefreshOrOptions === "object") {
6117
+ networkId = forceRefreshOrOptions.networkId;
6118
+ forceRefresh = forceRefreshOrOptions.forceRefresh ?? false;
6119
+ console.log(tag6, `\uD83D\uDCCD New signature - networkId: ${networkId}, forceRefresh: ${forceRefresh}`);
6120
+ } else {
6121
+ forceRefresh = forceRefreshOrOptions ?? false;
6122
+ if (caip) {
6123
+ console.log(tag6, `\uD83C\uDFAF Old signature - Refreshing single asset: ${caip}`);
6124
+ networkId = caip.split("/")[0];
6125
+ console.log(tag6, `\uD83D\uDCCD Extracted networkId: ${networkId}`);
6126
+ }
6127
+ }
6128
+ if (networkId) {
6129
+ console.log(tag6, `\uD83C\uDFAF Refreshing specific network: ${networkId}`);
5985
6130
  const results = await this.getBalancesForNetworks([networkId], forceRefresh);
5986
- return results.filter((b2) => b2.caip === caip || b2.networkId === networkId);
6131
+ return results.filter((b2) => b2.networkId === networkId || b2.caip?.startsWith(networkId));
5987
6132
  }
6133
+ console.log(tag6, `\uD83C\uDF10 Refreshing all blockchains (${this.blockchains.length} networks)`);
5988
6134
  return await this.getBalancesForNetworks(this.blockchains, forceRefresh);
5989
6135
  } catch (e) {
5990
6136
  console.error(tag6, "Error in getBalances: ", e);
@@ -6125,7 +6271,7 @@ class SDK {
6125
6271
  "bip122:12a765e31ffd4059bada1e25190f6e98": { address: "https://blockchair.com/litecoin/address/", tx: "https://blockchair.com/litecoin/transaction/" },
6126
6272
  "bip122:00000000001a91e3dace36e2be3bf030": { address: "https://dogechain.info/address/", tx: "https://dogechain.info/tx/" },
6127
6273
  "bip122:000000000000000000651ef99cb9fcbe": { address: "https://blockchair.com/bitcoin-cash/address/", tx: "https://blockchair.com/bitcoin-cash/transaction/" },
6128
- "bip122:000007d91d1254d60e2dd1ae58038307": { address: "https://chainz.cryptoid.info/dash/address.dws?", tx: "https://chainz.cryptoid.info/dash/tx.dws?" },
6274
+ "bip122:000007d91d1254d60e2dd1ae58038307": { address: "https://explorer.dash.org/insight/address/", tx: "https://explorer.dash.org/insight/tx/" },
6129
6275
  "bip122:4da631f2ac1bed857bd968c67c913978": { address: "https://digiexplorer.info/address/", tx: "https://digiexplorer.info/tx/" },
6130
6276
  "bip122:00040fe8ec8471911baa1db1266ea15d": { address: "https://explorer.zcha.in/accounts/", tx: "https://explorer.zcha.in/transactions/" },
6131
6277
  "cosmos:cosmoshub-4": { address: "https://www.mintscan.io/cosmos/address/", tx: "https://www.mintscan.io/cosmos/tx/" },
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "author": "highlander",
3
3
  "name": "@pioneer-platform/pioneer-sdk",
4
- "version": "8.15.40",
4
+ "version": "8.15.44",
5
5
  "dependencies": {
6
6
  "@keepkey/keepkey-sdk": "^0.2.62",
7
- "@pioneer-platform/pioneer-caip": "^9.10.17",
8
- "@pioneer-platform/pioneer-client": "^9.10.23",
9
- "@pioneer-platform/pioneer-coins": "^9.11.17",
10
- "@pioneer-platform/pioneer-discovery": "^8.15.40",
11
- "@pioneer-platform/pioneer-events": "^8.12.12",
7
+ "@pioneer-platform/pioneer-caip": "^9.10.21",
8
+ "@pioneer-platform/pioneer-client": "^9.10.24",
9
+ "@pioneer-platform/pioneer-coins": "^9.11.21",
10
+ "@pioneer-platform/pioneer-discovery": "^8.15.44",
11
+ "@pioneer-platform/pioneer-events": "^8.12.13",
12
12
  "coinselect": "^3.1.13",
13
13
  "eventemitter3": "^5.0.1",
14
14
  "neotraverse": "^0.6.8",
package/src/index.ts CHANGED
@@ -128,6 +128,7 @@ export class SDK {
128
128
  public assetsMap: any;
129
129
  public dashboard: any;
130
130
  public nfts: any[];
131
+ public pendingTransactions: any[]; // Track recent/pending transactions
131
132
  public events: any;
132
133
  public pairWallet: (options: any) => Promise<any>;
133
134
  public setContext: (context: string) => Promise<{ success: boolean }>;
@@ -236,6 +237,7 @@ export class SDK {
236
237
  this.nodes = config.nodes || [];
237
238
  this.charts = ['covalent', 'zapper'];
238
239
  this.nfts = [];
240
+ this.pendingTransactions = []; // Initialize empty pending transactions array
239
241
  this.isPioneer = null;
240
242
  this.pioneer = null;
241
243
  this.context = '';
@@ -814,6 +816,46 @@ export class SDK {
814
816
  let txManager = new TransactionManager(transactionDependencies, this.events);
815
817
  let unsignedTx = await txManager.transfer(sendPayload);
816
818
  console.log(tag, 'unsignedTx: ', unsignedTx);
819
+
820
+ // CRITICAL: Store transaction details in assetContext for optimistic balance update
821
+ // These will be used by broadcastTx to debit the balance immediately
822
+ if (this.assetContext && sendPayload) {
823
+ this.assetContext.sendAmount = sendPayload.amount;
824
+ this.assetContext.sendTo = sendPayload.to;
825
+ this.assetContext.sendMemo = sendPayload.memo;
826
+
827
+ // Extract fee from unsignedTx if available
828
+ // Different chains have different fee structures
829
+ let estimatedFee = '0';
830
+ if (unsignedTx) {
831
+ // UTXO chains
832
+ if (unsignedTx.fee) {
833
+ estimatedFee = typeof unsignedTx.fee === 'string'
834
+ ? unsignedTx.fee
835
+ : unsignedTx.fee.toString();
836
+ }
837
+ // EVM chains
838
+ else if (unsignedTx.gasPrice && unsignedTx.gasLimit) {
839
+ const gasPrice = parseFloat(unsignedTx.gasPrice);
840
+ const gasLimit = parseFloat(unsignedTx.gasLimit);
841
+ // Convert from gwei to native token (rough estimate)
842
+ estimatedFee = ((gasPrice * gasLimit) / 1000000000).toFixed(8);
843
+ }
844
+ // Tendermint chains
845
+ else if (unsignedTx.fee && unsignedTx.fee.amount && Array.isArray(unsignedTx.fee.amount)) {
846
+ estimatedFee = unsignedTx.fee.amount[0]?.amount || '0';
847
+ }
848
+ }
849
+
850
+ this.assetContext.sendFee = estimatedFee;
851
+
852
+ console.log(tag, '💾 Stored transaction details for optimistic update:', {
853
+ amount: this.assetContext.sendAmount,
854
+ fee: this.assetContext.sendFee,
855
+ to: this.assetContext.sendTo
856
+ });
857
+ }
858
+
817
859
  return unsignedTx;
818
860
  } catch (e) {
819
861
  console.error(e);
@@ -943,12 +985,149 @@ export class SDK {
943
985
  serialized: signedTx,
944
986
  };
945
987
  let txid = await txManager.broadcast(payload);
988
+
989
+ // OPTIMISTIC UPDATE: Debit balance immediately after successful broadcast
990
+ if (txid && !txid.error) {
991
+ // Extract transaction details from assetContext (set during buildTx)
992
+ const amount = this.assetContext?.sendAmount || '0';
993
+ const fee = this.assetContext?.sendFee || '0';
994
+ const to = this.assetContext?.sendTo || '';
995
+ const from = this.pubkeyContext?.address || this.pubkeyContext?.master || '';
996
+
997
+ // Only perform optimistic update if we have valid transaction details
998
+ if (amount !== '0' && parseFloat(amount) > 0) {
999
+ console.log(tag, '💰 Performing optimistic balance update:', {
1000
+ caip,
1001
+ amount,
1002
+ fee,
1003
+ from,
1004
+ to
1005
+ });
1006
+
1007
+ // Debit the balance optimistically
1008
+ this.debitBalance(caip, amount, fee);
1009
+
1010
+ // Track pending transaction
1011
+ this.addPendingTransaction({
1012
+ txid,
1013
+ caip,
1014
+ amount,
1015
+ to,
1016
+ from,
1017
+ fee,
1018
+ broadcastTime: Date.now(),
1019
+ status: 'pending'
1020
+ });
1021
+ }
1022
+ }
1023
+
946
1024
  return txid;
947
1025
  } catch (e) {
948
1026
  console.error(e);
949
1027
  throw e;
950
1028
  }
951
1029
  };
1030
+
1031
+ // Add pending transaction to tracking array
1032
+ this.addPendingTransaction = function (txData: {
1033
+ txid: string;
1034
+ caip: string;
1035
+ amount: string;
1036
+ to: string;
1037
+ from: string;
1038
+ fee: string;
1039
+ broadcastTime: number;
1040
+ status: 'pending' | 'confirmed' | 'failed';
1041
+ }) {
1042
+ const tag = TAG + ' | addPendingTransaction | ';
1043
+ console.log(tag, 'Adding pending transaction:', txData);
1044
+
1045
+ // Add to pending transactions array (most recent first)
1046
+ this.pendingTransactions.unshift({
1047
+ ...txData,
1048
+ status: txData.status || 'pending',
1049
+ addedAt: Date.now()
1050
+ });
1051
+
1052
+ // Keep only last 50 pending transactions to avoid memory bloat
1053
+ if (this.pendingTransactions.length > 50) {
1054
+ this.pendingTransactions = this.pendingTransactions.slice(0, 50);
1055
+ }
1056
+
1057
+ // Emit events for UI updates
1058
+ this.events.emit('PENDING_TX_ADDED', txData);
1059
+ this.events.emit('PENDING_TXS_UPDATED', this.pendingTransactions);
1060
+
1061
+ console.log(tag, `Pending transactions count: ${this.pendingTransactions.length}`);
1062
+
1063
+ return txData;
1064
+ };
1065
+
1066
+ // Optimistically debit balance after broadcast (before confirmation)
1067
+ this.debitBalance = function (caip: string, amount: string, fee: string = '0') {
1068
+ const tag = TAG + ' | debitBalance | ';
1069
+ console.log(tag, 'Debiting balance:', { caip, amount, fee });
1070
+
1071
+ // Find the balance entry for this asset
1072
+ const balanceIndex = this.balances.findIndex((b: any) => b.caip === caip);
1073
+
1074
+ if (balanceIndex === -1) {
1075
+ console.warn(tag, 'Balance not found for CAIP:', caip);
1076
+ return null;
1077
+ }
1078
+
1079
+ const currentBalance = this.balances[balanceIndex];
1080
+ const currentBalanceNum = parseFloat(currentBalance.balance || '0');
1081
+ const amountNum = parseFloat(amount);
1082
+ const feeNum = parseFloat(fee);
1083
+ const totalDebit = amountNum + feeNum;
1084
+
1085
+ // Calculate new balance
1086
+ const newBalanceNum = currentBalanceNum - totalDebit;
1087
+
1088
+ // Safety check: don't allow negative balance
1089
+ if (newBalanceNum < 0) {
1090
+ console.warn(tag, 'Cannot debit - would result in negative balance:', {
1091
+ current: currentBalanceNum,
1092
+ debit: totalDebit,
1093
+ result: newBalanceNum
1094
+ });
1095
+ return null;
1096
+ }
1097
+
1098
+ // Update the balance with optimistic flag
1099
+ const updatedBalance = {
1100
+ ...currentBalance,
1101
+ balance: newBalanceNum.toFixed(8),
1102
+ valueUsd: newBalanceNum * (parseFloat(currentBalance.priceUsd) || 0),
1103
+ updated: Date.now(),
1104
+ optimistic: true, // Mark as optimistic update (will be replaced by real data on next sync)
1105
+ previousBalance: currentBalanceNum // Store previous balance for rollback if needed
1106
+ };
1107
+
1108
+ this.balances[balanceIndex] = updatedBalance;
1109
+
1110
+ console.log(tag, '✅ Balance updated:', {
1111
+ previous: currentBalanceNum.toFixed(8),
1112
+ new: newBalanceNum.toFixed(8),
1113
+ deducted: totalDebit.toFixed(8)
1114
+ });
1115
+
1116
+ // Emit balance update events
1117
+ this.events.emit('BALANCES_UPDATED', this.balances);
1118
+ this.events.emit('SET_BALANCES', this.balances);
1119
+
1120
+ // Rebuild dashboard with updated balances
1121
+ try {
1122
+ this.dashboard = this.buildDashboardFromBalances();
1123
+ this.events.emit('SET_DASHBOARD', this.dashboard);
1124
+ console.log(tag, '✅ Dashboard rebuilt with updated balance');
1125
+ } catch (dashboardError) {
1126
+ console.error(tag, 'Error rebuilding dashboard:', dashboardError);
1127
+ }
1128
+
1129
+ return updatedBalance;
1130
+ };
952
1131
  this.swap = async function (swapPayload) {
953
1132
  let tag = `${TAG} | swap | `;
954
1133
  try {
@@ -1622,6 +1801,14 @@ export class SDK {
1622
1801
  const assetQuery: { caip: string; pubkey: string }[] = [];
1623
1802
  for (const networkId of networkIds) {
1624
1803
  const pubkeys = findPubkeysForNetwork(this.pubkeys, networkId, this.paths, tag);
1804
+ console.log(`🔍 [DIAGNOSTIC] ${networkId}: Found ${pubkeys.length} pubkeys`);
1805
+ if (networkId.startsWith('bip122:000000000019')) {
1806
+ console.log('🔍 [BITCOIN DIAGNOSTIC] Bitcoin pubkeys:', pubkeys.map((p: any) => ({
1807
+ pubkey: p.pubkey?.substring(0, 20) + '...',
1808
+ networks: p.networks,
1809
+ symbol: p.symbol
1810
+ })));
1811
+ }
1625
1812
  const caip = await networkIdToCaip(networkId);
1626
1813
  assetQuery.push(...buildAssetQuery(pubkeys, caip));
1627
1814
  }
@@ -1653,8 +1840,30 @@ export class SDK {
1653
1840
 
1654
1841
  console.log(`⏱️ [PERF] Enrichment completed in ${(performance.now() - enrichStart).toFixed(0)}ms`);
1655
1842
 
1656
- // Update state and emit events
1657
- this.balances = balances;
1843
+ // CRITICAL: Deduplicate balances BEFORE setting
1844
+ // Merge new balances with existing balances, deduplicating by identifier (caip:pubkey)
1845
+ console.log(tag, `⚙️ Merging balances: ${balances.length} new + ${this.balances.length} existing`);
1846
+
1847
+ // Create a Map with identifier as key to deduplicate
1848
+ // Put NEW balances LAST so they override stale cached data
1849
+ const uniqueBalances = new Map(
1850
+ [...this.balances, ...balances].map((balance: any) => [
1851
+ balance.identifier || `${balance.caip}:${balance.pubkey}`,
1852
+ balance
1853
+ ])
1854
+ );
1855
+
1856
+ const beforeCount = [...this.balances, ...balances].length;
1857
+ this.balances = Array.from(uniqueBalances.values());
1858
+ const duplicatesRemoved = beforeCount - this.balances.length;
1859
+
1860
+ if (duplicatesRemoved > 0) {
1861
+ console.log(tag, `🔧 Removed ${duplicatesRemoved} duplicate balances`);
1862
+ }
1863
+
1864
+ console.log(tag, `✅ Final balance count: ${this.balances.length} unique balances`);
1865
+
1866
+ // Emit events
1658
1867
  this.events.emit('SET_BALANCES', this.balances);
1659
1868
 
1660
1869
  // Build and emit dashboard
@@ -1672,20 +1881,41 @@ export class SDK {
1672
1881
  throw e;
1673
1882
  }
1674
1883
  };
1675
- this.getBalances = async function (forceRefresh?: boolean, caip?: string) {
1884
+ this.getBalances = async function (
1885
+ forceRefreshOrOptions?: boolean | { networkId?: string; forceRefresh?: boolean },
1886
+ caip?: string
1887
+ ) {
1676
1888
  const tag = `${TAG} | getBalances | `;
1677
1889
  try {
1678
- // If CAIP is provided, refresh only that specific asset
1679
- if (caip) {
1680
- console.log(tag, `🎯 Refreshing single asset: ${caip}`);
1681
- const networkId = caip.split('/')[0];
1682
- console.log(tag, `📍 Target network: ${networkId}`);
1890
+ // Parse parameters - support both old and new signatures
1891
+ let forceRefresh = false;
1892
+ let networkId: string | undefined;
1893
+
1894
+ if (typeof forceRefreshOrOptions === 'object') {
1895
+ // New signature: getBalances({ networkId, forceRefresh })
1896
+ networkId = forceRefreshOrOptions.networkId;
1897
+ forceRefresh = forceRefreshOrOptions.forceRefresh ?? false;
1898
+ console.log(tag, `📍 New signature - networkId: ${networkId}, forceRefresh: ${forceRefresh}`);
1899
+ } else {
1900
+ // Old signature: getBalances(forceRefresh, caip)
1901
+ forceRefresh = forceRefreshOrOptions ?? false;
1902
+
1903
+ if (caip) {
1904
+ console.log(tag, `🎯 Old signature - Refreshing single asset: ${caip}`);
1905
+ networkId = caip.split('/')[0];
1906
+ console.log(tag, `📍 Extracted networkId: ${networkId}`);
1907
+ }
1908
+ }
1683
1909
 
1910
+ // If networkId is provided, refresh only that network
1911
+ if (networkId) {
1912
+ console.log(tag, `🎯 Refreshing specific network: ${networkId}`);
1684
1913
  const results = await this.getBalancesForNetworks([networkId], forceRefresh);
1685
- return results.filter((b) => b.caip === caip || b.networkId === networkId);
1914
+ return results.filter((b) => b.networkId === networkId || b.caip?.startsWith(networkId));
1686
1915
  }
1687
1916
 
1688
1917
  // Default: refresh all blockchains
1918
+ console.log(tag, `🌐 Refreshing all blockchains (${this.blockchains.length} networks)`);
1689
1919
  return await this.getBalancesForNetworks(this.blockchains, forceRefresh);
1690
1920
  } catch (e) {
1691
1921
  console.error(tag, 'Error in getBalances: ', e);
@@ -1881,7 +2111,7 @@ export class SDK {
1881
2111
  'bip122:12a765e31ffd4059bada1e25190f6e98': { address: 'https://blockchair.com/litecoin/address/', tx: 'https://blockchair.com/litecoin/transaction/' },
1882
2112
  'bip122:00000000001a91e3dace36e2be3bf030': { address: 'https://dogechain.info/address/', tx: 'https://dogechain.info/tx/' },
1883
2113
  'bip122:000000000000000000651ef99cb9fcbe': { address: 'https://blockchair.com/bitcoin-cash/address/', tx: 'https://blockchair.com/bitcoin-cash/transaction/' },
1884
- 'bip122:000007d91d1254d60e2dd1ae58038307': { address: 'https://chainz.cryptoid.info/dash/address.dws?', tx: 'https://chainz.cryptoid.info/dash/tx.dws?' },
2114
+ 'bip122:000007d91d1254d60e2dd1ae58038307': { address: 'https://explorer.dash.org/insight/address/', tx: 'https://explorer.dash.org/insight/tx/' },
1885
2115
  'bip122:4da631f2ac1bed857bd968c67c913978': { address: 'https://digiexplorer.info/address/', tx: 'https://digiexplorer.info/tx/' },
1886
2116
  'bip122:00040fe8ec8471911baa1db1266ea15d': { address: 'https://explorer.zcha.in/accounts/', tx: 'https://explorer.zcha.in/transactions/' },
1887
2117
  'cosmos:cosmoshub-4': { address: 'https://www.mintscan.io/cosmos/address/', tx: 'https://www.mintscan.io/cosmos/tx/' },
@@ -57,8 +57,8 @@ const EXPLORER_BASE_URLS: Record<string, { address: string; tx: string }> = {
57
57
  },
58
58
  // Dash
59
59
  'bip122:000007d91d1254d60e2dd1ae58038307': {
60
- address: 'https://chainz.cryptoid.info/dash/address.dws?',
61
- tx: 'https://chainz.cryptoid.info/dash/tx.dws?'
60
+ address: 'https://explorer.dash.org/insight/address/',
61
+ tx: 'https://explorer.dash.org/insight/tx/'
62
62
  },
63
63
  // DigiByte
64
64
  'bip122:4da631f2ac1bed857bd968c67c913978': {