@rhinestone/deposit-modal 0.1.4 → 0.1.6

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
@@ -38,12 +38,17 @@ __export(index_exports, {
38
38
  getExplorerName: () => getExplorerName,
39
39
  getExplorerTxUrl: () => getExplorerTxUrl,
40
40
  getExplorerUrl: () => getExplorerUrl,
41
+ getSupportedChainIds: () => getSupportedChainIds,
42
+ getSupportedTargetTokens: () => getSupportedTargetTokens,
43
+ getSupportedTokenSymbolsForChain: () => getSupportedTokenSymbolsForChain,
41
44
  getTokenAddress: () => getTokenAddress,
42
45
  getTokenDecimals: () => getTokenDecimals,
46
+ getTokenDecimalsByAddress: () => getTokenDecimalsByAddress,
43
47
  getTokenIcon: () => getTokenIcon,
44
48
  getTokenSymbol: () => getTokenSymbol,
45
49
  getUsdcAddress: () => getUsdcAddress,
46
- getUsdcDecimals: () => getUsdcDecimals
50
+ getUsdcDecimals: () => getUsdcDecimals,
51
+ isSupportedTokenAddressForChain: () => isSupportedTokenAddressForChain
47
52
  });
48
53
  module.exports = __toCommonJS(index_exports);
49
54
 
@@ -308,13 +313,56 @@ var import_shared_configs = require("@rhinestone/shared-configs");
308
313
  var DEFAULT_BACKEND_URL = "https://v1.orchestrator.rhinestone.dev/deposit-widget";
309
314
  var DEFAULT_SIGNER_ADDRESS = "0xcc47aa2d96c35bc6aab12ffb0e2edab8042274bd";
310
315
  var NATIVE_TOKEN_ADDRESS = "0x0000000000000000000000000000000000000000";
311
- var SOURCE_CHAINS = [import_chains.base, import_chains.optimism, import_chains.arbitrum];
312
- var CHAIN_BY_ID = {
316
+ var ALL_CHAINS_BY_ID = {
317
+ [import_chains.mainnet.id]: import_chains.mainnet,
313
318
  [import_chains.base.id]: import_chains.base,
314
319
  [import_chains.optimism.id]: import_chains.optimism,
315
- [import_chains.arbitrum.id]: import_chains.arbitrum
320
+ [import_chains.arbitrum.id]: import_chains.arbitrum,
321
+ [import_chains.polygon.id]: import_chains.polygon,
322
+ [import_chains.bsc.id]: import_chains.bsc
323
+ };
324
+ var SUPPORTED_TOKEN_MATRIX = {
325
+ ETH: [import_chains.mainnet.id, import_chains.base.id, import_chains.arbitrum.id, import_chains.optimism.id, import_chains.polygon.id],
326
+ WETH: [import_chains.mainnet.id, import_chains.base.id, import_chains.arbitrum.id, import_chains.optimism.id, import_chains.polygon.id],
327
+ USDC: [import_chains.mainnet.id, import_chains.base.id, import_chains.arbitrum.id, import_chains.optimism.id, import_chains.polygon.id],
328
+ USDT: [import_chains.mainnet.id, import_chains.arbitrum.id, import_chains.polygon.id, import_chains.bsc.id]
329
+ };
330
+ var CHAIN_DISPLAY_ORDER = [
331
+ import_chains.mainnet.id,
332
+ import_chains.base.id,
333
+ import_chains.arbitrum.id,
334
+ import_chains.optimism.id,
335
+ import_chains.polygon.id,
336
+ import_chains.bsc.id
337
+ ];
338
+ var supportedChainSet = /* @__PURE__ */ new Set();
339
+ for (const chainIds of Object.values(SUPPORTED_TOKEN_MATRIX)) {
340
+ for (const chainId of chainIds) {
341
+ supportedChainSet.add(chainId);
342
+ }
343
+ }
344
+ var SUPPORTED_CHAIN_IDS = CHAIN_DISPLAY_ORDER.filter(
345
+ (chainId) => supportedChainSet.has(chainId) && Boolean(ALL_CHAINS_BY_ID[chainId])
346
+ );
347
+ var CHAIN_BY_ID = Object.fromEntries(
348
+ SUPPORTED_CHAIN_IDS.map((id) => [id, ALL_CHAINS_BY_ID[id]])
349
+ );
350
+ var SOURCE_CHAINS = SUPPORTED_CHAIN_IDS.map(
351
+ (id) => CHAIN_BY_ID[id]
352
+ );
353
+ var SUPPORTED_CHAINS = SOURCE_CHAINS;
354
+ var SUPPORTED_TOKENS_BY_CHAIN = Object.fromEntries(
355
+ SUPPORTED_CHAIN_IDS.map((chainId) => {
356
+ const symbols = Object.entries(SUPPORTED_TOKEN_MATRIX).filter(([, chainIds]) => chainIds.includes(chainId)).map(([symbol]) => symbol);
357
+ return [chainId, symbols];
358
+ })
359
+ );
360
+ var SYMBOL_ALIASES = {
361
+ USDT: ["USDT", "USDT0"]
362
+ };
363
+ var CANONICAL_SYMBOL_BY_REGISTRY_SYMBOL = {
364
+ USDT0: "USDT"
316
365
  };
317
- var SUPPORTED_CHAINS = Object.values(CHAIN_BY_ID);
318
366
  function getChainId(chain) {
319
367
  return typeof chain === "number" ? chain : chain.id;
320
368
  }
@@ -324,15 +372,32 @@ function getChainObject(chain) {
324
372
  }
325
373
  return chain;
326
374
  }
