@trustware/sdk-staging 1.1.12-staging.6 → 1.1.12-staging.8

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
@@ -334,9 +334,107 @@ var init_bridges = __esm({
334
334
  }
335
335
  });
336
336
 
337
+ // src/wallets/chainParams.ts
338
+ function chainParamsFor(chainId) {
339
+ return registered.get(chainId) ?? BUILTIN_CHAIN_PARAMS[chainId];
340
+ }
341
+ function registerChainParams(chainId, params) {
342
+ registered.set(chainId, params);
343
+ }
344
+ function usableRpcUrls(chain) {
345
+ const candidates = [
346
+ ...Array.isArray(chain.rpcList) ? chain.rpcList : [],
347
+ ...chain.rpc ? [chain.rpc] : []
348
+ ];
349
+ const seen = /* @__PURE__ */ new Set();
350
+ const out = [];
351
+ for (const raw of candidates) {
352
+ const url = String(raw ?? "").trim();
353
+ if (!/^https?:\/\//i.test(url) || seen.has(url)) continue;
354
+ seen.add(url);
355
+ out.push(url);
356
+ }
357
+ return out;
358
+ }
359
+ function chainParamsFromChainDef(chain) {
360
+ const chainType = String(
361
+ chain.chainType ?? chain.type ?? "evm"
362
+ ).toLowerCase();
363
+ if (chainType !== "evm") return void 0;
364
+ const numericId = Number(chain.chainId ?? chain.id);
365
+ if (!Number.isSafeInteger(numericId) || numericId <= 0) return void 0;
366
+ const rpcUrls = usableRpcUrls(chain);
367
+ if (rpcUrls.length === 0) return void 0;
368
+ const native = chain.nativeCurrency;
369
+ const symbol = String(native?.symbol ?? "").trim();
370
+ if (!symbol) return void 0;
371
+ const decimals = Number(native?.decimals);
372
+ const chainName = String(
373
+ chain.networkName ?? chain.axelarChainName ?? chain.networkIdentifier ?? ""
374
+ ).trim();
375
+ const explorers = (chain.blockExplorerUrls ?? []).filter(
376
+ (u) => /^https?:\/\//i.test(String(u ?? ""))
377
+ );
378
+ return {
379
+ chainIdHex: `0x${numericId.toString(16)}`,
380
+ chainName: chainName || `Chain ${numericId}`,
381
+ rpcUrls,
382
+ nativeCurrency: {
383
+ name: String(native?.name ?? symbol),
384
+ symbol,
385
+ decimals: Number.isFinite(decimals) ? decimals : 18
386
+ },
387
+ ...explorers.length > 0 ? { blockExplorerUrls: explorers } : {}
388
+ };
389
+ }
390
+ var BUILTIN_CHAIN_PARAMS, registered;
391
+ var init_chainParams = __esm({
392
+ "src/wallets/chainParams.ts"() {
393
+ "use strict";
394
+ BUILTIN_CHAIN_PARAMS = {
395
+ 1: {
396
+ chainIdHex: "0x1",
397
+ chainName: "Ethereum",
398
+ rpcUrls: ["https://eth.llamarpc.com"],
399
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
400
+ blockExplorerUrls: ["https://etherscan.io"]
401
+ },
402
+ 137: {
403
+ chainIdHex: "0x89",
404
+ chainName: "Polygon",
405
+ rpcUrls: ["https://polygon-rpc.com"],
406
+ nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
407
+ blockExplorerUrls: ["https://polygonscan.com"]
408
+ },
409
+ 8453: {
410
+ chainIdHex: "0x2105",
411
+ chainName: "Base",
412
+ rpcUrls: ["https://mainnet.base.org"],
413
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
414
+ blockExplorerUrls: ["https://basescan.org"]
415
+ },
416
+ 42161: {
417
+ chainIdHex: "0xa4b1",
418
+ chainName: "Arbitrum One",
419
+ rpcUrls: ["https://arb1.arbitrum.io/rpc"],
420
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
421
+ blockExplorerUrls: ["https://arbiscan.io"]
422
+ },
423
+ 43114: {
424
+ chainIdHex: "0xa86a",
425
+ chainName: "Avalanche C-Chain",
426
+ rpcUrls: ["https://api.avax.network/ext/bc/C/rpc"],
427
+ nativeCurrency: { name: "Avalanche", symbol: "AVAX", decimals: 18 },
428
+ blockExplorerUrls: ["https://snowtrace.io"]
429
+ }
430
+ };
431
+ registered = /* @__PURE__ */ new Map();
432
+ }
433
+ });
434
+
337
435
  // src/wallets/eipWallets.ts
338
436
  async function addThenSwitch(eth, chainId) {
339
- const p = CHAIN_PARAMS[chainId];
437
+ const p = chainParamsFor(chainId);
340
438
  if (!p) throw new Error(`Unknown chain ${chainId} (no params to add)`);
341
439
  await eth.request({ method: "wallet_addEthereumChain", params: [p] });
342
440
  await eth.request({
@@ -364,7 +462,7 @@ function useEIP1193(eth) {
364
462
  async switchChain(chainId) {
365
463
  if (switching) return;
366
464
  switching = true;
367
- const hex = CHAIN_PARAMS[chainId]?.chainIdHex ?? `0x${chainId.toString(16)}`;
465
+ const hex = chainParamsFor(chainId)?.chainIdHex ?? `0x${chainId.toString(16)}`;
368
466
  try {
369
467
  await eth.request({
370
468
  method: "wallet_switchEthereumChain",
@@ -373,7 +471,6 @@ function useEIP1193(eth) {
373
471
  } catch (e2) {
374
472
  if (e2?.code === 4902) {
375
473
  await addThenSwitch(eth, chainId);
376
- } else if (e2?.code === 4001) {
377
474
  } else {
378
475
  throw e2;
379
476
  }
@@ -415,15 +512,13 @@ function useWagmi(client) {
415
512
  const eth = globalThis.ethereum;
416
513
  if (!eth?.request) throw new Error("switchChain not available");
417
514
  try {
418
- const hex = CHAIN_PARAMS[target]?.chainIdHex ?? `0x${target.toString(16)}`;
515
+ const hex = chainParamsFor(target)?.chainIdHex ?? `0x${target.toString(16)}`;
419
516
  await eth.request({
420
517
  method: "wallet_switchEthereumChain",
421
518
  params: [{ chainId: hex }]
422
519
  });
423
520
  } catch (e2) {
424
521
  if (e2?.code === 4902) await addThenSwitch(eth, target);
425
- else if (e2?.code === 4001)
426
- ;
427
522
  else throw e2;
428
523
  }
429
524
  } finally {
@@ -464,47 +559,10 @@ function useWagmi(client) {
464
559
  sendTransaction: sendTransaction2
465
560
  };
466
561
  }
467
- var CHAIN_PARAMS;
468
562
  var init_eipWallets = __esm({
469
563
  "src/wallets/eipWallets.ts"() {
470
564
  "use strict";
471
- CHAIN_PARAMS = {
472
- 1: {
473
- chainIdHex: "0x1",
474
- chainName: "Ethereum",
475
- rpcUrls: ["https://eth.llamarpc.com"],
476
- nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
477
- blockExplorerUrls: ["https://etherscan.io"]
478
- },
479
- 137: {
480
- chainIdHex: "0x89",
481
- chainName: "Polygon",
482
- rpcUrls: ["https://polygon-rpc.com"],
483
- nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
484
- blockExplorerUrls: ["https://polygonscan.com"]
485
- },
486
- 8453: {
487
- chainIdHex: "0x2105",
488
- chainName: "Base",
489
- rpcUrls: ["https://mainnet.base.org"],
490
- nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
491
- blockExplorerUrls: ["https://basescan.org"]
492
- },
493
- 42161: {
494
- chainIdHex: "0xa4b1",
495
- chainName: "Arbitrum One",
496
- rpcUrls: ["https://arb1.arbitrum.io/rpc"],
497
- nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
498
- blockExplorerUrls: ["https://arbiscan.io"]
499
- },
500
- 43114: {
501
- chainIdHex: "0xa86a",
502
- chainName: "Avalanche C-Chain",
503
- rpcUrls: ["https://api.avax.network/ext/bc/C/rpc"],
504
- nativeCurrency: { name: "Avalanche", symbol: "AVAX", decimals: 18 },
505
- blockExplorerUrls: ["https://snowtrace.io"]
506
- }
507
- };
565
+ init_chainParams();
508
566
  }
509
567
  });
510
568
 
@@ -514,7 +572,7 @@ var init_constants = __esm({
514
572
  "src/constants.ts"() {
515
573
  "use strict";
516
574
  SDK_NAME = "@trustware/sdk";
517
- SDK_VERSION = "1.1.12-staging.6";
575
+ SDK_VERSION = "1.1.12-staging.8";
518
576
  API_ROOT = "https://bv-staging-api.trustware.io";
519
577
  GTM_ID = "GTM-TZDGNCXB";
520
578
  API_PREFIX = "/api";
@@ -4848,6 +4906,7 @@ var init_registry = __esm({
4848
4906
  "use strict";
4849
4907
  init_store();
4850
4908
  init_chains();
4909
+ init_chainParams();
4851
4910
  NATIVE = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
4852
4911
  PAGE_CACHE_TTL_MS = 5 * 60 * 1e3;
4853
4912
  PAGE_CACHE_LIMIT = 100;
@@ -4926,6 +4985,10 @@ var init_registry = __esm({
4926
4985
  for (const alias of getChainAliases(normalized)) {
4927
4986
  this._chainAliases.set(alias, canonicalKey);
4928
4987
  }
4988
+ const addParams = chainParamsFromChainDef(normalized);
4989
+ if (addParams) {
4990
+ registerChainParams(Number(normalized.chainId ?? canonical), addParams);
4991
+ }
4929
4992
  }
4930
4993
  storeTokenForAlias(chainKey, token) {
4931
4994
  const key = tokenKey(token);
@@ -5509,6 +5572,25 @@ function backendChainId(chain, fallback) {
5509
5572
  function sleep2(ms) {
5510
5573
  return new Promise((resolve) => setTimeout(resolve, ms));
5511
5574
  }
5575
+ async function ensureWalletOnChain(wallet, target) {
5576
+ if (!Number.isSafeInteger(target) || target <= 0) {
5577
+ throw new Error(`Invalid chain id: ${target}`);
5578
+ }
5579
+ if (await wallet.getChainId() === target) return;
5580
+ let switchError;
5581
+ try {
5582
+ await wallet.switchChain(target);
5583
+ } catch (e2) {
5584
+ switchError = e2;
5585
+ }
5586
+ if (await wallet.getChainId() === target) return;
5587
+ if (switchError && isUserRejected(switchError)) {
5588
+ throw switchError;
5589
+ }
5590
+ throw new Error(
5591
+ `Wallet is on the wrong network. Switch to chain ${target} and try again.`
5592
+ );
5593
+ }
5512
5594
  async function sendEvmTx(w, tx) {
5513
5595
  if (w.type === "eip1193") {
5514
5596
  const from = await w.getAddress();
@@ -5535,19 +5617,37 @@ async function sendEvmTx(w, tx) {
5535
5617
  });
5536
5618
  return response.hash;
5537
5619
  }
5538
- async function waitForTxConfirmation(chainId, txHash) {
5539
- const timeoutMs = 12e4;
5540
- const intervalMs = 2e3;
5620
+ async function waitForEvmTxConfirmation(chainId, txHash, label, options = {}) {
5621
+ const {
5622
+ readStatus = getEVMTxStatus,
5623
+ timeoutMs = 12e4,
5624
+ intervalMs = 2e3,
5625
+ notFoundGraceMs = NOT_FOUND_GRACE_MS
5626
+ } = options;
5541
5627
  const started = Date.now();
5628
+ let notFoundSince = null;
5542
5629
  while (Date.now() - started < timeoutMs) {
5543
- const status = await getEVMTxStatus({ chainId, txHash });
5630
+ const status = await readStatus({ chainId, txHash });
5544
5631
  if (status.status === "success") return;
5545
5632
  if (status.status === "reverted") {
5546
- throw new Error("Approval transaction reverted");
5633
+ throw new Error(`${label} transaction reverted`);
5634
+ }
5635
+ if (status.status === "not_found") {
5636
+ notFoundSince ?? (notFoundSince = Date.now());
5637
+ if (Date.now() - notFoundSince >= notFoundGraceMs) {
5638
+ throw new Error(
5639
+ `${label} transaction ${txHash} was not found on chain ${chainId}. It may have been sent on a different network \u2014 check your wallet's selected network and try again.`
5640
+ );
5641
+ }
5642
+ } else {
5643
+ notFoundSince = null;
5547
5644
  }
5548
5645
  await sleep2(intervalMs);
5549
5646
  }
5550
- throw new Error("Timed out waiting for approval confirmation");
5647
+ throw new Error(`Timed out waiting for ${label.toLowerCase()} confirmation`);
5648
+ }
5649
+ function waitForApprovalConfirmation(chainId, txHash, options) {
5650
+ return waitForEvmTxConfirmation(chainId, txHash, "Approval", options);
5551
5651
  }
5552
5652
  function requiredApprovalAmount(planAmountWei, routeAmountWei) {
5553
5653
  if (planAmountWei >= UNLIMITED_APPROVAL_FLOOR && routeAmountWei !== void 0 && routeAmountWei > 0n) {
@@ -5587,17 +5687,22 @@ async function ensureApprovals(w, approvals, fallbackChainId, intentId, routeAmo
5587
5687
  functionName: "approve",
5588
5688
  args: [spender, amountWei]
5589
5689
  });
5690
+ const approvalChainId = Number(chainId);
5691
+ if (!Number.isSafeInteger(approvalChainId) || approvalChainId <= 0) {
5692
+ throw new Error(`Approval has an invalid chain id: ${chainId}`);
5693
+ }
5694
+ await ensureWalletOnChain(w, approvalChainId);
5590
5695
  const hash = await sendEvmTx(w, {
5591
5696
  to: tokenAddress,
5592
5697
  data,
5593
5698
  value: 0n,
5594
- chainId: Number.isFinite(Number(chainId)) ? Number(chainId) : void 0
5699
+ chainId: approvalChainId
5595
5700
  });
5596
5701
  if (intentId) {
5597
5702
  void submitStepReceipt(intentId, stepIndex, hash).catch(() => {
5598
5703
  });
5599
5704
  }
5600
- await waitForTxConfirmation(chainId, hash);
5705
+ await waitForApprovalConfirmation(chainId, hash);
5601
5706
  }
5602
5707
  }
5603
5708
  function isUserRejected(e2) {
@@ -5624,15 +5729,14 @@ async function sendRouteTransaction(b, fallbackChainId, options) {
5624
5729
  validatedSponsorship = b.sponsorship;
5625
5730
  }
5626
5731
  }
5627
- if (Number.isFinite(target)) {
5628
- const current = await w.getChainId();
5629
- if (current !== target) {
5630
- try {
5631
- await w.switchChain(target);
5632
- } catch {
5633
- }
5634
- }
5732
+ if (!Number.isSafeInteger(target) || target <= 0) {
5733
+ throw new Error(
5734
+ `Route is missing a usable chain id (got ${String(
5735
+ txReq.chainId ?? fallbackChainId
5736
+ )}).`
5737
+ );
5635
5738
  }
5739
+ await ensureWalletOnChain(w, target);
5636
5740
  if (!validatedSponsorship && !options?.approvalsEnsured) {
5637
5741
  await ensureApprovals(
5638
5742
  w,
@@ -5738,7 +5842,7 @@ async function runTopUp(params) {
5738
5842
  }
5739
5843
  }
5740
5844
  }
5741
- var import_viem2, erc20ApproveAbi, UNLIMITED_APPROVAL_FLOOR;
5845
+ var import_viem2, erc20ApproveAbi, NOT_FOUND_GRACE_MS, UNLIMITED_APPROVAL_FLOOR;
5742
5846
  var init_tx = __esm({
5743
5847
  "src/core/tx.ts"() {
5744
5848
  "use strict";
@@ -5749,6 +5853,7 @@ var init_tx = __esm({
5749
5853
  erc20ApproveAbi = (0, import_viem2.parseAbi)([
5750
5854
  "function approve(address spender, uint256 amount) returns (bool)"
5751
5855
  ]);
5856
+ NOT_FOUND_GRACE_MS = 2e4;
5752
5857
  UNLIMITED_APPROVAL_FLOOR = 1n << 255n;
5753
5858
  }
5754
5859
  });
@@ -9819,12 +9924,32 @@ function mapWalletTokens(balances, chains, tokens) {
9819
9924
  if (!foundToken && balanceRow.category === "native") {
9820
9925
  const nativeAddress = canonicalTokenAddressForChain(
9821
9926
  chain,
9822
- getNativeTokenAddress2(chain.type),
9927
+ getNativeTokenAddress2(normalizeChainType2(chain)),
9823
9928
  tokens
9824
9929
  );
9825
9930
  const nativeKey = `${normalizeChainKey2(balanceRow.chain_id)}:${nativeAddress}`;
9826
9931
  foundToken = tokensByCanonicalKey.get(nativeKey);
9827
9932
  }
9933
+ if (!foundToken && balanceRow.category === "native") {
9934
+ const native = chain.nativeCurrency;
9935
+ const symbol = native?.symbol?.trim();
9936
+ if (symbol) {
9937
+ return [
9938
+ {
9939
+ ...balanceRow,
9940
+ symbol,
9941
+ decimals: native?.decimals ?? balanceRow.decimals ?? 18,
9942
+ name: native?.name?.trim() || symbol,
9943
+ iconUrl: chain.chainIconURI || "",
9944
+ chainId: balanceRow.chain_id,
9945
+ usdPrice: void 0,
9946
+ address: getNativeTokenAddress2(normalizeChainType2(chain)),
9947
+ chainIconURI: chain.chainIconURI || "",
9948
+ chainData: chain
9949
+ }
9950
+ ];
9951
+ }
9952
+ }
9828
9953
  if (!foundToken?.name || !foundToken.symbol || !foundToken.address) {
9829
9954
  return [];
9830
9955
  }
@@ -33774,6 +33899,35 @@ var init_useSwapRoute = __esm({
33774
33899
  }
33775
33900
  });
33776
33901
 
33902
+ // src/modes/swap/routeValue.ts
33903
+ function parseUsd(value) {
33904
+ if (value == null) return null;
33905
+ const n = parseFloat(value);
33906
+ return Number.isFinite(n) ? n : null;
33907
+ }
33908
+ function routeNetUsd(estimate) {
33909
+ if (!estimate) return null;
33910
+ const toUsd = parseUsd(estimate.toAmountUsd);
33911
+ const feesUsd = parseUsd(estimate.totalFeesUsd);
33912
+ if (toUsd == null || feesUsd == null) return null;
33913
+ return toUsd - feesUsd;
33914
+ }
33915
+ function isValueDestroying(estimate) {
33916
+ const net = routeNetUsd(estimate);
33917
+ if (net == null) return false;
33918
+ const toUsd = parseUsd(estimate?.toAmountUsd) ?? 0;
33919
+ const feesUsd = parseUsd(estimate?.totalFeesUsd) ?? 0;
33920
+ if (toUsd < USD_NOISE_FLOOR && feesUsd < USD_NOISE_FLOOR) return false;
33921
+ return net < 0;
33922
+ }
33923
+ var USD_NOISE_FLOOR;
33924
+ var init_routeValue = __esm({
33925
+ "src/modes/swap/routeValue.ts"() {
33926
+ "use strict";
33927
+ USD_NOISE_FLOOR = 5e-3;
33928
+ }
33929
+ });
33930
+
33777
33931
  // src/modes/swap/hooks/useSwapExecution.ts
33778
33932
  function normalizeTx(raw) {
33779
33933
  const r = raw;
@@ -33785,9 +33939,6 @@ function normalizeTx(raw) {
33785
33939
  toChainTxUrl: r.toChainTxUrl || r.to_chain_tx_url || void 0
33786
33940
  };
33787
33941
  }
33788
- function sleep4(ms) {
33789
- return new Promise((resolve) => setTimeout(resolve, ms));
33790
- }
33791
33942
  function isUserRejection(err) {
33792
33943
  if (!err) return false;
33793
33944
  const e2 = err;
@@ -33796,17 +33947,6 @@ function isUserRejection(err) {
33796
33947
  const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
33797
33948
  return msg.includes("user rejected") || msg.includes("user denied") || msg.includes("cancelled");
33798
33949
  }
33799
- async function waitForApprovalConfirmation(chainId, txHash) {
33800
- const started = Date.now();
33801
- while (Date.now() - started < 12e4) {
33802
- const status = await getEVMTxStatus({ chainId, txHash });
33803
- if (status.status === "success") return;
33804
- if (status.status === "reverted")
33805
- throw new Error("Approval transaction reverted");
33806
- await sleep4(2e3);
33807
- }
33808
- throw new Error("Timed out waiting for approval confirmation");
33809
- }
33810
33950
  async function requireActiveAddress(wallet, plannedFor) {
33811
33951
  if (!wallet) throw new Error("Wallet not connected. Please reconnect.");
33812
33952
  const active = await wallet.getAddress();
@@ -33970,6 +34110,12 @@ function useSwapExecution(fromChain) {
33970
34110
  onError(msg);
33971
34111
  return;
33972
34112
  }
34113
+ if (isValueDestroying(routeResult.route?.estimate)) {
34114
+ const msg = "This route now costs more in fees than it delivers. Get a new quote.";
34115
+ setState((p) => ({ ...p, txStatus: "error", errorMessage: msg }));
34116
+ onError(msg);
34117
+ return;
34118
+ }
33973
34119
  setState((p) => ({
33974
34120
  ...p,
33975
34121
  isSubmitting: true,
@@ -34111,15 +34257,10 @@ function useSwapExecution(fromChain) {
34111
34257
  throw new Error("Invalid chain ID for token approval");
34112
34258
  }
34113
34259
  const targetChain = Number(required.chainId ?? txReq.chainId);
34114
- if (Number.isFinite(targetChain)) {
34115
- const current = await wallet.getChainId();
34116
- if (current !== targetChain) {
34117
- try {
34118
- await wallet.switchChain(targetChain);
34119
- } catch {
34120
- }
34121
- }
34260
+ if (!Number.isFinite(targetChain)) {
34261
+ throw new Error("Invalid chain ID for token approval");
34122
34262
  }
34263
+ await ensureWalletOnChain(wallet, targetChain);
34123
34264
  const approveAmount = maxApproval ? BigInt(
34124
34265
  "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
34125
34266
  ) : required.amountWei;
@@ -34247,6 +34388,7 @@ var init_useSwapExecution = __esm({
34247
34388
  init_failure();
34248
34389
  init_tx();
34249
34390
  init_sdkRpc();
34391
+ init_routeValue();
34250
34392
  init_chainHelpers();
34251
34393
  FAST_POLL_MS = 1500;
34252
34394
  SLOW_POLL_MS = 2500;
@@ -34255,6 +34397,33 @@ var init_useSwapExecution = __esm({
34255
34397
  }
34256
34398
  });
34257
34399
 
34400
+ // src/modes/swap/walletBalance.ts
34401
+ function compareKey(address, chainType) {
34402
+ if (chainType) return normalizeAddress2(address, chainType);
34403
+ return HEX_ADDRESS.test(address.trim()) ? address.toLowerCase() : address.trim();
34404
+ }
34405
+ function findWalletBalanceRow(rows, token, chainId, chainType) {
34406
+ const rawAddress = token?.address;
34407
+ if (!rawAddress || !rows?.length) return void 0;
34408
+ const wantAddress = compareKey(rawAddress, chainType);
34409
+ if (!wantAddress) return void 0;
34410
+ const wantChain = chainId == null ? "" : String(chainId).trim().toLowerCase();
34411
+ return rows.find((row) => {
34412
+ if (!row?.address) return false;
34413
+ if (compareKey(row.address, chainType) !== wantAddress) return false;
34414
+ if (!wantChain) return true;
34415
+ return String(row.chainId ?? "").trim().toLowerCase() === wantChain;
34416
+ });
34417
+ }
34418
+ var HEX_ADDRESS;
34419
+ var init_walletBalance = __esm({
34420
+ "src/modes/swap/walletBalance.ts"() {
34421
+ "use strict";
34422
+ init_chainHelpers();
34423
+ HEX_ADDRESS = /^0x[0-9a-f]+$/i;
34424
+ }
34425
+ });
34426
+
34258
34427
  // src/core/forex.ts
34259
34428
  async function fetchForexRates(base2 = "USD") {
34260
34429
  let r;
@@ -36407,14 +36576,19 @@ function SwapMode({
36407
36576
  route
36408
36577
  ]);
36409
36578
  const fromBalance = (0, import_react50.useMemo)(() => {
36410
- const walletToken = fromToken;
36411
- if (!walletToken || !("balance" in walletToken)) return null;
36412
- const raw = walletToken.balance;
36579
+ if (!fromToken) return null;
36580
+ const row = findWalletBalanceRow(
36581
+ yourWalletTokens,
36582
+ fromToken,
36583
+ fromChain?.chainId,
36584
+ normalizeChainType2(fromChain)
36585
+ );
36586
+ const raw = row?.balance ?? fromToken.balance;
36413
36587
  if (!raw) return null;
36414
- const decimals = fromToken?.decimals ?? 18;
36588
+ const decimals = row?.decimals ?? fromToken?.decimals ?? 18;
36415
36589
  const n = Number(rawToDecimal(raw, decimals));
36416
36590
  return Number.isFinite(n) ? n : null;
36417
- }, [fromToken]);
36591
+ }, [fromToken, fromChain, yourWalletTokens]);
36418
36592
  const balanceUsd = fromBalance !== null && hasFromUsdPrice ? fromBalance * fromTokenPriceUSD : null;
36419
36593
  const estimatedToAmount = (0, import_react50.useMemo)(() => {
36420
36594
  if (tokenSellNum <= 0 || !hasFromUsdPrice || !hasToUsdPrice) return null;
@@ -38183,8 +38357,9 @@ function SwapMode({
38183
38357
  }
38184
38358
  ) });
38185
38359
  }
38186
- const ctaLabel = !hasTokens ? "Get started" : !hasAmount ? "Enter an amount" : insufficient ? `Insufficient ${fromToken?.symbol} balance` : !isConnected ? "Connect Wallet" : needsDestAddress && !isValidDestAddress ? `Enter ${toChain?.networkName ?? "destination"} address` : route.loading ? "Getting quote..." : "Review";
38187
- const ctaDisabled = !hasTokens || !hasAmount || insufficient || isConnected && needsDestAddress && !isValidDestAddress || route.loading;
38360
+ const feesExceedOutput = isValueDestroying(route.data?.route?.estimate);
38361
+ const ctaLabel = !hasTokens ? "Get started" : !hasAmount ? "Enter an amount" : insufficient ? `Insufficient ${fromToken?.symbol} balance` : !isConnected ? "Connect Wallet" : needsDestAddress && !isValidDestAddress ? `Enter ${toChain?.networkName ?? "destination"} address` : route.loading ? "Getting quote..." : feesExceedOutput ? "Fees exceed amount received" : "Review";
38362
+ const ctaDisabled = !hasTokens || !hasAmount || insufficient || isConnected && needsDestAddress && !isValidDestAddress || route.loading || feesExceedOutput;
38188
38363
  const ctaAction = !isConnected ? handleConnectAndReview : () => void handleReview();
38189
38364
  const showRateRow = hasTokens && exchangeRate !== null;
38190
38365
  return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(WidgetContainer, { theme: resolvedTheme, style, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
@@ -39286,35 +39461,51 @@ function SwapMode({
39286
39461
  ]
39287
39462
  }
39288
39463
  ),
39289
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { style: { padding: `${spacing[2]} ${spacing[3]} 0` }, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
39290
- "button",
39291
- {
39292
- disabled: ctaDisabled,
39293
- onClick: ctaAction,
39294
- style: mergeStyles(
39295
- {
39296
- width: "100%",
39297
- height: "3.5rem",
39298
- borderRadius: "1.5rem",
39299
- fontSize: fontSize.base,
39300
- fontWeight: fontWeight.semibold,
39301
- border: 0,
39302
- transition: "all 0.2s",
39303
- marginBottom: spacing[3]
39464
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { style: { padding: `${spacing[2]} ${spacing[3]} 0` }, children: [
39465
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
39466
+ "button",
39467
+ {
39468
+ disabled: ctaDisabled,
39469
+ onClick: ctaAction,
39470
+ style: mergeStyles(
39471
+ {
39472
+ width: "100%",
39473
+ height: "3.5rem",
39474
+ borderRadius: "1.5rem",
39475
+ fontSize: fontSize.base,
39476
+ fontWeight: fontWeight.semibold,
39477
+ border: 0,
39478
+ transition: "all 0.2s",
39479
+ marginBottom: spacing[3]
39480
+ },
39481
+ !ctaDisabled ? {
39482
+ backgroundColor: colors.primary,
39483
+ color: colors.primaryForeground,
39484
+ cursor: "pointer"
39485
+ } : {
39486
+ backgroundColor: "hsl(var(--tw-muted))",
39487
+ color: colors.mutedForeground,
39488
+ cursor: "default"
39489
+ }
39490
+ ),
39491
+ children: ctaLabel
39492
+ }
39493
+ ),
39494
+ feesExceedOutput && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
39495
+ "div",
39496
+ {
39497
+ style: {
39498
+ marginTop: `-${spacing[2]}`,
39499
+ marginBottom: spacing[3],
39500
+ fontSize: fontSize.xs,
39501
+ lineHeight: 1.4,
39502
+ color: "#f87171",
39503
+ textAlign: "center"
39304
39504
  },
39305
- !ctaDisabled ? {
39306
- backgroundColor: colors.primary,
39307
- color: colors.primaryForeground,
39308
- cursor: "pointer"
39309
- } : {
39310
- backgroundColor: "hsl(var(--tw-muted))",
39311
- color: colors.mutedForeground,
39312
- cursor: "default"
39313
- }
39314
- ),
39315
- children: ctaLabel
39316
- }
39317
- ) }),
39505
+ children: "This route costs more in fees than it delivers. Try a larger amount, or a different token or network."
39506
+ }
39507
+ )
39508
+ ] }),
39318
39509
  showRateRow && /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
39319
39510
  "div",
39320
39511
  {
@@ -40161,6 +40352,8 @@ var init_SwapMode = __esm({
40161
40352
  init_provider();
40162
40353
  init_useSwapRoute();
40163
40354
  init_useSwapExecution();
40355
+ init_routeValue();
40356
+ init_walletBalance();
40164
40357
  init_useForex();
40165
40358
  init_SwapTokenSelect();
40166
40359
  init_currency();