375
+ function normalizeTokenSymbol(symbol) {
376
+ const trimmed = symbol.trim();
377
+ const wrapped = trimmed.match(/\(([^)]+)\)/);
378
+ if (wrapped?.[1]) {
379
+ return wrapped[1].trim().toUpperCase();
380
+ }
381
+ const upper = trimmed.toUpperCase();
382
+ return CANONICAL_SYMBOL_BY_REGISTRY_SYMBOL[upper] ?? upper;
383
+ }
384
+ function isSymbolSupportedOnChain(symbol, chainId) {
385
+ const symbols = SUPPORTED_TOKENS_BY_CHAIN[chainId];
386
+ if (!symbols) return false;
387
+ return symbols.includes(normalizeTokenSymbol(symbol));
388
+ }
327
389
  function getTokenFromRegistry(chainId, symbol) {
328
390
  const chainEntry = import_shared_configs.chainRegistry[String(chainId)];
329
391
  if (!chainEntry) return void 0;
330
- const upperSymbol = symbol.toUpperCase();
331
- const token = chainEntry.tokens.find(
332
- (t) => t.symbol.toUpperCase() === upperSymbol
333
- );
334
- if (token) {
335
- return { address: token.address, decimals: token.decimals };
392
+ const normalized = normalizeTokenSymbol(symbol);
393
+ const candidates = SYMBOL_ALIASES[normalized] ?? [normalized];
394
+ for (const candidate of candidates) {
395
+ const token = chainEntry.tokens.find(
396
+ (t) => t.symbol.toUpperCase() === candidate
397
+ );
398
+ if (token) {
399
+ return { address: token.address, decimals: token.decimals };
400
+ }
336
401
  }
337
402
  return void 0;
338
403
  }
@@ -346,8 +411,14 @@ function getUsdcDecimals(chainId) {
346
411
  }
347
412
  function getTokenAddress(symbol, chainId) {
348
413
  if (symbol.toUpperCase() === "ETH") {
414
+ if (!isSymbolSupportedOnChain("ETH", chainId)) {
415
+ return void 0;
416
+ }
349
417
  return NATIVE_TOKEN_ADDRESS;
350
418
  }
419
+ if (!isSymbolSupportedOnChain(symbol, chainId)) {
420
+ return void 0;
421
+ }
351
422
  const token = getTokenFromRegistry(chainId, symbol);
352
423
  return token?.address;
353
424
  }
@@ -358,6 +429,61 @@ function getTokenDecimals(symbol, chainId) {
358
429
  const token = getTokenFromRegistry(chainId, symbol);
359
430
  return token?.decimals ?? 18;
360
431
  }
432
+ function getSupportedTokenSymbolsForChain(chainId) {
433
+ const symbols = SUPPORTED_TOKENS_BY_CHAIN[chainId] ?? [];
434
+ return [...symbols];
435
+ }
436
+ function getSupportedChainIds() {
437
+ return [...SUPPORTED_CHAIN_IDS];
438
+ }
439
+ function isSupportedTokenAddressForChain(token, chainId) {
440
+ const normalized = token.toLowerCase();
441
+ if (normalized === NATIVE_TOKEN_ADDRESS) {
442
+ return isSymbolSupportedOnChain("ETH", chainId);
443
+ }
444
+ const symbol = getTokenSymbol(token, chainId);
445
+ if (!symbol || symbol === "Token") return false;
446
+ if (!isSymbolSupportedOnChain(symbol, chainId)) return false;
447
+ const expected = getTokenFromRegistry(chainId, symbol);
448
+ if (!expected) return false;
449
+ return expected.address.toLowerCase() === normalized;
450
+ }
451
+ function getSupportedTargetTokens(chainId) {
452
+ const symbols = getSupportedTokenSymbolsForChain(chainId);
453
+ const options = [];
454
+ for (const symbol of symbols) {
455
+ const address = getTokenAddress(symbol, chainId);
456
+ if (!address) continue;
457
+ options.push({
458
+ symbol,
459
+ address,
460
+ decimals: getTokenDecimals(symbol, chainId)
461
+ });
462
+ }
463
+ return options;
464
+ }
465
+ function getTokenDecimalsByAddress(token, chainId) {
466
+ const normalized = token.toLowerCase();
467
+ if (normalized === NATIVE_TOKEN_ADDRESS) {
468
+ return 18;
469
+ }
470
+ if (chainId) {
471
+ const chainEntry = import_shared_configs.chainRegistry[String(chainId)];
472
+ if (chainEntry) {
473
+ const found = chainEntry.tokens.find(
474
+ (t) => t.address.toLowerCase() === normalized
475
+ );
476
+ if (found) return found.decimals;
477
+ }
478
+ }
479
+ for (const chainEntry of Object.values(import_shared_configs.chainRegistry)) {
480
+ const found = chainEntry.tokens.find(
481
+ (t) => t.address.toLowerCase() === normalized
482
+ );
483
+ if (found) return found.decimals;
484
+ }
485
+ return 18;
486
+ }
361
487
  function findChainIdForToken(address) {
362
488
  const normalized = address.toLowerCase();
363
489
  for (const [chainIdStr, chainEntry] of Object.entries(import_shared_configs.chainRegistry)) {
@@ -380,21 +506,26 @@ function getTokenSymbol(token, chainId) {
380
506
  const found = chainEntry.tokens.find(
381
507
  (t) => t.address.toLowerCase() === normalized
382
508
  );
383
- if (found) return found.symbol;
509
+ if (found)
510
+ return CANONICAL_SYMBOL_BY_REGISTRY_SYMBOL[found.symbol.toUpperCase()] ?? found.symbol;
384
511
  }
385
512
  }
386
513
  for (const chainEntry of Object.values(import_shared_configs.chainRegistry)) {
387
514
  const found = chainEntry.tokens.find(
388
515
  (t) => t.address.toLowerCase() === normalized
389
516
  );
390
- if (found) return found.symbol;
517
+ if (found)
518
+ return CANONICAL_SYMBOL_BY_REGISTRY_SYMBOL[found.symbol.toUpperCase()] ?? found.symbol;
391
519
  }
392
520
  return "Token";
393
521
  }
394
522
  var CHAIN_BADGES = {
523
+ [import_chains.mainnet.id]: { shortLabel: "ETH", color: "#627EEA", bg: "#EEF2FF" },
395
524
  [import_chains.base.id]: { shortLabel: "Base", color: "#0052FF", bg: "#E7F0FF" },
396
525
  [import_chains.optimism.id]: { shortLabel: "OP", color: "#FF0420", bg: "#FFE9EC" },
397
- [import_chains.arbitrum.id]: { shortLabel: "Arb", color: "#28A0F0", bg: "#E6F6FF" }
526
+ [import_chains.arbitrum.id]: { shortLabel: "Arb", color: "#28A0F0", bg: "#E6F6FF" },
527
+ [import_chains.polygon.id]: { shortLabel: "Matic", color: "#8247E5", bg: "#EFE7FF" },
528
+ [import_chains.bsc.id]: { shortLabel: "BSC", color: "#F3BA2F", bg: "#FFF8E0" }
398
529
  };
399
530
  function getChainName(chainId) {
400
531
  const chain = CHAIN_BY_ID[chainId];
@@ -424,9 +555,12 @@ function getExplorerName(chainId) {
424
555
  return chain?.blockExplorers?.default?.name ?? "Explorer";
425
556
  }
426
557
  var CHAIN_ICONS = {
558
+ [import_chains.mainnet.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 784.37 1277.39'%3E%3Cpolygon fill='%23627EEA' points='392.07 0 383.5 29.11 383.5 873.74 392.07 882.29 784.13 650.54'/%3E%3Cpolygon fill='%23C0CBF6' points='392.07 0 0 650.54 392.07 882.29 392.07 472.33'/%3E%3Cpolygon fill='%238EA2F2' points='392.07 956.52 387.24 962.41 387.24 1263.28 392.07 1277.38 784.37 724.89'/%3E%3Cpolygon fill='%23C0CBF6' points='392.07 1277.38 392.07 956.52 0 724.89'/%3E%3Cpolygon fill='%23627EEA' points='392.07 882.29 784.13 650.54 392.07 472.33'/%3E%3Cpolygon fill='%238EA2F2' points='0 650.54 392.07 882.29 392.07 472.33'/%3E%3C/svg%3E",
427
559
  [import_chains.base.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 111 111'%3E%3Ccircle cx='55.5' cy='55.5' r='55.5' fill='%230052FF'/%3E%3Cpath d='M54.921 93.4c20.942 0 37.92-16.978 37.92-37.921S75.863 17.558 54.92 17.558c-19.498 0-35.57 14.725-37.655 33.647h49.82v5.548h-49.82C19.351 75.675 35.423 93.4 54.921 93.4z' fill='%23fff'/%3E%3C/svg%3E",
428
560
  [import_chains.optimism.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 500 500'%3E%3Ccircle cx='250' cy='250' r='250' fill='%23FF0420'/%3E%3Cpath fill='%23fff' d='M177.1 316.4c-14.9 0-27.1-3.5-36.6-10.5-9.4-7.1-14.1-17.3-14.1-30.4 0-2.8.3-6.1.9-10.1 1.6-9 3.9-19.8 6.9-32.5 8.5-34.4 30.5-51.6 65.9-51.6 9.6 0 18.3 1.6 25.9 4.9 7.6 3.1 13.6 7.9 18 14.3 4.4 6.3 6.6 13.8 6.6 22.5 0 2.6-.3 5.9-.9 9.9-1.9 11.1-4.1 22-6.8 32.5-4.4 17.1-11.9 30-22.7 38.5-10.6 8.2-25 12.3-42.9 12.3zm2.7-27c7 0 12.9-2.1 17.8-6.2 5-4.1 8.6-10.4 10.7-19 2.9-11.8 5.1-22 6.6-30.8.5-2.6.8-5.3.8-8.1 0-11.4-5.9-17.1-17.8-17.1-7 0-13 2.1-18 6.2-4.9 4.1-8.4 10.4-10.5 19-2.3 8.4-4.5 18.6-6.8 30.8-.5 2.5-.8 5.1-.8 7.9 0 11.6 6.1 17.3 18.1 17.3zm79.5 25.2c-1.4 0-2.4-.4-3.2-1.3-.6-1-.8-2.1-.6-3.4l25.9-122c.2-1.4.9-2.5 2.1-3.4 1.1-.9 2.3-1.3 3.6-1.3H337c13.9 0 25 2.9 33.4 8.6 8.5 5.8 12.8 14.1 12.8 25 0 3.1-.4 6.4-1.1 9.8-3.1 14.4-9.4 25-19 31.9-9.4 6.9-22.3 10.3-38.7 10.3h-25.3l-8.6 41.1c-.3 1.4-.9 2.5-2.1 3.4-1.1.9-2.3 1.3-3.6 1.3h-25.5zm66.4-71.7c5.3 0 9.8-1.4 13.7-4.3 4-2.9 6.6-7 7.9-12.4.4-2.1.6-4 .6-5.6 0-3.6-1.1-6.4-3.2-8.3-2.1-2-5.8-3-10.9-3h-22.5l-7.1 33.6h21.5z'/%3E%3C/svg%3E",
429
- [import_chains.arbitrum.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2500 2500'%3E%3Crect fill='none' width='2500' height='2500'/%3E%3Cpath fill='%23213147' d='M226 760v980c0 63 33 120 88 152l849 490c54 31 121 31 175 0l849-490c54-31 88-89 88-152V760c0-63-33-120-88-152l-849-490c-54-31-121-31-175 0L314 608c-54 31-87 89-87 152z'/%3E%3Cpath fill='%2312AAFF' d='M1435 1440l-121 332c-3 9-3 19 0 29l208 571 241-139-289-793c-7-18-32-18-39 0zm243-558c-7-18-32-18-39 0l-121 332c-3 9-3 19 0 29l341 935 241-139-422-1156z'/%3E%3Cpath fill='%239DCCED' d='M1250 155c6 0 12 2 17 5l918 530c11 6 17 18 17 30v1060c0 12-7 24-17 30l-918 530c-5 3-11 5-17 5s-12-2-17-5l-918-530c-11-6-17-18-17-30V719c0-12 7-24 17-30l918-530c5-3 11-5 17-5zm0-155c-33 0-65 8-95 25L237 555c-59 34-95 96-95 164v1060c0 68 36 130 95 164l918 530c29 17 62 25 95 25s65-8 95-25l918-530c59-34 95-96 95-164V719c0-68-36-130-95-164L1344 25c-29-17-62-25-95-25z'/%3E%3Cpolygon fill='%23213147' points='642 2179 727 1947 897 2088 738 2234'/%3E%3Cpath fill='%23fff' d='M1172 644H939c-17 0-33 11-39 27L401 2039l241 139 550-1507c5-14-5-28-19-28zm408 0h-233c-17 0-33 11-39 27L738 2233l241 139 620-1701c5-14-5-28-19-28z'/%3E%3C/svg%3E"
561
+ [import_chains.arbitrum.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2500 2500'%3E%3Crect fill='none' width='2500' height='2500'/%3E%3Cpath fill='%23213147' d='M226 760v980c0 63 33 120 88 152l849 490c54 31 121 31 175 0l849-490c54-31 88-89 88-152V760c0-63-33-120-88-152l-849-490c-54-31-121-31-175 0L314 608c-54 31-87 89-87 152z'/%3E%3Cpath fill='%2312AAFF' d='M1435 1440l-121 332c-3 9-3 19 0 29l208 571 241-139-289-793c-7-18-32-18-39 0zm243-558c-7-18-32-18-39 0l-121 332c-3 9-3 19 0 29l341 935 241-139-422-1156z'/%3E%3Cpath fill='%239DCCED' d='M1250 155c6 0 12 2 17 5l918 530c11 6 17 18 17 30v1060c0 12-7 24-17 30l-918 530c-5 3-11 5-17 5s-12-2-17-5l-918-530c-11-6-17-18-17-30V719c0-12 7-24 17-30l918-530c5-3 11-5 17-5zm0-155c-33 0-65 8-95 25L237 555c-59 34-95 96-95 164v1060c0 68 36 130 95 164l918 530c29 17 62 25 95 25s65-8 95-25l918-530c59-34 95-96 95-164V719c0-68-36-130-95-164L1344 25c-29-17-62-25-95-25z'/%3E%3Cpolygon fill='%23213147' points='642 2179 727 1947 897 2088 738 2234'/%3E%3Cpath fill='%23fff' d='M1172 644H939c-17 0-33 11-39 27L401 2039l241 139 550-1507c5-14-5-28-19-28zm408 0h-233c-17 0-33 11-39 27L738 2233l241 139 620-1701c5-14-5-28-19-28z'/%3E%3C/svg%3E",
562
+ [import_chains.polygon.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 38 33'%3E%3Cpath fill='%238247E5' d='M29.6 10.1c-.4-.2-.9-.2-1.3 0l-3 1.7-2-1.2-3-1.7c-.4-.2-.9-.2-1.3 0l-3 1.7-2 1.2-3 1.7c-.4.2-.7.7-.7 1.1v3.5c0 .5.3.9.7 1.1l3 1.7 2 1.2 3 1.7c.4.2.9.2 1.3 0l3-1.7 2-1.2 3-1.7c.4-.2.7-.7.7-1.1v-3.5c0-.5-.3-.9-.7-1.1l-3-1.7 2-1.2 3-1.7c.4-.2.7-.7.7-1.1V8.4c0-.5-.3-.9-.7-1.1l-3-1.7-2-1.2-3-1.7c-.4-.2-.9-.2-1.3 0l-3 1.7-2 1.2-3 1.7c-.4.2-.7.7-.7 1.1v3.5c0 .5.3.9.7 1.1l3 1.7-2 1.2-3 1.7c-.4.2-.7.7-.7 1.1v3.5c0 .5.3.9.7 1.1l3 1.7 2 1.2 3 1.7c.4.2.9.2 1.3 0l3-1.7 2-1.2 3-1.7c.4-.2.7-.7.7-1.1v-3.5c0-.5-.3-.9-.7-1.1l-3-1.7 2-1.2 3-1.7c.4-.2.7-.7.7-1.1V11.2c0-.5-.3-.9-.7-1.1z'/%3E%3C/svg%3E",
563
+ [import_chains.bsc.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 96'%3E%3Ccircle cx='48' cy='48' r='48' fill='%23F3BA2F'/%3E%3Cpath fill='%23fff' d='M48 19.2l7.2 7.2-18 18-7.2-7.2 18-18zm18 18l7.2 7.2-18 18-7.2-7.2 18-18zM30 37.2l7.2 7.2-7.2 7.2-7.2-7.2 7.2-7.2zm36 0l7.2 7.2-7.2 7.2-7.2-7.2 7.2-7.2zm-18 18l7.2 7.2-7.2 7.2-7.2-7.2 7.2-7.2z'/%3E%3C/svg%3E"
430
564
  };
431
565
  var TOKEN_ICONS = {
432
566
  USDC: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 2000'%3E%3Cpath d='M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z' fill='%232775ca'/%3E%3Cpath d='M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z' fill='%23fff'/%3E%3Cpath d='M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zm441.67-1300c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z' fill='%23fff'/%3E%3C/svg%3E",
@@ -517,12 +651,29 @@ async function signEnableSessionWithOwner(rhinestoneAccount, sessionDetails, sig
517
651
  rhinestoneAccount.config.owners = originalOwners;
518
652
  }
519
653
  }
520
- async function getSessionDetails(rhinestoneAccount, targetChain, signerAddress, sessionSigner) {
521
- const allChains = [...SUPPORTED_CHAINS];
522
- if (!allChains.some((c) => c.id === targetChain.id)) {
523
- allChains.push(targetChain);
654
+ async function getSessionDetails(rhinestoneAccount, targetChain, signerAddress, sessionSigner, targetToken) {
655
+ const isTargetTestnet = Boolean(targetChain.testnet);
656
+ const chainsByNetworkType = SUPPORTED_CHAINS.filter(
657
+ (chain) => Boolean(chain.testnet) === isTargetTestnet
658
+ );
659
+ let selectedChains = [...chainsByNetworkType];
660
+ if (targetToken) {
661
+ const targetSymbol = getTokenSymbol(targetToken, targetChain.id).toUpperCase();
662
+ if (targetSymbol && targetSymbol !== "TOKEN") {
663
+ const chainsForToken = selectedChains.filter(
664
+ (chain) => getSupportedTokenSymbolsForChain(chain.id).includes(targetSymbol)
665
+ );
666
+ if (chainsForToken.length > 0) {
667
+ selectedChains = chainsForToken;
668
+ }
669
+ }
670
+ }
671
+ if (!selectedChains.some((c) => c.id === targetChain.id)) {
672
+ selectedChains.push(targetChain);
524
673
  }
525
- const sessions = allChains.map((chain) => buildSession(chain, signerAddress));
674
+ const sessions = selectedChains.map(
675
+ (chain) => buildSession(chain, signerAddress)
676
+ );
526
677
  const sessionDetails = await rhinestoneAccount.experimental_getSessionDetails(sessions);
527
678
  const enableSignature = sessionSigner ? await signEnableSessionWithOwner(
528
679
  rhinestoneAccount,
@@ -647,7 +798,8 @@ function SetupStep({
647
798
  account,
648
799
  targetChainObj,
649
800
  signerAddress,
650
- sessionOwner.account
801
+ sessionOwner.account,
802
+ targetToken
651
803
  );
652
804
  setState({ type: "registering" });
653
805
  await service.registerAccount({
@@ -921,16 +1073,29 @@ function normalizeOrchestratorPortfolio(data) {
921
1073
  const chainBalances = tokenData.tokenChainBalance ?? tokenData.chainBalances ?? [];
922
1074
  for (const chainBalance of chainBalances) {
923
1075
  const unlocked = chainBalance.balance?.unlocked ?? "0";
1076
+ const normalizedName = tokenData.tokenName.trim();
1077
+ const isNativeSymbol = normalizedName.toUpperCase() === "ETH" || normalizedName.toUpperCase() === "ETHER";
924
1078
  const tokenAddress = chainBalance.tokenAddress ?? extractTokenAddress(tokenData, chainBalance.chainId) ?? getTokenAddress(tokenData.tokenName, chainBalance.chainId);
925
- if (!tokenAddress) {
1079
+ const resolvedTokenAddress = isNativeSymbol ? NATIVE_TOKEN_ADDRESS : tokenAddress;
1080
+ if (!resolvedTokenAddress) {
926
1081
  continue;
927
1082
  }
1083
+ if (!isSupportedTokenAddressForChain(
1084
+ resolvedTokenAddress,
1085
+ chainBalance.chainId
1086
+ )) {
1087
+ continue;
1088
+ }
1089
+ const symbol = getTokenSymbol(resolvedTokenAddress, chainBalance.chainId);
928
1090
  tokens.push({
929
1091
  chainId: chainBalance.chainId,
930
- address: tokenAddress,
931
- symbol: tokenData.tokenName,
932
- name: tokenData.tokenName,
933
- decimals: tokenData.tokenDecimals,
1092
+ address: resolvedTokenAddress,
1093
+ symbol,
1094
+ name: symbol,
1095
+ decimals: getTokenDecimalsByAddress(
1096
+ resolvedTokenAddress,
1097
+ chainBalance.chainId
1098
+ ),
934
1099
  balance: unlocked,
935
1100
  balanceUsd: 0
936
1101
  });
@@ -946,9 +1111,6 @@ function normalizeDirectToken(token) {
946
1111
  if (!chainId) return null;
947
1112
  const symbol = extractString(token, "symbol") ?? extractString(token, "tokenSymbol") ?? extractString(token, "tokenName") ?? extractString(token, "name");
948
1113
  if (!symbol) return null;
949
- const name = extractString(token, "name") ?? extractString(token, "tokenName") ?? symbol;
950
- const decimals = extractNumber(token, "decimals") ?? extractNumber(token, "tokenDecimals");
951
- if (decimals === null) return null;
952
1114
  const balanceValue = extractString(token, "balance") ?? extractString(token, "amount") ?? extractString(token, "value") ?? extractString(token, "rawBalance") ?? extractNumber(token, "balance")?.toString() ?? extractNumber(token, "amount")?.toString() ?? extractNumber(token, "value")?.toString() ?? extractNumber(token, "rawBalance")?.toString();
953
1115
  if (!balanceValue) return null;
954
1116
  const address = extractString(token, "address") ?? extractString(token, "tokenAddress") ?? extractString(
@@ -956,13 +1118,15 @@ function normalizeDirectToken(token) {
956
1118
  "address"
957
1119
  ) ?? getTokenAddress(symbol, chainId);
958
1120
  if (!address) return null;
1121
+ const addressAsToken = address;
1122
+ if (!isSupportedTokenAddressForChain(addressAsToken, chainId)) return null;
959
1123
  const balanceUsd = extractNumber(token, "balanceUsd") ?? extractNumber(token, "usdValue") ?? extractNumber(token, "valueUsd") ?? extractNumericString(token, "balanceUsd") ?? extractNumericString(token, "usdValue") ?? extractNumericString(token, "valueUsd") ?? 0;
960
1124
  return {
961
1125
  chainId,
962
- address,
963
- symbol,
964
- name,
965
- decimals,
1126
+ address: addressAsToken,
1127
+ symbol: getTokenSymbol(addressAsToken, chainId),
1128
+ name: getTokenSymbol(addressAsToken, chainId),
1129
+ decimals: getTokenDecimalsByAddress(addressAsToken, chainId),
966
1130
  balance: balanceValue,
967
1131
  balanceUsd
968
1132
  };
@@ -1272,29 +1436,30 @@ function AssetSelectStep({
1272
1436
  }
1273
1437
  async function fetchNativeAssets(address, publicClient, existing) {
1274
1438
  const existingIds = new Set(existing.map((asset) => asset.id));
1275
- const settled = await Promise.allSettled(
1276
- SOURCE_CHAINS.map(async (chain) => {
1277
- const id = getAssetId({ chainId: chain.id, token: NATIVE_TOKEN_ADDRESS });
1278
- if (existingIds.has(id)) return null;
1279
- const balance = await publicClient.getBalance({ address });
1280
- return {
1439
+ const connectedChainId = publicClient.chain?.id;
1440
+ if (!connectedChainId) return [];
1441
+ if (!SOURCE_CHAINS.some((chain) => chain.id === connectedChainId)) return [];
1442
+ const id = getAssetId({
1443
+ chainId: connectedChainId,
1444
+ token: NATIVE_TOKEN_ADDRESS
1445
+ });
1446
+ if (existingIds.has(id)) return [];
1447
+ try {
1448
+ const balance = await publicClient.getBalance({ address });
1449
+ return [
1450
+ {
1281
1451
  id,
1282
- chainId: chain.id,
1452
+ chainId: connectedChainId,
1283
1453
  token: NATIVE_TOKEN_ADDRESS,
1284
1454
  symbol: "ETH",
1285
1455
  name: "Ethereum",
1286
1456
  decimals: 18,
1287
1457
  balance: balance.toString()
1288
- };
1289
- })
1290
- );
1291
- const results = [];
1292
- for (const r of settled) {
1293
- if (r.status === "fulfilled" && r.value !== null) {
1294
- results.push(r.value);
1295
- }
1458
+ }
1459
+ ];
1460
+ } catch {
1461
+ return [];
1296
1462
  }
1297
- return results;
1298
1463
  }
1299
1464
  function mergeAssets(existing, incoming) {
1300
1465
  if (incoming.length === 0) return existing;
@@ -2174,7 +2339,7 @@ function ProcessingStep({
2174
2339
  };
2175
2340
  const sourceSymbol = getTokenSymbol(sourceToken, sourceChain);
2176
2341
  const targetSymbol = getTokenSymbol(targetToken, targetChain);
2177
- const sourceDecimals = getTokenDecimals(sourceSymbol, sourceChain);
2342
+ const sourceDecimals = getTokenDecimalsByAddress(sourceToken, sourceChain);
2178
2343
  const formattedReceivedAmount = (() => {
2179
2344
  try {
2180
2345
  const raw = (0, import_viem6.formatUnits)(BigInt(amount), sourceDecimals);
@@ -3078,6 +3243,7 @@ function WithdrawFormStep({
3078
3243
  targetChain,
3079
3244
  targetToken,
3080
3245
  targetChains,
3246
+ targetTokenOptions,
3081
3247
  onTargetChainChange,
3082
3248
  onTargetTokenChange,
3083
3249
  switchChain,
@@ -3110,9 +3276,6 @@ function WithdrawFormStep({
3110
3276
  const targetSymbol = getTokenSymbol(targetToken, targetChain);
3111
3277
  const targetChainName = getChainName(targetChain);
3112
3278
  const isBusy = submitting || isSubmitting;
3113
- const targetTokenOptions = (0, import_react9.useMemo)(() => {
3114
- return [{ address: targetToken, symbol: targetSymbol }];
3115
- }, [targetToken, targetSymbol]);
3116
3279
  (0, import_react9.useEffect)(() => {
3117
3280
  if (chainMismatch && switchChain && !hasAttemptedSwitch.current) {
3118
3281
  hasAttemptedSwitch.current = true;
@@ -3151,9 +3314,16 @@ function WithdrawFormStep({
3151
3314
  }
3152
3315
  }
3153
3316
  }
3154
- fetchBalance();
3317
+ void fetchBalance();
3318
+ const unwatch = publicClient.watchBlockNumber({
3319
+ emitOnBegin: false,
3320
+ onBlockNumber() {
3321
+ void fetchBalance();
3322
+ }
3323
+ });
3155
3324
  return () => {
3156
3325
  active = false;
3326
+ unwatch();
3157
3327
  };
3158
3328
  }, [safeAddress, publicClient, publicClientChainId, asset]);
3159
3329
  const formattedBalance = (0, import_react9.useMemo)(() => {
@@ -3171,7 +3341,8 @@ function WithdrawFormStep({
3171
3341
  }, [balance, asset.decimals]);
3172
3342
  (0, import_react9.useEffect)(() => {
3173
3343
  if (balance === null) return;
3174
- if (asset.symbol.toUpperCase() !== "USDC") return;
3344
+ const sym = asset.symbol.toUpperCase();
3345
+ if (sym !== "USDC" && sym !== "USDT") return;
3175
3346
  try {
3176
3347
  const raw = (0, import_viem7.formatUnits)(balance, asset.decimals);
3177
3348
  const numeric = Number(raw);
@@ -3185,7 +3356,8 @@ function WithdrawFormStep({
3185
3356
  if (!amount) return null;
3186
3357
  const parsed = Number(amount);
3187
3358
  if (!Number.isFinite(parsed) || parsed <= 0) return null;
3188
- if (asset.symbol.toUpperCase() === "USDC") {
3359
+ const sym = asset.symbol.toUpperCase();
3360
+ if (sym === "USDC" || sym === "USDT") {
3189
3361
  return parsed;
3190
3362
  }
3191
3363
  return null;
@@ -3817,7 +3989,7 @@ function WithdrawFlow({
3817
3989
  const targetChainObj = (0, import_react10.useMemo)(() => CHAIN_BY_ID[targetChain], [targetChain]);
3818
3990
  const asset = (0, import_react10.useMemo)(() => {
3819
3991
  const symbol = getTokenSymbol(sourceToken, sourceChain);
3820
- const decimals = getTokenDecimals(symbol, sourceChain);
3992
+ const decimals = getTokenDecimalsByAddress(sourceToken, sourceChain);
3821
3993
  return {
3822
3994
  id: getAssetId({ chainId: sourceChain, token: sourceToken }),
3823
3995
  chainId: sourceChain,
@@ -3885,7 +4057,8 @@ function WithdrawFlow({
3885
4057
  account,
3886
4058
  targetChainObj,
3887
4059
  signerAddress,
3888
- sessionOwner.account
4060
+ sessionOwner.account,
4061
+ targetToken
3889
4062
  );
3890
4063
  await service.registerAccount({
3891
4064
  address: smartAccount,
@@ -3975,22 +4148,38 @@ function WithdrawFlow({
3975
4148
  [onWithdrawFailed]
3976
4149
  );
3977
4150
  const targetChainOptions = (0, import_react10.useMemo)(() => {
3978
- if (isSourceNative) return SOURCE_CHAINS;
3979
- return SOURCE_CHAINS.filter((chain) => Boolean(getUsdcAddress(chain.id)));
3980
- }, [isSourceNative]);
4151
+ return SOURCE_CHAINS.filter(
4152
+ (chain) => getSupportedTargetTokens(chain.id).length > 0
4153
+ );
4154
+ }, []);
4155
+ const targetTokenOptions = (0, import_react10.useMemo)(
4156
+ () => getSupportedTargetTokens(targetChain),
4157
+ [targetChain]
4158
+ );
4159
+ (0, import_react10.useEffect)(() => {
4160
+ if (targetTokenOptions.length === 0) return;
4161
+ const matches = targetTokenOptions.some(
4162
+ (option) => option.address.toLowerCase() === targetToken.toLowerCase()
4163
+ );
4164
+ if (!matches) {
4165
+ setTargetToken(targetTokenOptions[0].address);
4166
+ }
4167
+ }, [targetToken, targetTokenOptions]);
3981
4168
  const handleTargetChainChange = (0, import_react10.useCallback)(
3982
4169
  (chainId) => {
3983
4170
  setTargetChain(chainId);
3984
- if (isSourceNative) {
3985
- setTargetToken(NATIVE_TOKEN_ADDRESS);
4171
+ const options = getSupportedTargetTokens(chainId);
4172
+ if (options.length === 0) {
3986
4173
  return;
3987
4174
  }
3988
- const nextToken = getUsdcAddress(chainId);
3989
- if (nextToken) {
3990
- setTargetToken(nextToken);
3991
- }
4175
+ const currentlySupported = options.some(
4176
+ (option) => option.address.toLowerCase() === targetToken.toLowerCase()
4177
+ );
4178
+ setTargetToken(
4179
+ currentlySupported ? targetToken : options[0].address
4180
+ );
3992
4181
  },
3993
- [isSourceNative]
4182
+ [targetToken]
3994
4183
  );
3995
4184
  const handleTargetTokenChange = (0, import_react10.useCallback)((token) => {
3996
4185
  setTargetToken(token);
@@ -4018,6 +4207,7 @@ function WithdrawFlow({
4018
4207
  targetChain,
4019
4208
  targetToken,
4020
4209
  targetChains: targetChainOptions,
4210
+ targetTokenOptions,
4021
4211
  onTargetChainChange: handleTargetChainChange,
4022
4212
  onTargetTokenChange: handleTargetTokenChange,
4023
4213
  switchChain,
@@ -4272,10 +4462,15 @@ WithdrawModal.displayName = "WithdrawModal";
4272
4462
  getExplorerName,
4273
4463
  getExplorerTxUrl,
4274
4464
  getExplorerUrl,
4465
+ getSupportedChainIds,
4466
+ getSupportedTargetTokens,
4467
+ getSupportedTokenSymbolsForChain,
4275
4468
  getTokenAddress,
4276
4469
  getTokenDecimals,
4470
+ getTokenDecimalsByAddress,
4277
4471
  getTokenIcon,
4278
4472
  getTokenSymbol,
4279
4473
  getUsdcAddress,
4280
- getUsdcDecimals
4474
+ getUsdcDecimals,
4475
+ isSupportedTokenAddressForChain
4281
4476
  });
package/dist/index.d.cts CHANGED
@@ -149,15 +149,25 @@ declare namespace WithdrawModal {
149
149
  declare const DEFAULT_BACKEND_URL = "https://v1.orchestrator.rhinestone.dev/deposit-widget";
150
150
  declare const DEFAULT_SIGNER_ADDRESS: Address;
151
151
  declare const NATIVE_TOKEN_ADDRESS: Address;
152
- declare const SOURCE_CHAINS: Chain$1[];
153
152
  declare const CHAIN_BY_ID: Record<number, Chain$1>;
153
+ declare const SOURCE_CHAINS: Chain$1[];
154
154
  declare const SUPPORTED_CHAINS: Chain$1[];
155
+ type SupportedTokenOption = {
156
+ symbol: string;
157
+ address: Address;
158
+ decimals: number;
159
+ };
155
160
  declare function getChainId(chain: Chain$1 | number): number;
156
161
  declare function getChainObject(chain: Chain$1 | number): Chain$1 | undefined;
157
162
  declare function getUsdcAddress(chainId: number): Address | undefined;
158
163
  declare function getUsdcDecimals(chainId: number): number;
159
164
  declare function getTokenAddress(symbol: string, chainId: number): Address | undefined;
160
165
  declare function getTokenDecimals(symbol: string, chainId: number): number;
166
+ declare function getSupportedTokenSymbolsForChain(chainId: number): string[];
167
+ declare function getSupportedChainIds(): number[];
168
+ declare function isSupportedTokenAddressForChain(token: Address, chainId: number): boolean;
169
+ declare function getSupportedTargetTokens(chainId: number): SupportedTokenOption[];
170
+ declare function getTokenDecimalsByAddress(token: Address, chainId?: number): number;
161
171
  declare function findChainIdForToken(address: Address): number | undefined;
162
172
  declare function getTokenSymbol(token: Address, chainId?: number): string;
163
173
  declare function getChainName(chainId: number): string;
@@ -172,4 +182,4 @@ declare function getExplorerName(chainId: number): string;
172
182
  declare function getChainIcon(chainId: number): string | undefined;
173
183
  declare function getTokenIcon(symbol: string): string | undefined;
174
184
 
175
- export { type AssetOption, CHAIN_BY_ID, type ConnectedEventData, DEFAULT_BACKEND_URL, DEFAULT_SIGNER_ADDRESS, type DepositCompleteEventData, type DepositFailedEventData, DepositModal, type DepositModalBranding, type DepositModalProps, type DepositModalTheme, type DepositModalUIConfig, type DepositSubmittedEventData, type ErrorEventData, NATIVE_TOKEN_ADDRESS, SOURCE_CHAINS, SUPPORTED_CHAINS, type WithdrawCompleteEventData, type WithdrawFailedEventData, WithdrawModal, type WithdrawModalProps, type WithdrawSubmittedEventData, findChainIdForToken, getChainBadge, getChainIcon, getChainId, getChainName, getChainObject, getExplorerName, getExplorerTxUrl, getExplorerUrl, getTokenAddress, getTokenDecimals, getTokenIcon, getTokenSymbol, getUsdcAddress, getUsdcDecimals };
185
+ export { type AssetOption, CHAIN_BY_ID, type ConnectedEventData, DEFAULT_BACKEND_URL, DEFAULT_SIGNER_ADDRESS, type DepositCompleteEventData, type DepositFailedEventData, DepositModal, type DepositModalBranding, type DepositModalProps, type DepositModalTheme, type DepositModalUIConfig, type DepositSubmittedEventData, type ErrorEventData, NATIVE_TOKEN_ADDRESS, SOURCE_CHAINS, SUPPORTED_CHAINS, type WithdrawCompleteEventData, type WithdrawFailedEventData, WithdrawModal, type WithdrawModalProps, type WithdrawSubmittedEventData, findChainIdForToken, getChainBadge, getChainIcon, getChainId, getChainName, getChainObject, getExplorerName, getExplorerTxUrl, getExplorerUrl, getSupportedChainIds, getSupportedTargetTokens, getSupportedTokenSymbolsForChain, getTokenAddress, getTokenDecimals, getTokenDecimalsByAddress, getTokenIcon, getTokenSymbol, getUsdcAddress, getUsdcDecimals, isSupportedTokenAddressForChain };
package/dist/index.d.ts CHANGED
@@ -149,15 +149,25 @@ declare namespace WithdrawModal {
149
149
  declare const DEFAULT_BACKEND_URL = "https://v1.orchestrator.rhinestone.dev/deposit-widget";
150
150
  declare const DEFAULT_SIGNER_ADDRESS: Address;
151
151
  declare const NATIVE_TOKEN_ADDRESS: Address;
152
- declare const SOURCE_CHAINS: Chain$1[];
153
152
  declare const CHAIN_BY_ID: Record<number, Chain$1>;
153
+ declare const SOURCE_CHAINS: Chain$1[];
154
154
  declare const SUPPORTED_CHAINS: Chain$1[];
155
+ type SupportedTokenOption = {
156
+ symbol: string;
157
+ address: Address;
158
+ decimals: number;
159
+ };
155
160
  declare function getChainId(chain: Chain$1 | number): number;
156
161
  declare function getChainObject(chain: Chain$1 | number): Chain$1 | undefined;
157
162
  declare function getUsdcAddress(chainId: number): Address | undefined;
158
163
  declare function getUsdcDecimals(chainId: number): number;
159
164
  declare function getTokenAddress(symbol: string, chainId: number): Address | undefined;
160
165
  declare function getTokenDecimals(symbol: string, chainId: number): number;
166
+ declare function getSupportedTokenSymbolsForChain(chainId: number): string[];
167
+ declare function getSupportedChainIds(): number[];
168
+ declare function isSupportedTokenAddressForChain(token: Address, chainId: number): boolean;
169
+ declare function getSupportedTargetTokens(chainId: number): SupportedTokenOption[];
170
+ declare function getTokenDecimalsByAddress(token: Address, chainId?: number): number;
161
171
  declare function findChainIdForToken(address: Address): number | undefined;
162
172
  declare function getTokenSymbol(token: Address, chainId?: number): string;
163
173
  declare function getChainName(chainId: number): string;
@@ -172,4 +182,4 @@ declare function getExplorerName(chainId: number): string;
172
182
  declare function getChainIcon(chainId: number): string | undefined;
173
183
  declare function getTokenIcon(symbol: string): string | undefined;
174
184
 
175
- export { type AssetOption, CHAIN_BY_ID, type ConnectedEventData, DEFAULT_BACKEND_URL, DEFAULT_SIGNER_ADDRESS, type DepositCompleteEventData, type DepositFailedEventData, DepositModal, type DepositModalBranding, type DepositModalProps, type DepositModalTheme, type DepositModalUIConfig, type DepositSubmittedEventData, type ErrorEventData, NATIVE_TOKEN_ADDRESS, SOURCE_CHAINS, SUPPORTED_CHAINS, type WithdrawCompleteEventData, type WithdrawFailedEventData, WithdrawModal, type WithdrawModalProps, type WithdrawSubmittedEventData, findChainIdForToken, getChainBadge, getChainIcon, getChainId, getChainName, getChainObject, getExplorerName, getExplorerTxUrl, getExplorerUrl, getTokenAddress, getTokenDecimals, getTokenIcon, getTokenSymbol, getUsdcAddress, getUsdcDecimals };
185
+ export { type AssetOption, CHAIN_BY_ID, type ConnectedEventData, DEFAULT_BACKEND_URL, DEFAULT_SIGNER_ADDRESS, type DepositCompleteEventData, type DepositFailedEventData, DepositModal, type DepositModalBranding, type DepositModalProps, type DepositModalTheme, type DepositModalUIConfig, type DepositSubmittedEventData, type ErrorEventData, NATIVE_TOKEN_ADDRESS, SOURCE_CHAINS, SUPPORTED_CHAINS, type WithdrawCompleteEventData, type WithdrawFailedEventData, WithdrawModal, type WithdrawModalProps, type WithdrawSubmittedEventData, findChainIdForToken, getChainBadge, getChainIcon, getChainId, getChainName, getChainObject, getExplorerName, getExplorerTxUrl, getExplorerUrl, getSupportedChainIds, getSupportedTargetTokens, getSupportedTokenSymbolsForChain, getTokenAddress, getTokenDecimals, getTokenDecimalsByAddress, getTokenIcon, getTokenSymbol, getUsdcAddress, getUsdcDecimals, isSupportedTokenAddressForChain };
package/dist/index.mjs CHANGED
@@ -260,18 +260,68 @@ import { zeroAddress } from "viem";
260
260
  import { toAccount } from "viem/accounts";
261
261
 
262
262
  // src/core/constants.ts
263
- import { base, optimism, arbitrum } from "viem/chains";
263
+ import {
264
+ arbitrum,
265
+ base,
266
+ bsc,
267
+ mainnet,
268
+ optimism,
269
+ polygon
270
+ } from "viem/chains";
264
271
  import { chainRegistry } from "@rhinestone/shared-configs";
265
272
  var DEFAULT_BACKEND_URL = "https://v1.orchestrator.rhinestone.dev/deposit-widget";
266
273
  var DEFAULT_SIGNER_ADDRESS = "0xcc47aa2d96c35bc6aab12ffb0e2edab8042274bd";
267
274
  var NATIVE_TOKEN_ADDRESS = "0x0000000000000000000000000000000000000000";
268
- var SOURCE_CHAINS = [base, optimism, arbitrum];
269
- var CHAIN_BY_ID = {
275
+ var ALL_CHAINS_BY_ID = {
276
+ [mainnet.id]: mainnet,
270
277
  [base.id]: base,
271
278
  [optimism.id]: optimism,
272
- [arbitrum.id]: arbitrum
279
+ [arbitrum.id]: arbitrum,
280
+ [polygon.id]: polygon,
281
+ [bsc.id]: bsc
282
+ };
283
+ var SUPPORTED_TOKEN_MATRIX = {
284
+ ETH: [mainnet.id, base.id, arbitrum.id, optimism.id, polygon.id],
285
+ WETH: [mainnet.id, base.id, arbitrum.id, optimism.id, polygon.id],
286
+ USDC: [mainnet.id, base.id, arbitrum.id, optimism.id, polygon.id],
287
+ USDT: [mainnet.id, arbitrum.id, polygon.id, bsc.id]
288
+ };
289
+ var CHAIN_DISPLAY_ORDER = [
290
+ mainnet.id,
291
+ base.id,
292
+ arbitrum.id,
293
+ optimism.id,
294
+ polygon.id,
295
+ bsc.id
296
+ ];
297
+ var supportedChainSet = /* @__PURE__ */ new Set();
298
+ for (const chainIds of Object.values(SUPPORTED_TOKEN_MATRIX)) {
299
+ for (const chainId of chainIds) {
300
+ supportedChainSet.add(chainId);
301
+ }
302
+ }
303
+ var SUPPORTED_CHAIN_IDS = CHAIN_DISPLAY_ORDER.filter(
304
+ (chainId) => supportedChainSet.has(chainId) && Boolean(ALL_CHAINS_BY_ID[chainId])
305
+ );
306
+ var CHAIN_BY_ID = Object.fromEntries(
307
+ SUPPORTED_CHAIN_IDS.map((id) => [id, ALL_CHAINS_BY_ID[id]])
308
+ );
309
+ var SOURCE_CHAINS = SUPPORTED_CHAIN_IDS.map(
310
+ (id) => CHAIN_BY_ID[id]
311
+ );
312
+ var SUPPORTED_CHAINS = SOURCE_CHAINS;
313
+ var SUPPORTED_TOKENS_BY_CHAIN = Object.fromEntries(
314
+ SUPPORTED_CHAIN_IDS.map((chainId) => {
315
+ const symbols = Object.entries(SUPPORTED_TOKEN_MATRIX).filter(([, chainIds]) => chainIds.includes(chainId)).map(([symbol]) => symbol);
316
+ return [chainId, symbols];
317
+ })
318
+ );
319
+ var SYMBOL_ALIASES = {
320
+ USDT: ["USDT", "USDT0"]
321
+ };
322
+ var CANONICAL_SYMBOL_BY_REGISTRY_SYMBOL = {
323
+ USDT0: "USDT"
273
324
  };
274
- var SUPPORTED_CHAINS = Object.values(CHAIN_BY_ID);
275
325
  function getChainId(chain) {
276
326
  return typeof chain === "number" ? chain : chain.id;
277
327
  }
@@ -281,15 +331,32 @@ function getChainObject(chain) {
281
331
  }
282
332
  return chain;
283
333
  }
334
+ function normalizeTokenSymbol(symbol) {
335
+ const trimmed = symbol.trim();
336
+ const wrapped = trimmed.match(/\(([^)]+)\)/);
337
+ if (wrapped?.[1]) {
338
+ return wrapped[1].trim().toUpperCase();
339
+ }
340
+ const upper = trimmed.toUpperCase();
341
+ return CANONICAL_SYMBOL_BY_REGISTRY_SYMBOL[upper] ?? upper;
342
+ }
343
+ function isSymbolSupportedOnChain(symbol, chainId) {
344
+ const symbols = SUPPORTED_TOKENS_BY_CHAIN[chainId];
345
+ if (!symbols) return false;
346
+ return symbols.includes(normalizeTokenSymbol(symbol));
347
+ }
284
348
  function getTokenFromRegistry(chainId, symbol) {
285
349
  const chainEntry = chainRegistry[String(chainId)];
286
350
  if (!chainEntry) return void 0;
287
- const upperSymbol = symbol.toUpperCase();
288
- const token = chainEntry.tokens.find(
289
- (t) => t.symbol.toUpperCase() === upperSymbol
290
- );
291
- if (token) {
292
- return { address: token.address, decimals: token.decimals };
351
+ const normalized = normalizeTokenSymbol(symbol);
352
+ const candidates = SYMBOL_ALIASES[normalized] ?? [normalized];
353
+ for (const candidate of candidates) {
354
+ const token = chainEntry.tokens.find(
355
+ (t) => t.symbol.toUpperCase() === candidate
356
+ );
357
+ if (token) {
358
+ return { address: token.address, decimals: token.decimals };
359
+ }
293
360
  }
294
361
  return void 0;
295
362
  }
@@ -303,8 +370,14 @@ function getUsdcDecimals(chainId) {
303
370
  }
304
371
  function getTokenAddress(symbol, chainId) {
305
372
  if (symbol.toUpperCase() === "ETH") {
373
+ if (!isSymbolSupportedOnChain("ETH", chainId)) {
374
+ return void 0;
375
+ }
306
376
  return NATIVE_TOKEN_ADDRESS;
307
377
  }
378
+ if (!isSymbolSupportedOnChain(symbol, chainId)) {
379
+ return void 0;
380
+ }
308
381
  const token = getTokenFromRegistry(chainId, symbol);
309
382
  return token?.address;
310
383
  }
@@ -315,6 +388,61 @@ function getTokenDecimals(symbol, chainId) {
315
388
  const token = getTokenFromRegistry(chainId, symbol);
316
389
  return token?.decimals ?? 18;
317
390
  }
391
+ function getSupportedTokenSymbolsForChain(chainId) {
392
+ const symbols = SUPPORTED_TOKENS_BY_CHAIN[chainId] ?? [];
393
+ return [...symbols];
394
+ }
395
+ function getSupportedChainIds() {
396
+ return [...SUPPORTED_CHAIN_IDS];
397
+ }
398
+ function isSupportedTokenAddressForChain(token, chainId) {
399
+ const normalized = token.toLowerCase();
400
+ if (normalized === NATIVE_TOKEN_ADDRESS) {
401
+ return isSymbolSupportedOnChain("ETH", chainId);
402
+ }
403
+ const symbol = getTokenSymbol(token, chainId);
404
+ if (!symbol || symbol === "Token") return false;
405
+ if (!isSymbolSupportedOnChain(symbol, chainId)) return false;
406
+ const expected = getTokenFromRegistry(chainId, symbol);
407
+ if (!expected) return false;
408
+ return expected.address.toLowerCase() === normalized;
409
+ }
410
+ function getSupportedTargetTokens(chainId) {
411
+ const symbols = getSupportedTokenSymbolsForChain(chainId);
412
+ const options = [];
413
+ for (const symbol of symbols) {
414
+ const address = getTokenAddress(symbol, chainId);
415
+ if (!address) continue;
416
+ options.push({
417
+ symbol,
418
+ address,
419
+ decimals: getTokenDecimals(symbol, chainId)
420
+ });
421
+ }
422
+ return options;
423
+ }
424
+ function getTokenDecimalsByAddress(token, chainId) {
425
+ const normalized = token.toLowerCase();
426
+ if (normalized === NATIVE_TOKEN_ADDRESS) {
427
+ return 18;
428
+ }
429
+ if (chainId) {
430
+ const chainEntry = chainRegistry[String(chainId)];
431
+ if (chainEntry) {
432
+ const found = chainEntry.tokens.find(
433
+ (t) => t.address.toLowerCase() === normalized
434
+ );
435
+ if (found) return found.decimals;
436
+ }
437
+ }
438
+ for (const chainEntry of Object.values(chainRegistry)) {
439
+ const found = chainEntry.tokens.find(
440
+ (t) => t.address.toLowerCase() === normalized
441
+ );
442
+ if (found) return found.decimals;
443
+ }
444
+ return 18;
445
+ }
318
446
  function findChainIdForToken(address) {
319
447
  const normalized = address.toLowerCase();
320
448
  for (const [chainIdStr, chainEntry] of Object.entries(chainRegistry)) {
@@ -337,21 +465,26 @@ function getTokenSymbol(token, chainId) {
337
465
  const found = chainEntry.tokens.find(
338
466
  (t) => t.address.toLowerCase() === normalized
339
467
  );
340
- if (found) return found.symbol;
468
+ if (found)
469
+ return CANONICAL_SYMBOL_BY_REGISTRY_SYMBOL[found.symbol.toUpperCase()] ?? found.symbol;
341
470
  }
342
471
  }
343
472
  for (const chainEntry of Object.values(chainRegistry)) {
344
473
  const found = chainEntry.tokens.find(
345
474
  (t) => t.address.toLowerCase() === normalized
346
475
  );
347
- if (found) return found.symbol;
476
+ if (found)
477
+ return CANONICAL_SYMBOL_BY_REGISTRY_SYMBOL[found.symbol.toUpperCase()] ?? found.symbol;
348
478
  }
349
479
  return "Token";
350
480
  }
351
481
  var CHAIN_BADGES = {
482
+ [mainnet.id]: { shortLabel: "ETH", color: "#627EEA", bg: "#EEF2FF" },
352
483
  [base.id]: { shortLabel: "Base", color: "#0052FF", bg: "#E7F0FF" },
353
484
  [optimism.id]: { shortLabel: "OP", color: "#FF0420", bg: "#FFE9EC" },
354
- [arbitrum.id]: { shortLabel: "Arb", color: "#28A0F0", bg: "#E6F6FF" }
485
+ [arbitrum.id]: { shortLabel: "Arb", color: "#28A0F0", bg: "#E6F6FF" },
486
+ [polygon.id]: { shortLabel: "Matic", color: "#8247E5", bg: "#EFE7FF" },
487
+ [bsc.id]: { shortLabel: "BSC", color: "#F3BA2F", bg: "#FFF8E0" }
355
488
  };
356
489
  function getChainName(chainId) {
357
490
  const chain = CHAIN_BY_ID[chainId];
@@ -381,9 +514,12 @@ function getExplorerName(chainId) {
381
514
  return chain?.blockExplorers?.default?.name ?? "Explorer";
382
515
  }
383
516
  var CHAIN_ICONS = {
517
+ [mainnet.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 784.37 1277.39'%3E%3Cpolygon fill='%23627EEA' points='392.07 0 383.5 29.11 383.5 873.74 392.07 882.29 784.13 650.54'/%3E%3Cpolygon fill='%23C0CBF6' points='392.07 0 0 650.54 392.07 882.29 392.07 472.33'/%3E%3Cpolygon fill='%238EA2F2' points='392.07 956.52 387.24 962.41 387.24 1263.28 392.07 1277.38 784.37 724.89'/%3E%3Cpolygon fill='%23C0CBF6' points='392.07 1277.38 392.07 956.52 0 724.89'/%3E%3Cpolygon fill='%23627EEA' points='392.07 882.29 784.13 650.54 392.07 472.33'/%3E%3Cpolygon fill='%238EA2F2' points='0 650.54 392.07 882.29 392.07 472.33'/%3E%3C/svg%3E",
384
518
  [base.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 111 111'%3E%3Ccircle cx='55.5' cy='55.5' r='55.5' fill='%230052FF'/%3E%3Cpath d='M54.921 93.4c20.942 0 37.92-16.978 37.92-37.921S75.863 17.558 54.92 17.558c-19.498 0-35.57 14.725-37.655 33.647h49.82v5.548h-49.82C19.351 75.675 35.423 93.4 54.921 93.4z' fill='%23fff'/%3E%3C/svg%3E",
385
519
  [optimism.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 500 500'%3E%3Ccircle cx='250' cy='250' r='250' fill='%23FF0420'/%3E%3Cpath fill='%23fff' d='M177.1 316.4c-14.9 0-27.1-3.5-36.6-10.5-9.4-7.1-14.1-17.3-14.1-30.4 0-2.8.3-6.1.9-10.1 1.6-9 3.9-19.8 6.9-32.5 8.5-34.4 30.5-51.6 65.9-51.6 9.6 0 18.3 1.6 25.9 4.9 7.6 3.1 13.6 7.9 18 14.3 4.4 6.3 6.6 13.8 6.6 22.5 0 2.6-.3 5.9-.9 9.9-1.9 11.1-4.1 22-6.8 32.5-4.4 17.1-11.9 30-22.7 38.5-10.6 8.2-25 12.3-42.9 12.3zm2.7-27c7 0 12.9-2.1 17.8-6.2 5-4.1 8.6-10.4 10.7-19 2.9-11.8 5.1-22 6.6-30.8.5-2.6.8-5.3.8-8.1 0-11.4-5.9-17.1-17.8-17.1-7 0-13 2.1-18 6.2-4.9 4.1-8.4 10.4-10.5 19-2.3 8.4-4.5 18.6-6.8 30.8-.5 2.5-.8 5.1-.8 7.9 0 11.6 6.1 17.3 18.1 17.3zm79.5 25.2c-1.4 0-2.4-.4-3.2-1.3-.6-1-.8-2.1-.6-3.4l25.9-122c.2-1.4.9-2.5 2.1-3.4 1.1-.9 2.3-1.3 3.6-1.3H337c13.9 0 25 2.9 33.4 8.6 8.5 5.8 12.8 14.1 12.8 25 0 3.1-.4 6.4-1.1 9.8-3.1 14.4-9.4 25-19 31.9-9.4 6.9-22.3 10.3-38.7 10.3h-25.3l-8.6 41.1c-.3 1.4-.9 2.5-2.1 3.4-1.1.9-2.3 1.3-3.6 1.3h-25.5zm66.4-71.7c5.3 0 9.8-1.4 13.7-4.3 4-2.9 6.6-7 7.9-12.4.4-2.1.6-4 .6-5.6 0-3.6-1.1-6.4-3.2-8.3-2.1-2-5.8-3-10.9-3h-22.5l-7.1 33.6h21.5z'/%3E%3C/svg%3E",
386
- [arbitrum.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2500 2500'%3E%3Crect fill='none' width='2500' height='2500'/%3E%3Cpath fill='%23213147' d='M226 760v980c0 63 33 120 88 152l849 490c54 31 121 31 175 0l849-490c54-31 88-89 88-152V760c0-63-33-120-88-152l-849-490c-54-31-121-31-175 0L314 608c-54 31-87 89-87 152z'/%3E%3Cpath fill='%2312AAFF' d='M1435 1440l-121 332c-3 9-3 19 0 29l208 571 241-139-289-793c-7-18-32-18-39 0zm243-558c-7-18-32-18-39 0l-121 332c-3 9-3 19 0 29l341 935 241-139-422-1156z'/%3E%3Cpath fill='%239DCCED' d='M1250 155c6 0 12 2 17 5l918 530c11 6 17 18 17 30v1060c0 12-7 24-17 30l-918 530c-5 3-11 5-17 5s-12-2-17-5l-918-530c-11-6-17-18-17-30V719c0-12 7-24 17-30l918-530c5-3 11-5 17-5zm0-155c-33 0-65 8-95 25L237 555c-59 34-95 96-95 164v1060c0 68 36 130 95 164l918 530c29 17 62 25 95 25s65-8 95-25l918-530c59-34 95-96 95-164V719c0-68-36-130-95-164L1344 25c-29-17-62-25-95-25z'/%3E%3Cpolygon fill='%23213147' points='642 2179 727 1947 897 2088 738 2234'/%3E%3Cpath fill='%23fff' d='M1172 644H939c-17 0-33 11-39 27L401 2039l241 139 550-1507c5-14-5-28-19-28zm408 0h-233c-17 0-33 11-39 27L738 2233l241 139 620-1701c5-14-5-28-19-28z'/%3E%3C/svg%3E"
520
+ [arbitrum.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2500 2500'%3E%3Crect fill='none' width='2500' height='2500'/%3E%3Cpath fill='%23213147' d='M226 760v980c0 63 33 120 88 152l849 490c54 31 121 31 175 0l849-490c54-31 88-89 88-152V760c0-63-33-120-88-152l-849-490c-54-31-121-31-175 0L314 608c-54 31-87 89-87 152z'/%3E%3Cpath fill='%2312AAFF' d='M1435 1440l-121 332c-3 9-3 19 0 29l208 571 241-139-289-793c-7-18-32-18-39 0zm243-558c-7-18-32-18-39 0l-121 332c-3 9-3 19 0 29l341 935 241-139-422-1156z'/%3E%3Cpath fill='%239DCCED' d='M1250 155c6 0 12 2 17 5l918 530c11 6 17 18 17 30v1060c0 12-7 24-17 30l-918 530c-5 3-11 5-17 5s-12-2-17-5l-918-530c-11-6-17-18-17-30V719c0-12 7-24 17-30l918-530c5-3 11-5 17-5zm0-155c-33 0-65 8-95 25L237 555c-59 34-95 96-95 164v1060c0 68 36 130 95 164l918 530c29 17 62 25 95 25s65-8 95-25l918-530c59-34 95-96 95-164V719c0-68-36-130-95-164L1344 25c-29-17-62-25-95-25z'/%3E%3Cpolygon fill='%23213147' points='642 2179 727 1947 897 2088 738 2234'/%3E%3Cpath fill='%23fff' d='M1172 644H939c-17 0-33 11-39 27L401 2039l241 139 550-1507c5-14-5-28-19-28zm408 0h-233c-17 0-33 11-39 27L738 2233l241 139 620-1701c5-14-5-28-19-28z'/%3E%3C/svg%3E",
521
+ [polygon.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 38 33'%3E%3Cpath fill='%238247E5' d='M29.6 10.1c-.4-.2-.9-.2-1.3 0l-3 1.7-2-1.2-3-1.7c-.4-.2-.9-.2-1.3 0l-3 1.7-2 1.2-3 1.7c-.4.2-.7.7-.7 1.1v3.5c0 .5.3.9.7 1.1l3 1.7 2 1.2 3 1.7c.4.2.9.2 1.3 0l3-1.7 2-1.2 3-1.7c.4-.2.7-.7.7-1.1v-3.5c0-.5-.3-.9-.7-1.1l-3-1.7 2-1.2 3-1.7c.4-.2.7-.7.7-1.1V8.4c0-.5-.3-.9-.7-1.1l-3-1.7-2-1.2-3-1.7c-.4-.2-.9-.2-1.3 0l-3 1.7-2 1.2-3 1.7c-.4.2-.7.7-.7 1.1v3.5c0 .5.3.9.7 1.1l3 1.7-2 1.2-3 1.7c-.4.2-.7.7-.7 1.1v3.5c0 .5.3.9.7 1.1l3 1.7 2 1.2 3 1.7c.4.2.9.2 1.3 0l3-1.7 2-1.2 3-1.7c.4-.2.7-.7.7-1.1v-3.5c0-.5-.3-.9-.7-1.1l-3-1.7 2-1.2 3-1.7c.4-.2.7-.7.7-1.1V11.2c0-.5-.3-.9-.7-1.1z'/%3E%3C/svg%3E",
522
+ [bsc.id]: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 96'%3E%3Ccircle cx='48' cy='48' r='48' fill='%23F3BA2F'/%3E%3Cpath fill='%23fff' d='M48 19.2l7.2 7.2-18 18-7.2-7.2 18-18zm18 18l7.2 7.2-18 18-7.2-7.2 18-18zM30 37.2l7.2 7.2-7.2 7.2-7.2-7.2 7.2-7.2zm36 0l7.2 7.2-7.2 7.2-7.2-7.2 7.2-7.2zm-18 18l7.2 7.2-7.2 7.2-7.2-7.2 7.2-7.2z'/%3E%3C/svg%3E"
387
523
  };
388
524
  var TOKEN_ICONS = {
389
525
  USDC: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 2000'%3E%3Cpath d='M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z' fill='%232775ca'/%3E%3Cpath d='M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z' fill='%23fff'/%3E%3Cpath d='M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zm441.67-1300c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z' fill='%23fff'/%3E%3C/svg%3E",
@@ -474,12 +610,29 @@ async function signEnableSessionWithOwner(rhinestoneAccount, sessionDetails, sig
474
610
  rhinestoneAccount.config.owners = originalOwners;
475
611
  }
476
612
  }
477
- async function getSessionDetails(rhinestoneAccount, targetChain, signerAddress, sessionSigner) {
478
- const allChains = [...SUPPORTED_CHAINS];
479
- if (!allChains.some((c) => c.id === targetChain.id)) {
480
- allChains.push(targetChain);
613
+ async function getSessionDetails(rhinestoneAccount, targetChain, signerAddress, sessionSigner, targetToken) {
614
+ const isTargetTestnet = Boolean(targetChain.testnet);
615
+ const chainsByNetworkType = SUPPORTED_CHAINS.filter(
616
+ (chain) => Boolean(chain.testnet) === isTargetTestnet
617
+ );
618
+ let selectedChains = [...chainsByNetworkType];
619
+ if (targetToken) {
620
+ const targetSymbol = getTokenSymbol(targetToken, targetChain.id).toUpperCase();
621
+ if (targetSymbol && targetSymbol !== "TOKEN") {
622
+ const chainsForToken = selectedChains.filter(
623
+ (chain) => getSupportedTokenSymbolsForChain(chain.id).includes(targetSymbol)
624
+ );
625
+ if (chainsForToken.length > 0) {
626
+ selectedChains = chainsForToken;
627
+ }
628
+ }
629
+ }
630
+ if (!selectedChains.some((c) => c.id === targetChain.id)) {
631
+ selectedChains.push(targetChain);
481
632
  }
482
- const sessions = allChains.map((chain) => buildSession(chain, signerAddress));
633
+ const sessions = selectedChains.map(
634
+ (chain) => buildSession(chain, signerAddress)
635
+ );
483
636
  const sessionDetails = await rhinestoneAccount.experimental_getSessionDetails(sessions);
484
637
  const enableSignature = sessionSigner ? await signEnableSessionWithOwner(
485
638
  rhinestoneAccount,
@@ -607,7 +760,8 @@ function SetupStep({
607
760
  account,
608
761
  targetChainObj,
609
762
  signerAddress,
610
- sessionOwner.account
763
+ sessionOwner.account,
764
+ targetToken
611
765
  );
612
766
  setState({ type: "registering" });
613
767
  await service.registerAccount({
@@ -881,16 +1035,29 @@ function normalizeOrchestratorPortfolio(data) {
881
1035
  const chainBalances = tokenData.tokenChainBalance ?? tokenData.chainBalances ?? [];
882
1036
  for (const chainBalance of chainBalances) {
883
1037
  const unlocked = chainBalance.balance?.unlocked ?? "0";
1038
+ const normalizedName = tokenData.tokenName.trim();
1039
+ const isNativeSymbol = normalizedName.toUpperCase() === "ETH" || normalizedName.toUpperCase() === "ETHER";
884
1040
  const tokenAddress = chainBalance.tokenAddress ?? extractTokenAddress(tokenData, chainBalance.chainId) ?? getTokenAddress(tokenData.tokenName, chainBalance.chainId);
885
- if (!tokenAddress) {
1041
+ const resolvedTokenAddress = isNativeSymbol ? NATIVE_TOKEN_ADDRESS : tokenAddress;
1042
+ if (!resolvedTokenAddress) {
886
1043
  continue;
887
1044
  }
1045
+ if (!isSupportedTokenAddressForChain(
1046
+ resolvedTokenAddress,
1047
+ chainBalance.chainId
1048
+ )) {
1049
+ continue;
1050
+ }
1051
+ const symbol = getTokenSymbol(resolvedTokenAddress, chainBalance.chainId);
888
1052
  tokens.push({
889
1053
  chainId: chainBalance.chainId,
890
- address: tokenAddress,
891
- symbol: tokenData.tokenName,
892
- name: tokenData.tokenName,
893
- decimals: tokenData.tokenDecimals,
1054
+ address: resolvedTokenAddress,
1055
+ symbol,
1056
+ name: symbol,
1057
+ decimals: getTokenDecimalsByAddress(
1058
+ resolvedTokenAddress,
1059
+ chainBalance.chainId
1060
+ ),
894
1061
  balance: unlocked,
895
1062
  balanceUsd: 0
896
1063
  });
@@ -906,9 +1073,6 @@ function normalizeDirectToken(token) {
906
1073
  if (!chainId) return null;
907
1074
  const symbol = extractString(token, "symbol") ?? extractString(token, "tokenSymbol") ?? extractString(token, "tokenName") ?? extractString(token, "name");
908
1075
  if (!symbol) return null;
909
- const name = extractString(token, "name") ?? extractString(token, "tokenName") ?? symbol;
910
- const decimals = extractNumber(token, "decimals") ?? extractNumber(token, "tokenDecimals");
911
- if (decimals === null) return null;
912
1076
  const balanceValue = extractString(token, "balance") ?? extractString(token, "amount") ?? extractString(token, "value") ?? extractString(token, "rawBalance") ?? extractNumber(token, "balance")?.toString() ?? extractNumber(token, "amount")?.toString() ?? extractNumber(token, "value")?.toString() ?? extractNumber(token, "rawBalance")?.toString();
913
1077
  if (!balanceValue) return null;
914
1078
  const address = extractString(token, "address") ?? extractString(token, "tokenAddress") ?? extractString(
@@ -916,13 +1080,15 @@ function normalizeDirectToken(token) {
916
1080
  "address"
917
1081
  ) ?? getTokenAddress(symbol, chainId);
918
1082
  if (!address) return null;
1083
+ const addressAsToken = address;
1084
+ if (!isSupportedTokenAddressForChain(addressAsToken, chainId)) return null;
919
1085
  const balanceUsd = extractNumber(token, "balanceUsd") ?? extractNumber(token, "usdValue") ?? extractNumber(token, "valueUsd") ?? extractNumericString(token, "balanceUsd") ?? extractNumericString(token, "usdValue") ?? extractNumericString(token, "valueUsd") ?? 0;
920
1086
  return {
921
1087
  chainId,
922
- address,
923
- symbol,
924
- name,
925
- decimals,
1088
+ address: addressAsToken,
1089
+ symbol: getTokenSymbol(addressAsToken, chainId),
1090
+ name: getTokenSymbol(addressAsToken, chainId),
1091
+ decimals: getTokenDecimalsByAddress(addressAsToken, chainId),
926
1092
  balance: balanceValue,
927
1093
  balanceUsd
928
1094
  };
@@ -1232,29 +1398,30 @@ function AssetSelectStep({
1232
1398
  }
1233
1399
  async function fetchNativeAssets(address, publicClient, existing) {
1234
1400
  const existingIds = new Set(existing.map((asset) => asset.id));
1235
- const settled = await Promise.allSettled(
1236
- SOURCE_CHAINS.map(async (chain) => {
1237
- const id = getAssetId({ chainId: chain.id, token: NATIVE_TOKEN_ADDRESS });
1238
- if (existingIds.has(id)) return null;
1239
- const balance = await publicClient.getBalance({ address });
1240
- return {
1401
+ const connectedChainId = publicClient.chain?.id;
1402
+ if (!connectedChainId) return [];
1403
+ if (!SOURCE_CHAINS.some((chain) => chain.id === connectedChainId)) return [];
1404
+ const id = getAssetId({
1405
+ chainId: connectedChainId,
1406
+ token: NATIVE_TOKEN_ADDRESS
1407
+ });
1408
+ if (existingIds.has(id)) return [];
1409
+ try {
1410
+ const balance = await publicClient.getBalance({ address });
1411
+ return [
1412
+ {
1241
1413
  id,
1242
- chainId: chain.id,
1414
+ chainId: connectedChainId,
1243
1415
  token: NATIVE_TOKEN_ADDRESS,
1244
1416
  symbol: "ETH",
1245
1417
  name: "Ethereum",
1246
1418
  decimals: 18,
1247
1419
  balance: balance.toString()
1248
- };
1249
- })
1250
- );
1251
- const results = [];
1252
- for (const r of settled) {
1253
- if (r.status === "fulfilled" && r.value !== null) {
1254
- results.push(r.value);
1255
- }
1420
+ }
1421
+ ];
1422
+ } catch {
1423
+ return [];
1256
1424
  }
1257
- return results;
1258
1425
  }
1259
1426
  function mergeAssets(existing, incoming) {
1260
1427
  if (incoming.length === 0) return existing;
@@ -2134,7 +2301,7 @@ function ProcessingStep({
2134
2301
  };
2135
2302
  const sourceSymbol = getTokenSymbol(sourceToken, sourceChain);
2136
2303
  const targetSymbol = getTokenSymbol(targetToken, targetChain);
2137
- const sourceDecimals = getTokenDecimals(sourceSymbol, sourceChain);
2304
+ const sourceDecimals = getTokenDecimalsByAddress(sourceToken, sourceChain);
2138
2305
  const formattedReceivedAmount = (() => {
2139
2306
  try {
2140
2307
  const raw = formatUnits4(BigInt(amount), sourceDecimals);
@@ -3038,6 +3205,7 @@ function WithdrawFormStep({
3038
3205
  targetChain,
3039
3206
  targetToken,
3040
3207
  targetChains,
3208
+ targetTokenOptions,
3041
3209
  onTargetChainChange,
3042
3210
  onTargetTokenChange,
3043
3211
  switchChain,
@@ -3070,9 +3238,6 @@ function WithdrawFormStep({
3070
3238
  const targetSymbol = getTokenSymbol(targetToken, targetChain);
3071
3239
  const targetChainName = getChainName(targetChain);
3072
3240
  const isBusy = submitting || isSubmitting;
3073
- const targetTokenOptions = useMemo6(() => {
3074
- return [{ address: targetToken, symbol: targetSymbol }];
3075
- }, [targetToken, targetSymbol]);
3076
3241
  useEffect8(() => {
3077
3242
  if (chainMismatch && switchChain && !hasAttemptedSwitch.current) {
3078
3243
  hasAttemptedSwitch.current = true;
@@ -3111,9 +3276,16 @@ function WithdrawFormStep({
3111
3276
  }
3112
3277
  }
3113
3278
  }
3114
- fetchBalance();
3279
+ void fetchBalance();
3280
+ const unwatch = publicClient.watchBlockNumber({
3281
+ emitOnBegin: false,
3282
+ onBlockNumber() {
3283
+ void fetchBalance();
3284
+ }
3285
+ });
3115
3286
  return () => {
3116
3287
  active = false;
3288
+ unwatch();
3117
3289
  };
3118
3290
  }, [safeAddress, publicClient, publicClientChainId, asset]);
3119
3291
  const formattedBalance = useMemo6(() => {
@@ -3131,7 +3303,8 @@ function WithdrawFormStep({
3131
3303
  }, [balance, asset.decimals]);
3132
3304
  useEffect8(() => {
3133
3305
  if (balance === null) return;
3134
- if (asset.symbol.toUpperCase() !== "USDC") return;
3306
+ const sym = asset.symbol.toUpperCase();
3307
+ if (sym !== "USDC" && sym !== "USDT") return;
3135
3308
  try {
3136
3309
  const raw = formatUnits5(balance, asset.decimals);
3137
3310
  const numeric = Number(raw);
@@ -3145,7 +3318,8 @@ function WithdrawFormStep({
3145
3318
  if (!amount) return null;
3146
3319
  const parsed = Number(amount);
3147
3320
  if (!Number.isFinite(parsed) || parsed <= 0) return null;
3148
- if (asset.symbol.toUpperCase() === "USDC") {
3321
+ const sym = asset.symbol.toUpperCase();
3322
+ if (sym === "USDC" || sym === "USDT") {
3149
3323
  return parsed;
3150
3324
  }
3151
3325
  return null;
@@ -3785,7 +3959,7 @@ function WithdrawFlow({
3785
3959
  const targetChainObj = useMemo7(() => CHAIN_BY_ID[targetChain], [targetChain]);
3786
3960
  const asset = useMemo7(() => {
3787
3961
  const symbol = getTokenSymbol(sourceToken, sourceChain);
3788
- const decimals = getTokenDecimals(symbol, sourceChain);
3962
+ const decimals = getTokenDecimalsByAddress(sourceToken, sourceChain);
3789
3963
  return {
3790
3964
  id: getAssetId({ chainId: sourceChain, token: sourceToken }),
3791
3965
  chainId: sourceChain,
@@ -3853,7 +4027,8 @@ function WithdrawFlow({
3853
4027
  account,
3854
4028
  targetChainObj,
3855
4029
  signerAddress,
3856
- sessionOwner.account
4030
+ sessionOwner.account,
4031
+ targetToken
3857
4032
  );
3858
4033
  await service.registerAccount({
3859
4034
  address: smartAccount,
@@ -3943,22 +4118,38 @@ function WithdrawFlow({
3943
4118
  [onWithdrawFailed]
3944
4119
  );
3945
4120
  const targetChainOptions = useMemo7(() => {
3946
- if (isSourceNative) return SOURCE_CHAINS;
3947
- return SOURCE_CHAINS.filter((chain) => Boolean(getUsdcAddress(chain.id)));
3948
- }, [isSourceNative]);
4121
+ return SOURCE_CHAINS.filter(
4122
+ (chain) => getSupportedTargetTokens(chain.id).length > 0
4123
+ );
4124
+ }, []);
4125
+ const targetTokenOptions = useMemo7(
4126
+ () => getSupportedTargetTokens(targetChain),
4127
+ [targetChain]
4128
+ );
4129
+ useEffect9(() => {
4130
+ if (targetTokenOptions.length === 0) return;
4131
+ const matches = targetTokenOptions.some(
4132
+ (option) => option.address.toLowerCase() === targetToken.toLowerCase()
4133
+ );
4134
+ if (!matches) {
4135
+ setTargetToken(targetTokenOptions[0].address);
4136
+ }
4137
+ }, [targetToken, targetTokenOptions]);
3949
4138
  const handleTargetChainChange = useCallback6(
3950
4139
  (chainId) => {
3951
4140
  setTargetChain(chainId);
3952
- if (isSourceNative) {
3953
- setTargetToken(NATIVE_TOKEN_ADDRESS);
4141
+ const options = getSupportedTargetTokens(chainId);
4142
+ if (options.length === 0) {
3954
4143
  return;
3955
4144
  }
3956
- const nextToken = getUsdcAddress(chainId);
3957
- if (nextToken) {
3958
- setTargetToken(nextToken);
3959
- }
4145
+ const currentlySupported = options.some(
4146
+ (option) => option.address.toLowerCase() === targetToken.toLowerCase()
4147
+ );
4148
+ setTargetToken(
4149
+ currentlySupported ? targetToken : options[0].address
4150
+ );
3960
4151
  },
3961
- [isSourceNative]
4152
+ [targetToken]
3962
4153
  );
3963
4154
  const handleTargetTokenChange = useCallback6((token) => {
3964
4155
  setTargetToken(token);
@@ -3986,6 +4177,7 @@ function WithdrawFlow({
3986
4177
  targetChain,
3987
4178
  targetToken,
3988
4179
  targetChains: targetChainOptions,
4180
+ targetTokenOptions,
3989
4181
  onTargetChainChange: handleTargetChainChange,
3990
4182
  onTargetTokenChange: handleTargetTokenChange,
3991
4183
  switchChain,
@@ -4239,10 +4431,15 @@ export {
4239
4431
  getExplorerName,
4240
4432
  getExplorerTxUrl,
4241
4433
  getExplorerUrl,
4434
+ getSupportedChainIds,
4435
+ getSupportedTargetTokens,
4436
+ getSupportedTokenSymbolsForChain,
4242
4437
  getTokenAddress,
4243
4438
  getTokenDecimals,
4439
+ getTokenDecimalsByAddress,
4244
4440
  getTokenIcon,
4245
4441
  getTokenSymbol,
4246
4442
  getUsdcAddress,
4247
- getUsdcDecimals
4443
+ getUsdcDecimals,
4444
+ isSupportedTokenAddressForChain
4248
4445
  };
package/dist/styles.css CHANGED
@@ -1829,10 +1829,10 @@
1829
1829
  position: relative;
1830
1830
  }
1831
1831
 
1832
- /* Dropdown menu - clean popover */
1832
+ /* Dropdown menu - opens upward to avoid modal overflow clipping */
1833
1833
  .rs-withdraw-dropdown-menu {
1834
1834
  position: absolute;
1835
- top: calc(100% + 4px);
1835
+ bottom: calc(100% + 4px);
1836
1836
  left: 0;
1837
1837
  right: 0;
1838
1838
  z-index: 20;
@@ -1840,19 +1840,21 @@
1840
1840
  border: 1px solid var(--rs-border);
1841
1841
  border-radius: var(--rs-radius-sm);
1842
1842
  box-shadow:
1843
- 0 4px 12px rgba(0, 0, 0, 0.08),
1844
- 0 1px 3px rgba(0, 0, 0, 0.06);
1843
+ 0 -4px 12px rgba(0, 0, 0, 0.08),
1844
+ 0 -1px 3px rgba(0, 0, 0, 0.06);
1845
1845
  padding: 4px;
1846
1846
  display: flex;
1847
1847
  flex-direction: column;
1848
1848
  gap: 2px;
1849
+ max-height: 200px;
1850
+ overflow-y: auto;
1849
1851
  animation: rs-dropdown-in 0.12s ease-out;
1850
1852
  }
1851
1853
 
1852
1854
  @keyframes rs-dropdown-in {
1853
1855
  from {
1854
1856
  opacity: 0;
1855
- transform: translateY(-4px);
1857
+ transform: translateY(4px);
1856
1858
  }
1857
1859
  to {
1858
1860
  opacity: 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhinestone/deposit-modal",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "React modal component for Rhinestone cross-chain deposits",
5
5
  "author": "Rhinestone <dev@rhinestone.wtf>",
6
6
  "bugs": {
@@ -40,8 +40,8 @@
40
40
  "viem": ">=2.0.0"
41
41
  },
42
42
  "dependencies": {
43
- "@rhinestone/sdk": "^1.2.9",
44
- "@rhinestone/shared-configs": "^1.4.91"
43
+ "@rhinestone/sdk": "^1.2.10",
44
+ "@rhinestone/shared-configs": "^1.4.93"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/react": "^19.0.0",