@trustware/sdk-staging 1.1.9-staging.5 → 1.1.9-staging.7

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
@@ -71,6 +71,31 @@ var init_config = __esm({
71
71
  }
72
72
  });
73
73
 
74
+ // src/errors/TrustwareError.ts
75
+ var TrustwareError;
76
+ var init_TrustwareError = __esm({
77
+ "src/errors/TrustwareError.ts"() {
78
+ "use strict";
79
+ TrustwareError = class extends Error {
80
+ constructor(params) {
81
+ super(params.message);
82
+ this.name = "TrustwareError";
83
+ this.code = params.code;
84
+ this.userMessage = params.userMessage;
85
+ this.cause = params.cause;
86
+ }
87
+ toJSON() {
88
+ return {
89
+ name: this.name,
90
+ code: this.code,
91
+ message: this.message,
92
+ userMessage: this.userMessage
93
+ };
94
+ }
95
+ };
96
+ }
97
+ });
98
+
74
99
  // src/config/merge.ts
75
100
  function deepMerge(base2, patch) {
76
101
  if (!patch) return { ...base2 };
@@ -91,46 +116,80 @@ function normalizeSlippage(v) {
91
116
  if (n > 5) return 5;
92
117
  return n;
93
118
  }
119
+ function warnDeprecatedSwapModeFlag() {
120
+ if (hasWarnedDeprecatedSwapModeFlag) return;
121
+ hasWarnedDeprecatedSwapModeFlag = true;
122
+ console.warn(
123
+ '[Trustware SDK] `features.swapMode` is deprecated \u2014 use `mode: "swap"` on the top-level config instead.'
124
+ );
125
+ }
126
+ function resolveMode(input) {
127
+ if (input.mode === "swap") return "swap";
128
+ if (input.mode === "deposit") return "deposit";
129
+ if (input.features?.swapMode) {
130
+ warnDeprecatedSwapModeFlag();
131
+ return "swap";
132
+ }
133
+ return "deposit";
134
+ }
94
135
  function resolveConfig(input) {
95
136
  if (!input?.apiKey) {
96
- throw new Error("TrustwareConfig: 'apiKey' is required.");
137
+ throw new TrustwareError({
138
+ code: "INVALID_CONFIG" /* INVALID_CONFIG */,
139
+ message: "TrustwareConfig: 'apiKey' is required.",
140
+ userMessage: "Missing required API key configuration."
141
+ });
97
142
  }
98
- if (!input.routes?.toChain || !input.routes?.toToken) {
99
- throw new Error(
100
- "TrustwareConfig: 'routes.toChain' and 'routes.toToken' are required."
101
- );
143
+ const mode = resolveMode(input);
144
+ if (mode === "deposit" && (!input.routes?.toChain || !input.routes?.toToken)) {
145
+ throw new TrustwareError({
146
+ code: "INVALID_CONFIG" /* INVALID_CONFIG */,
147
+ message: "TrustwareConfig: 'routes.toChain' and 'routes.toToken' are required in deposit mode.",
148
+ userMessage: "Missing required destination chain/token configuration."
149
+ });
102
150
  }
103
- const toChain = input.routes.toChain;
104
- if (input.routes.toAddress) {
151
+ const toChain = input.routes?.toChain;
152
+ if (input.routes?.toAddress && toChain) {
105
153
  const result = validateAddressForChain(input.routes.toAddress, toChain);
106
154
  if (!result.isValid) {
107
155
  console.error(`[Trustware SDK] Invalid toAddress: ${result.error}`);
108
- throw new Error(`Invalid toAddress: ${result.error}`);
156
+ throw new TrustwareError({
157
+ code: "INVALID_CONFIG" /* INVALID_CONFIG */,
158
+ message: `Invalid toAddress: ${result.error}`,
159
+ userMessage: "The configured destination address is invalid."
160
+ });
109
161
  }
110
162
  }
111
- if (input.routes.fromAddress) {
112
- const result = validateAddressForChain(
113
- input.routes.fromAddress,
114
- input.routes.fromChain ?? toChain
115
- );
116
- if (!result.isValid) {
117
- console.error(`[Trustware SDK] Invalid fromAddress: ${result.error}`);
118
- throw new Error(`Invalid fromAddress: ${result.error}`);
163
+ if (input.routes?.fromAddress) {
164
+ const fromChain = input.routes.fromChain ?? toChain;
165
+ if (fromChain) {
166
+ const result = validateAddressForChain(
167
+ input.routes.fromAddress,
168
+ fromChain
169
+ );
170
+ if (!result.isValid) {
171
+ console.error(`[Trustware SDK] Invalid fromAddress: ${result.error}`);
172
+ throw new TrustwareError({
173
+ code: "INVALID_CONFIG" /* INVALID_CONFIG */,
174
+ message: `Invalid fromAddress: ${result.error}`,
175
+ userMessage: "The configured source address is invalid."
176
+ });
177
+ }
119
178
  }
120
179
  }
121
180
  const autoDetectProvider = typeof input.autoDetectProvider === "boolean" ? input.autoDetectProvider : DEFAULT_AUTO_DETECT_PROVIDER;
122
181
  const routes = {
123
- toChain: input.routes.toChain,
124
- toToken: input.routes.toToken,
125
- fromToken: input.routes.fromToken,
126
- fromAddress: input.routes.fromAddress,
127
- fromChain: input.routes.fromChain,
128
- toAddress: input.routes.toAddress,
182
+ toChain: input.routes?.toChain ?? "",
183
+ toToken: input.routes?.toToken ?? "",
184
+ fromToken: input.routes?.fromToken,
185
+ fromAddress: input.routes?.fromAddress,
186
+ fromChain: input.routes?.fromChain,
187
+ toAddress: input.routes?.toAddress,
129
188
  defaultSlippage: normalizeSlippage(
130
- input.routes.defaultSlippage ?? DEFAULT_SLIPPAGE
189
+ input.routes?.defaultSlippage ?? DEFAULT_SLIPPAGE
131
190
  ),
132
191
  options: {
133
- ...input.routes.options
192
+ ...input.routes?.options
134
193
  }
135
194
  };
136
195
  const theme = input.theme ?? "system";
@@ -149,13 +208,16 @@ function resolveConfig(input) {
149
208
  tokensPagination: input.features?.tokensPagination ?? DEFAULT_FEATURE_FLAGS.tokensPagination,
150
209
  balanceStreaming: input.features?.balanceStreaming ?? DEFAULT_FEATURE_FLAGS.balanceStreaming,
151
210
  shouldAllowGA4: input.features?.shouldAllowGA4 ?? DEFAULT_FEATURE_FLAGS.shouldAllowGA4,
152
- swapMode: input.features?.swapMode ?? DEFAULT_FEATURE_FLAGS.swapMode,
211
+ // Always mirrors the canonical `mode`, however the caller set it (new `mode` field
212
+ // or the deprecated `features.swapMode` flag).
213
+ swapMode: mode === "swap",
153
214
  swapDefaultDestToken: input.features?.swapDefaultDestToken ?? DEFAULT_FEATURE_FLAGS.swapDefaultDestToken,
154
215
  swapLockDestToken: input.features?.swapLockDestToken ?? DEFAULT_FEATURE_FLAGS.swapLockDestToken,
155
216
  swapAllowedDestTokens: input.features?.swapAllowedDestTokens ?? DEFAULT_FEATURE_FLAGS.swapAllowedDestTokens
156
217
  };
157
218
  return {
158
219
  apiKey: input.apiKey,
220
+ mode,
159
221
  routes,
160
222
  autoDetectProvider,
161
223
  theme,
@@ -168,12 +230,15 @@ function resolveConfig(input) {
168
230
  onEvent: input.onEvent
169
231
  };
170
232
  }
233
+ var hasWarnedDeprecatedSwapModeFlag;
171
234
  var init_merge = __esm({
172
235
  "src/config/merge.ts"() {
173
236
  "use strict";
174
237
  init_defaults();
175
238
  init_config();
176
239
  init_index();
240
+ init_TrustwareError();
241
+ hasWarnedDeprecatedSwapModeFlag = false;
177
242
  }
178
243
  });
179
244
 
@@ -430,7 +495,7 @@ var init_constants = __esm({
430
495
  "src/constants.ts"() {
431
496
  "use strict";
432
497
  SDK_NAME = "@trustware/sdk";
433
- SDK_VERSION = "1.1.9-staging.5";
498
+ SDK_VERSION = "1.1.9-staging.7";
434
499
  API_ROOT = "https://bv-staging-api.trustware.io";
435
500
  GTM_ID = "GTM-TZDGNCXB";
436
501
  API_PREFIX = "/api";
@@ -1035,21 +1100,28 @@ function formatDeepLink(id, currentUrl) {
1035
1100
  const enc = encodeURIComponent(currentUrl);
1036
1101
  switch (id) {
1037
1102
  // EVM
1103
+ // MetaMask's dapp browser also exposes its Wallet Standard Solana
1104
+ // provider in the same session, so "metamask-solana" reuses this link.
1038
1105
  case "metamask":
1106
+ case "metamask-solana":
1039
1107
  return `metamask://dapp/${currentUrl}`;
1040
1108
  case "coinbase":
1041
1109
  return `coinbase://wallet/dapp?url=${enc}`;
1042
1110
  case "rainbow":
1043
- return `rainbow://connect?uri=${enc}`;
1111
+ return `https://rainbow.me/dapp?url=${enc}`;
1044
1112
  case "trust":
1045
1113
  return `https://link.trustwallet.com/open_url?coin_id=60&url=${enc}`;
1046
1114
  case "okx":
1047
1115
  return `okx://wallet/dapp/url?dappUrl=${enc}`;
1048
1116
  // Solana
1117
+ // Phantom is one app with one in-app browser — browsing there injects
1118
+ // both window.ethereum and window.phantom.solana, so "phantom-evm"
1119
+ // reuses the same browse link as "phantom-solana".
1049
1120
  case "phantom-solana":
1050
- return `phantom://browse/${enc}`;
1121
+ case "phantom-evm":
1122
+ return `https://phantom.app/ul/browse/${enc}?ref=${enc}`;
1051
1123
  case "solflare":
1052
- return `solflare://ul/v1/browse/${enc}`;
1124
+ return `https://solflare.com/ul/v1/browse/${enc}?ref=${enc}`;
1053
1125
  case "backpack":
1054
1126
  return `https://backpack.app/ul/v1/browse/${enc}?ref=${enc}`;
1055
1127
  // No confirmed deep link scheme
@@ -1159,8 +1231,10 @@ var init_metadata = __esm({
1159
1231
  homepage: "https://phantom.app/",
1160
1232
  ios: "https://apps.apple.com/app/phantom-crypto-wallet/id1598432977",
1161
1233
  android: "https://play.google.com/store/apps/details?id=app.phantom",
1162
- detectFlags: ["isPhantom"]
1163
- // No EVM dapp browser deep link — falls back to app store
1234
+ detectFlags: ["isPhantom"],
1235
+ // Same app/in-app browser as "phantom-solana" — browsing there injects
1236
+ // window.ethereum too.
1237
+ deepLink: (url) => formatDeepLink("phantom-evm", url) ?? ""
1164
1238
  },
1165
1239
  {
1166
1240
  id: "phantom-solana",
@@ -1208,8 +1282,10 @@ var init_metadata = __esm({
1208
1282
  emoji: "\u{1F98A}",
1209
1283
  homepage: "https://metamask.io/",
1210
1284
  ios: "https://apps.apple.com/app/metamask/id1438144202",
1211
- android: "https://play.google.com/store/apps/details?id=io.metamask"
1212
- // No Solana-specific deep link for MetaMask
1285
+ android: "https://play.google.com/store/apps/details?id=io.metamask",
1286
+ // Same app/in-app browser as "metamask" — its Wallet Standard Solana
1287
+ // provider is exposed in that same browse session.
1288
+ deepLink: (url) => formatDeepLink("metamask-solana", url) ?? ""
1213
1289
  },
1214
1290
  // ── Extension/desktop only — hidden on mobile ─────────────────────────────
1215
1291
  {
@@ -2403,7 +2479,9 @@ var init_chains = __esm({
2403
2479
  btc: "bitcoin",
2404
2480
  bitcoin: "bitcoin",
2405
2481
  sei: "cosmos",
2406
- "pacific-1": "cosmos"
2482
+ "pacific-1": "cosmos",
2483
+ nibiru: "cosmos",
2484
+ "cataclysm-1": "cosmos"
2407
2485
  };
2408
2486
  }
2409
2487
  });
@@ -2458,6 +2536,25 @@ function validateSeiAddress(address) {
2458
2536
  error: "SEI addresses must be 0x-prefixed EVM or sei1 bech32 strings."
2459
2537
  };
2460
2538
  }
2539
+ function resolveCosmosBech32Prefix(chain) {
2540
+ const chainDef = typeof chain === "object" && chain ? chain : void 0;
2541
+ const identifier = chainDef?.networkIdentifier ?? chainDef?.chainId ?? chainDef?.id ?? (typeof chain === "string" ? chain : void 0);
2542
+ const normalized = String(identifier ?? "").trim().toLowerCase();
2543
+ return COSMOS_BECH32_PREFIX_BY_CHAIN_ID[normalized] ?? "sei";
2544
+ }
2545
+ function validateCosmosAddress(address, chain) {
2546
+ const trimmed = address.trim();
2547
+ const prefix = resolveCosmosBech32Prefix(chain);
2548
+ if (prefix === "sei" && (0, import_viem.isAddress)(trimmed)) {
2549
+ return { isValid: true };
2550
+ }
2551
+ const result = validateBech32LikeAddress(trimmed, prefix);
2552
+ if (result.isValid) return result;
2553
+ return {
2554
+ isValid: false,
2555
+ error: prefix === "sei" ? "SEI addresses must be 0x-prefixed EVM or sei1 bech32 strings." : `Address must be a valid ${prefix}1 bech32 string.`
2556
+ };
2557
+ }
2461
2558
  function validateSolanaAddress(address) {
2462
2559
  const trimmed = address.trim();
2463
2560
  if (trimmed.startsWith("0x") || (0, import_viem.isAddress)(trimmed)) {
@@ -2505,15 +2602,12 @@ function validateAddressForChain(address, chain) {
2505
2602
  case "bitcoin":
2506
2603
  return validateBtcAddress(trimmed);
2507
2604
  case "cosmos":
2508
- if (chainDef?.networkIdentifier?.toLowerCase() === "sei") {
2509
- return validateSeiAddress(trimmed);
2510
- }
2511
- return validateBech32LikeAddress(trimmed, "sei");
2605
+ return validateCosmosAddress(trimmed, chainDef ?? chain);
2512
2606
  default:
2513
2607
  return { isValid: false, error: "Unsupported or unknown chain type." };
2514
2608
  }
2515
2609
  }
2516
- function validateAddressForRouteChain(address, chainType) {
2610
+ function validateAddressForRouteChain(address, chainType, chainRef) {
2517
2611
  switch (normalizeChainType(chainType)) {
2518
2612
  case "evm":
2519
2613
  return validateEvmAddress(address);
@@ -2522,7 +2616,7 @@ function validateAddressForRouteChain(address, chainType) {
2522
2616
  case "bitcoin":
2523
2617
  return validateBtcAddress(address);
2524
2618
  case "cosmos":
2525
- return validateSeiAddress(address);
2619
+ return validateCosmosAddress(address, chainRef ?? chainType);
2526
2620
  default:
2527
2621
  return { isValid: false, error: "Unsupported chain type." };
2528
2622
  }
@@ -2544,14 +2638,18 @@ function validateRouteAddresses(params) {
2544
2638
  const normalizedDirection = params.direction?.trim().toLowerCase();
2545
2639
  const isDepositFlow = normalizedDirection === "deposit" || (toType === "evm" || toType === "cosmos") && (fromType === "bitcoin" || fromType === "solana");
2546
2640
  if (isDepositFlow) {
2547
- const fromResult2 = validateAddressForRouteChain(fromAddress, fromType);
2641
+ const fromResult2 = validateAddressForRouteChain(
2642
+ fromAddress,
2643
+ fromType,
2644
+ params.fromChain
2645
+ );
2548
2646
  if (!fromResult2.isValid) {
2549
2647
  return {
2550
2648
  isValid: false,
2551
2649
  error: `From address: ${fromResult2.error ?? "Invalid address."}`
2552
2650
  };
2553
2651
  }
2554
- const toResult2 = toType === "cosmos" ? validateSeiAddress(toAddress) : validateEvmAddress(toAddress);
2652
+ const toResult2 = toType === "cosmos" ? validateCosmosAddress(toAddress, params.toChain) : validateEvmAddress(toAddress);
2555
2653
  if (!toResult2.isValid) {
2556
2654
  return {
2557
2655
  isValid: false,
@@ -2576,14 +2674,22 @@ function validateRouteAddresses(params) {
2576
2674
  }
2577
2675
  return { isValid: true };
2578
2676
  }
2579
- const fromResult = validateAddressForRouteChain(fromAddress, fromType);
2677
+ const fromResult = validateAddressForRouteChain(
2678
+ fromAddress,
2679
+ fromType,
2680
+ params.fromChain
2681
+ );
2580
2682
  if (!fromResult.isValid) {
2581
2683
  return {
2582
2684
  isValid: false,
2583
2685
  error: `From address: ${fromResult.error ?? "Invalid address."}`
2584
2686
  };
2585
2687
  }
2586
- const toResult = validateAddressForRouteChain(toAddress, toType);
2688
+ const toResult = validateAddressForRouteChain(
2689
+ toAddress,
2690
+ toType,
2691
+ params.toChain
2692
+ );
2587
2693
  if (!toResult.isValid) {
2588
2694
  return {
2589
2695
  isValid: false,
@@ -2592,7 +2698,7 @@ function validateRouteAddresses(params) {
2592
2698
  }
2593
2699
  return { isValid: true };
2594
2700
  }
2595
- var import_viem, BECH32_CHARSET;
2701
+ var import_viem, BECH32_CHARSET, COSMOS_BECH32_PREFIX_BY_CHAIN_ID;
2596
2702
  var init_address = __esm({
2597
2703
  "src/validation/address.ts"() {
2598
2704
  "use strict";
@@ -2600,6 +2706,12 @@ var init_address = __esm({
2600
2706
  init_index_node4();
2601
2707
  init_chains();
2602
2708
  BECH32_CHARSET = /^[023456789acdefghjklmnpqrstuvwxyz]+$/i;
2709
+ COSMOS_BECH32_PREFIX_BY_CHAIN_ID = {
2710
+ "pacific-1": "sei",
2711
+ sei: "sei",
2712
+ "cataclysm-1": "nibi",
2713
+ nibiru: "nibi"
2714
+ };
2603
2715
  }
2604
2716
  });
2605
2717
 
@@ -2798,7 +2910,7 @@ var init_walletconnect = __esm({
2798
2910
  solanaMainnet = {
2799
2911
  id: 900,
2800
2912
  chainNamespace: "solana",
2801
- caipNetworkId: "solana:5eykt4UsFv8P8NJdTREpY1vzqAQ3H1FQ",
2913
+ caipNetworkId: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
2802
2914
  name: "Solana Mainnet",
2803
2915
  nativeCurrency: {
2804
2916
  name: "Solana",
@@ -3676,8 +3788,62 @@ function getChainMeta(chainId) {
3676
3788
  rpcUrls: chain.rpcUrls.default.http
3677
3789
  };
3678
3790
  }
3679
- async function buildWalletConnectAPI(walletCfg) {
3791
+ function extractSolanaAddress(connector) {
3792
+ const caipAccount = connector.provider.session?.namespaces?.solana?.accounts?.[0];
3793
+ if (!caipAccount) return null;
3794
+ return caipAccount.split(":")[2] ?? null;
3795
+ }
3796
+ function buildWalletConnectSolanaProvider(connector) {
3797
+ return {
3798
+ get publicKey() {
3799
+ const address = extractSolanaAddress(connector);
3800
+ return address ? { toString: () => address } : void 0;
3801
+ },
3802
+ async connect() {
3803
+ const address = extractSolanaAddress(connector);
3804
+ if (!address) {
3805
+ throw new Error(
3806
+ "This wallet did not approve a Solana account over WalletConnect."
3807
+ );
3808
+ }
3809
+ return { publicKey: { toString: () => address } };
3810
+ },
3811
+ async disconnect() {
3812
+ },
3813
+ async signTransaction(transaction) {
3814
+ const tx = transaction;
3815
+ const rawBytes = "version" in tx ? tx.serialize() : tx.serialize({
3816
+ requireAllSignatures: false,
3817
+ verifySignatures: false
3818
+ });
3819
+ const result = await connector.provider.request(
3820
+ {
3821
+ method: "solana_signTransaction",
3822
+ params: { transaction: encodeBase64(rawBytes) }
3823
+ },
3824
+ solanaMainnet.caipNetworkId
3825
+ );
3826
+ if (!result.transaction) {
3827
+ throw new Error(
3828
+ "WalletConnect wallet did not return a signed Solana transaction."
3829
+ );
3830
+ }
3831
+ const signedBytes = decodeBase64(result.transaction);
3832
+ return { serialize: () => signedBytes };
3833
+ },
3834
+ on() {
3835
+ },
3836
+ off() {
3837
+ },
3838
+ removeListener() {
3839
+ }
3840
+ };
3841
+ }
3842
+ async function buildWalletConnectAPI(walletCfg, ecosystem = "evm") {
3680
3843
  const connector = await getUniversalConnector(walletCfg);
3844
+ if (ecosystem === "solana") {
3845
+ return toSolanaWalletInterface(buildWalletConnectSolanaProvider(connector));
3846
+ }
3681
3847
  const provider = connector.provider;
3682
3848
  const api = {
3683
3849
  ecosystem: "evm",
@@ -3753,7 +3919,7 @@ function useWireDetectionIntoManager() {
3753
3919
  function useWalletConnectConnect(walletCfg) {
3754
3920
  const cfgRef = { current: walletCfg };
3755
3921
  return (0, import_react2.useCallback)(
3756
- () => walletManager.connectWalletConnect(cfgRef.current),
3922
+ (ecosystem) => walletManager.connectWalletConnect(cfgRef.current, ecosystem),
3757
3923
  []
3758
3924
  );
3759
3925
  }
@@ -3773,6 +3939,7 @@ function useWalletInfo(wagmi) {
3773
3939
  connectedVia: snapshot.connectedVia,
3774
3940
  walletType: snapshot.walletType,
3775
3941
  status: snapshot.status,
3942
+ detected: snapshot.detected,
3776
3943
  disconnect
3777
3944
  };
3778
3945
  }
@@ -3925,44 +4092,39 @@ var init_manager = __esm({
3925
4092
  this.emit();
3926
4093
  }
3927
4094
  }
3928
- async connectWalletConnect(walletCfg) {
3929
- if (this._status === "connected" && this._connectedVia === "walletconnect" && this._wallet) {
4095
+ async connectWalletConnect(walletCfg, ecosystem = "evm") {
4096
+ if (this._status === "connected" && this._connectedVia === "walletconnect" && this._wallet && this._wallet.ecosystem === ecosystem) {
3930
4097
  this.emit();
3931
4098
  return { error: null, api: this._wallet };
3932
4099
  }
4100
+ if (this._connectedVia === "walletconnect" && this._wallet) {
4101
+ await this._wallet.disconnect?.().catch(() => {
4102
+ });
4103
+ resetUniversalConnector();
4104
+ }
3933
4105
  this._status = "connecting";
3934
4106
  this.clearConnectedState();
3935
4107
  this.emit();
3936
4108
  try {
3937
4109
  const connector = await getUniversalConnector(walletCfg);
3938
4110
  await connector.connect();
3939
- const api = await buildWalletConnectAPI(walletCfg);
4111
+ const api = await buildWalletConnectAPI(walletCfg, ecosystem);
4112
+ try {
4113
+ await api.getAddress();
4114
+ } catch {
4115
+ await api.disconnect?.().catch(() => {
4116
+ });
4117
+ resetUniversalConnector();
4118
+ throw new Error(
4119
+ `This wallet did not approve a${ecosystem === "evm" ? "n" : ""} ${ecosystem === "evm" ? "EVM" : "Solana"} account over WalletConnect.`
4120
+ );
4121
+ }
3940
4122
  this._wallet = api;
3941
4123
  this._connectedVia = "walletconnect";
3942
4124
  this._connectedWalletId = "walletconnect";
3943
- const provider = connector.provider;
3944
- this._providerCleanup = bindWalletConnectEvents(provider, {
3945
- onAccountsChanged: (accounts) => {
3946
- if (accounts.length === 0) {
3947
- this.fullReset();
3948
- this.triggerExternalDisconnect();
3949
- this.emit();
3950
- return;
3951
- }
3952
- void this.syncIdentityFromWallet("walletconnect");
3953
- this.emit();
3954
- },
3955
- onChainChanged: () => {
3956
- void this.syncIdentityFromWallet("walletconnect");
3957
- this.emit();
3958
- },
3959
- onDisconnect: () => {
3960
- this.fullReset();
3961
- resetUniversalConnector();
3962
- this.triggerExternalDisconnect();
3963
- this.emit();
3964
- }
3965
- });
4125
+ this._providerCleanup = this.bindWalletConnectProviderEvents(
4126
+ connector.provider
4127
+ );
3966
4128
  await this.syncIdentityFromWallet("walletconnect");
3967
4129
  this._status = "connected";
3968
4130
  this._error = null;
@@ -3977,6 +4139,100 @@ var init_manager = __esm({
3977
4139
  return { error: message, api: null };
3978
4140
  }
3979
4141
  }
4142
+ bindWalletConnectProviderEvents(provider) {
4143
+ return bindWalletConnectEvents(provider, {
4144
+ onAccountsChanged: (accounts) => {
4145
+ if (accounts.length === 0) {
4146
+ this.fullReset();
4147
+ this.triggerExternalDisconnect();
4148
+ this.emit();
4149
+ return;
4150
+ }
4151
+ void this.syncIdentityFromWallet("walletconnect");
4152
+ this.emit();
4153
+ },
4154
+ onChainChanged: () => {
4155
+ void this.syncIdentityFromWallet("walletconnect");
4156
+ this.emit();
4157
+ },
4158
+ onDisconnect: () => {
4159
+ this.fullReset();
4160
+ resetUniversalConnector();
4161
+ this.triggerExternalDisconnect();
4162
+ this.emit();
4163
+ }
4164
+ });
4165
+ }
4166
+ // WalletConnect's own SignClient auto-restores the last persisted session
4167
+ // from storage on every init — including after a fresh page load — but
4168
+ // that restoration happens silently inside the library. Nothing calls back
4169
+ // into our code for it. On mobile, backgrounding the tab to approve in a
4170
+ // wallet app can cause the OS to reload the page before the original
4171
+ // connect() promise ever resolves, so the connect flow that triggered the
4172
+ // approval never gets to record it as "connected" here — even though
4173
+ // WalletConnect itself already has a live, approved session sitting in
4174
+ // storage. Call this on mount to pick that back up.
4175
+ async restoreWalletConnectSession(walletCfg) {
4176
+ if (this._status === "connected" && this._connectedVia === "walletconnect") {
4177
+ return this._wallet?.ecosystem === "solana" ? "solana" : "evm";
4178
+ }
4179
+ if (typeof window === "undefined") return null;
4180
+ try {
4181
+ if (!Object.keys(window.localStorage).some((key) => key.startsWith("wc@2"))) {
4182
+ return null;
4183
+ }
4184
+ } catch {
4185
+ }
4186
+ let connector;
4187
+ try {
4188
+ connector = await getUniversalConnector(walletCfg);
4189
+ } catch (e2) {
4190
+ console.warn(
4191
+ "[Trustware SDK] Failed to restore WalletConnect session:",
4192
+ e2
4193
+ );
4194
+ return null;
4195
+ }
4196
+ const session = connector.provider.session;
4197
+ if (!session) return null;
4198
+ const ecosystem = session.namespaces?.solana?.accounts?.length ? "solana" : session.namespaces?.eip155?.accounts?.length ? "evm" : null;
4199
+ if (!ecosystem) return null;
4200
+ try {
4201
+ const api = await buildWalletConnectAPI(walletCfg, ecosystem);
4202
+ this._wallet = api;
4203
+ this._connectedVia = "walletconnect";
4204
+ this._connectedWalletId = "walletconnect";
4205
+ this._providerCleanup = this.bindWalletConnectProviderEvents(
4206
+ connector.provider
4207
+ );
4208
+ await this.syncIdentityFromWallet("walletconnect");
4209
+ this._status = "connected";
4210
+ this._error = null;
4211
+ this.emit();
4212
+ return ecosystem;
4213
+ } catch {
4214
+ return null;
4215
+ }
4216
+ }
4217
+ // Forcibly abandon an in-progress connect() call the caller has decided is
4218
+ // stuck (e.g. the UI's own connect timeout elapsed with no response).
4219
+ // There's no clean way to cancel a pending WalletConnect pairing proposal
4220
+ // from this side, so this tears down the whole connector — the next
4221
+ // connect attempt starts against a brand new SignClient/pairing instead of
4222
+ // racing the abandoned one, which would otherwise risk reproducing the
4223
+ // "No matching key. proposal" class of error a real retry needs to avoid.
4224
+ cancelWalletConnectAttempt() {
4225
+ if (this._connectedVia === "walletconnect" && this._status === "connected") {
4226
+ return;
4227
+ }
4228
+ resetUniversalConnector();
4229
+ if (this._status === "connecting") {
4230
+ this.clearConnectedState();
4231
+ this._status = "idle";
4232
+ this._error = null;
4233
+ this.emit();
4234
+ }
4235
+ }
3980
4236
  async disconnect(wagmi) {
3981
4237
  if (wagmi && this._connectedVia === "extension") {
3982
4238
  await wagmi.disconnect().catch(() => {
@@ -4219,7 +4475,7 @@ async function buildDepositAddress(body, signal) {
4219
4475
  route
4220
4476
  };
4221
4477
  }
4222
- async function submitReceipt(intentId, txHash, sponsorshipRequestId) {
4478
+ async function submitReceipt(intentId, txHash, sponsorshipRequestId, eoaAddress) {
4223
4479
  const r = await rateLimitedFetch(
4224
4480
  `${apiBase()}/v1/route-intent/${intentId}/receipt`,
4225
4481
  {
@@ -4227,7 +4483,8 @@ async function submitReceipt(intentId, txHash, sponsorshipRequestId) {
4227
4483
  headers: jsonHeaders({ "Idempotency-Key": txHash }),
4228
4484
  body: JSON.stringify({
4229
4485
  txHash,
4230
- ...sponsorshipRequestId ? { sponsorshipRequestId } : {}
4486
+ ...sponsorshipRequestId ? { sponsorshipRequestId } : {},
4487
+ ...eoaAddress ? { eoaAddress } : {}
4231
4488
  })
4232
4489
  }
4233
4490
  );
@@ -5186,7 +5443,9 @@ var init_chainHelpers = __esm({
5186
5443
  btc: "bitcoin",
5187
5444
  bitcoin: "bitcoin",
5188
5445
  sei: "cosmos",
5189
- "pacific-1": "cosmos"
5446
+ "pacific-1": "cosmos",
5447
+ nibiru: "cosmos",
5448
+ "cataclysm-1": "cosmos"
5190
5449
  };
5191
5450
  SEI_EVM_CHAIN_ID = "1329";
5192
5451
  SEI_COSMOS_CHAIN_ID = "pacific-1";
@@ -5401,7 +5660,8 @@ function filterSupportedChains(chains) {
5401
5660
  }
5402
5661
  if (chainType === "cosmos") {
5403
5662
  const seiKey = canonicalSeiChainKey(chain.chainId ?? chain.id);
5404
- if (seiKey !== "sei" && seiKey !== "pacific-1") {
5663
+ const isNibiru = normalizeChainKey2(chain.chainId ?? chain.id) === NIBIRU_COSMOS_CHAIN_ID;
5664
+ if (seiKey !== "sei" && !isNibiru) {
5405
5665
  return false;
5406
5666
  }
5407
5667
  }
@@ -5501,7 +5761,7 @@ function useChains() {
5501
5761
  error
5502
5762
  };
5503
5763
  }
5504
- var import_react3, POPULAR_CHAINS_BY_TVL, POPULAR_LIMIT;
5764
+ var import_react3, POPULAR_CHAINS_BY_TVL, POPULAR_LIMIT, NIBIRU_COSMOS_CHAIN_ID;
5505
5765
  var init_useChains = __esm({
5506
5766
  "src/core/useChains.ts"() {
5507
5767
  "use strict";
@@ -5512,6 +5772,7 @@ var init_useChains = __esm({
5512
5772
  init_popularChains();
5513
5773
  POPULAR_CHAINS_BY_TVL = popularChains_default.byTvl;
5514
5774
  POPULAR_LIMIT = popularChains_default.popularLimit;
5775
+ NIBIRU_COSMOS_CHAIN_ID = "cataclysm-1";
5515
5776
  }
5516
5777
  });
5517
5778
 
@@ -7192,31 +7453,6 @@ var init_useTokens = __esm({
7192
7453
  }
7193
7454
  });
7194
7455
 
7195
- // src/errors/TrustwareError.ts
7196
- var TrustwareError;
7197
- var init_TrustwareError = __esm({
7198
- "src/errors/TrustwareError.ts"() {
7199
- "use strict";
7200
- TrustwareError = class extends Error {
7201
- constructor(params) {
7202
- super(params.message);
7203
- this.name = "TrustwareError";
7204
- this.code = params.code;
7205
- this.userMessage = params.userMessage;
7206
- this.cause = params.cause;
7207
- }
7208
- toJSON() {
7209
- return {
7210
- name: this.name,
7211
- code: this.code,
7212
- message: this.message,
7213
- userMessage: this.userMessage
7214
- };
7215
- }
7216
- };
7217
- }
7218
- });
7219
-
7220
7456
  // src/core/index.ts
7221
7457
  var _lastValidatedKey, Trustware;
7222
7458
  var init_core = __esm({
@@ -7674,12 +7910,71 @@ var init_useWalletSessionState = __esm({
7674
7910
  // src/widget/state/deposit/useWalletConnect.ts
7675
7911
  function useWalletConnect({
7676
7912
  setWalletType,
7677
- setCurrentStep
7913
+ setCurrentStep,
7914
+ selectedNamespace,
7915
+ setSelectedNamespace
7678
7916
  }) {
7679
7917
  const walletConnectCfg = TrustwareConfigStore.peek()?.walletConnect;
7680
7918
  const connectWC = useWalletConnectConnect(walletConnectCfg);
7919
+ const ecosystem = selectedNamespace.trim().toLowerCase() === "solana" ? "solana" : "evm";
7920
+ const [wcStatus, setWcStatus] = (0, import_react9.useState)("idle");
7921
+ const [wcErrorMessage, setWcErrorMessage] = (0, import_react9.useState)(null);
7922
+ const wcTimeoutRef = (0, import_react9.useRef)(null);
7923
+ const clearWcTimeout = (0, import_react9.useCallback)(() => {
7924
+ if (wcTimeoutRef.current !== null) {
7925
+ clearTimeout(wcTimeoutRef.current);
7926
+ wcTimeoutRef.current = null;
7927
+ }
7928
+ }, []);
7929
+ const beginWcAttempt = (0, import_react9.useCallback)(() => {
7930
+ setWcStatus("connecting");
7931
+ setWcErrorMessage(null);
7932
+ clearWcTimeout();
7933
+ wcTimeoutRef.current = setTimeout(() => {
7934
+ wcTimeoutRef.current = null;
7935
+ setWcStatus((prev) => prev === "connecting" ? "timedOut" : prev);
7936
+ }, WC_CONNECT_TIMEOUT_MS);
7937
+ }, [clearWcTimeout]);
7938
+ const resolveWcAttempt = (0, import_react9.useCallback)(() => {
7939
+ clearWcTimeout();
7940
+ setWcStatus("idle");
7941
+ setWcErrorMessage(null);
7942
+ }, [clearWcTimeout]);
7943
+ const failWcAttempt = (0, import_react9.useCallback)(
7944
+ (message) => {
7945
+ clearWcTimeout();
7946
+ setWcStatus("failed");
7947
+ setWcErrorMessage(message);
7948
+ },
7949
+ [clearWcTimeout]
7950
+ );
7951
+ const dismissWcStatus = (0, import_react9.useCallback)(() => {
7952
+ clearWcTimeout();
7953
+ setWcStatus("idle");
7954
+ setWcErrorMessage(null);
7955
+ }, [clearWcTimeout]);
7956
+ (0, import_react9.useEffect)(() => clearWcTimeout, [clearWcTimeout]);
7957
+ (0, import_react9.useEffect)(() => {
7958
+ let cancelled = false;
7959
+ beginWcAttempt();
7960
+ void (async () => {
7961
+ const restoredEcosystem = await walletManager.restoreWalletConnectSession(walletConnectCfg);
7962
+ if (cancelled) return;
7963
+ resolveWcAttempt();
7964
+ if (!restoredEcosystem) return;
7965
+ setWalletType("walletconnect");
7966
+ if (restoredEcosystem === "solana") {
7967
+ setSelectedNamespace("Solana");
7968
+ }
7969
+ const address = walletManager.identity?.addresses[0]?.address ?? null;
7970
+ if (address) setCurrentStep("crypto-pay");
7971
+ })();
7972
+ return () => {
7973
+ cancelled = true;
7974
+ };
7975
+ }, []);
7681
7976
  const WalletConnect = (0, import_react9.useCallback)(async () => {
7682
- if (walletManager.status === "connected" && walletManager.connectedVia === "walletconnect") {
7977
+ if (walletManager.status === "connected" && walletManager.connectedVia === "walletconnect" && walletManager.wallet?.ecosystem === ecosystem) {
7683
7978
  const address = walletManager.identity?.addresses[0]?.address ?? null;
7684
7979
  if (address) {
7685
7980
  setWalletType("walletconnect");
@@ -7688,35 +7983,60 @@ function useWalletConnect({
7688
7983
  }
7689
7984
  }
7690
7985
  setWalletType("walletconnect");
7691
- const { error } = await connectWC();
7986
+ beginWcAttempt();
7987
+ const { error } = await connectWC(ecosystem);
7692
7988
  if (!error) {
7693
7989
  const address = walletManager.identity?.addresses[0]?.address ?? null;
7694
7990
  if (address) {
7991
+ resolveWcAttempt();
7695
7992
  setCurrentStep("crypto-pay");
7993
+ } else {
7994
+ const message = `WalletConnect session established but no address resolved for ecosystem "${ecosystem}".`;
7995
+ console.error(`[Trustware SDK] ${message}`);
7996
+ failWcAttempt(message);
7696
7997
  }
7697
7998
  } else {
7999
+ console.error("[Trustware SDK] WalletConnect connection failed:", error);
8000
+ failWcAttempt(error);
7698
8001
  setWalletType("other");
7699
8002
  }
7700
- }, [connectWC, setCurrentStep, setWalletType]);
8003
+ }, [
8004
+ beginWcAttempt,
8005
+ connectWC,
8006
+ ecosystem,
8007
+ failWcAttempt,
8008
+ resolveWcAttempt,
8009
+ setCurrentStep,
8010
+ setWalletType
8011
+ ]);
8012
+ const retryWalletConnect = (0, import_react9.useCallback)(() => {
8013
+ walletManager.cancelWalletConnectAttempt();
8014
+ void WalletConnect();
8015
+ }, [WalletConnect]);
7701
8016
  const disconnectWalletConnect = (0, import_react9.useCallback)(async () => {
7702
8017
  await walletManager.disconnect();
7703
8018
  setWalletType("other");
7704
8019
  setCurrentStep("home");
7705
8020
  }, [setCurrentStep, setWalletType]);
7706
- const walletConnectAddress = walletManager.status === "connected" && walletManager.connectedVia === "walletconnect" ? walletManager.wallet?.ecosystem === "evm" ? walletManager.identity?.addresses[0]?.address ?? null : null : null;
8021
+ const walletConnectAddress = walletManager.status === "connected" && walletManager.connectedVia === "walletconnect" ? walletManager.identity?.addresses[0]?.address ?? null : null;
7707
8022
  return {
7708
8023
  walletConnectAddress,
7709
8024
  WalletConnect,
7710
- disconnectWalletConnect
8025
+ disconnectWalletConnect,
8026
+ wcStatus,
8027
+ wcErrorMessage,
8028
+ retryWalletConnect,
8029
+ dismissWcStatus
7711
8030
  };
7712
8031
  }
7713
- var import_react9;
8032
+ var import_react9, WC_CONNECT_TIMEOUT_MS;
7714
8033
  var init_useWalletConnect = __esm({
7715
8034
  "src/widget/state/deposit/useWalletConnect.ts"() {
7716
8035
  "use strict";
7717
8036
  import_react9 = require("react");
7718
8037
  init_config2();
7719
8038
  init_wallets();
8039
+ WC_CONNECT_TIMEOUT_MS = 3e4;
7720
8040
  }
7721
8041
  });
7722
8042
 
@@ -7728,6 +8048,7 @@ function useTrustwareConfig() {
7728
8048
  } catch {
7729
8049
  return {
7730
8050
  apiKey: "",
8051
+ mode: "deposit",
7731
8052
  routes: {
7732
8053
  toChain: "",
7733
8054
  toToken: "",
@@ -7807,14 +8128,24 @@ function DepositProvider({
7807
8128
  const [walletType, setWalletType] = (0, import_react11.useState)(
7808
8129
  "other"
7809
8130
  );
7810
- const { walletConnectAddress, WalletConnect, disconnectWalletConnect } = useWalletConnect({
8131
+ const [selectedNamespace, setSelectedNamespace] = (0, import_react11.useState)("evm");
8132
+ const {
8133
+ walletConnectAddress,
8134
+ WalletConnect,
8135
+ disconnectWalletConnect,
8136
+ wcStatus,
8137
+ wcErrorMessage,
8138
+ retryWalletConnect,
8139
+ dismissWcStatus
8140
+ } = useWalletConnect({
7811
8141
  setWalletType,
7812
- setCurrentStep
8142
+ setCurrentStep,
8143
+ selectedNamespace,
8144
+ setSelectedNamespace
7813
8145
  });
7814
8146
  const [selectedToken, setSelectedToken] = (0, import_react11.useState)(null);
7815
8147
  const [selectedChain, setSelectedChain] = (0, import_react11.useState)(null);
7816
8148
  const [amount, setAmount] = (0, import_react11.useState)("");
7817
- const [selectedNamespace, setSelectedNamespace] = (0, import_react11.useState)("evm");
7818
8149
  const walletAddress = (0, import_react11.useMemo)(
7819
8150
  () => walletType === "walletconnect" ? walletConnectAddress : otherWalletAddress,
7820
8151
  [walletType, walletConnectAddress, otherWalletAddress]
@@ -7886,7 +8217,11 @@ function DepositProvider({
7886
8217
  setWalletType,
7887
8218
  walletType,
7888
8219
  selectedNamespace,
7889
- setSelectedNamespace
8220
+ setSelectedNamespace,
8221
+ wcStatus,
8222
+ wcErrorMessage,
8223
+ retryWalletConnect,
8224
+ dismissWcStatus
7890
8225
  }),
7891
8226
  [
7892
8227
  WalletConnect,
@@ -7902,7 +8237,11 @@ function DepositProvider({
7902
8237
  yourWalletTokens,
7903
8238
  yourWalletTokensLoading,
7904
8239
  selectedNamespace,
7905
- setSelectedNamespace
8240
+ setSelectedNamespace,
8241
+ wcStatus,
8242
+ wcErrorMessage,
8243
+ retryWalletConnect,
8244
+ dismissWcStatus
7906
8245
  ]
7907
8246
  );
7908
8247
  const formValue = (0, import_react11.useMemo)(
@@ -16218,6 +16557,18 @@ var init_WalletNamespaceTabs = __esm({
16218
16557
  });
16219
16558
 
16220
16559
  // src/widget/features/wallet/components/CryptoWalletDropdownContent.tsx
16560
+ function ecosystemToNamespace(ecosystem) {
16561
+ switch (ecosystem.trim().toLowerCase()) {
16562
+ case "evm":
16563
+ return "evm";
16564
+ case "solana":
16565
+ return "Solana";
16566
+ case "bitcoin":
16567
+ return "bitcoin";
16568
+ default:
16569
+ return null;
16570
+ }
16571
+ }
16221
16572
  function DesktopWalletDropdownContent({
16222
16573
  browserWallets,
16223
16574
  handleWalletConnect,
@@ -16283,11 +16634,13 @@ function DesktopWalletDropdownContent({
16283
16634
  );
16284
16635
  }
16285
16636
  function MobileWalletDropdownContent({
16286
- handleWalletConnect
16637
+ browserWallets,
16638
+ handleWalletConnect,
16639
+ handleWalletSelect: connectDetectedWallet2
16287
16640
  }) {
16288
16641
  const { setCurrentStep } = useDepositNavigation();
16289
- const { selectedNamespace } = useDepositWallet();
16290
- const { walletMetaId, isConnected, status } = useWalletInfo();
16642
+ const { selectedNamespace, setSelectedNamespace } = useDepositWallet();
16643
+ const { walletMetaId, isConnected, status, detected } = useWalletInfo();
16291
16644
  const [hoveredId, setHoveredId] = (0, import_react34.useState)(null);
16292
16645
  const storeFallbackTimeoutRef = (0, import_react34.useRef)(
16293
16646
  null
@@ -16299,22 +16652,52 @@ function MobileWalletDropdownContent({
16299
16652
  }
16300
16653
  };
16301
16654
  }, []);
16655
+ (0, import_react34.useEffect)(() => {
16656
+ if (browserWallets.length > 0) return;
16657
+ const otherEcosystemWallet = detected.find((d) => {
16658
+ if (d.meta.id === "walletconnect") return false;
16659
+ const ecosystem = d.meta.ecosystem.trim().toLowerCase();
16660
+ return ecosystem !== "multi" && ecosystem !== selectedNamespace.trim().toLowerCase();
16661
+ });
16662
+ if (!otherEcosystemWallet) return;
16663
+ const nextNamespace = ecosystemToNamespace(
16664
+ otherEcosystemWallet.meta.ecosystem
16665
+ );
16666
+ if (nextNamespace) setSelectedNamespace(nextNamespace);
16667
+ }, [browserWallets, detected, selectedNamespace, setSelectedNamespace]);
16302
16668
  const connectedWalletId = isConnected ? walletMetaId : null;
16303
16669
  const currentUrl = window.location.href;
16304
- const mobileWallets = (0, import_react34.useMemo)(
16305
- () => WALLETS.filter((w) => {
16306
- if (w.id === "walletconnect") return true;
16670
+ const mobileWallets = (0, import_react34.useMemo)(() => {
16671
+ const entries = WALLETS.filter((w) => {
16672
+ if (w.id === "walletconnect") {
16673
+ return selectedNamespace.trim().toLowerCase() === "evm";
16674
+ }
16675
+ const isDetected = browserWallets.some((d) => d.meta.id === w.id);
16307
16676
  const hasMobileLink = Boolean(w.deepLink);
16308
- if (!hasMobileLink) return false;
16677
+ if (!hasMobileLink && !isDetected) return false;
16309
16678
  return w.ecosystem.trim().toLowerCase() === "multi" || w.ecosystem.trim().toLowerCase() === selectedNamespace.trim().toLowerCase();
16310
- }),
16311
- [selectedNamespace]
16312
- );
16313
- const handleWalletSelect = (wallet) => {
16679
+ }).map((meta) => ({
16680
+ meta,
16681
+ detectedWallet: browserWallets.find((d) => d.meta.id === meta.id) ?? null
16682
+ }));
16683
+ const listedIds = new Set(entries.map((e2) => e2.meta.id));
16684
+ for (const detected2 of browserWallets) {
16685
+ if (!listedIds.has(detected2.meta.id)) {
16686
+ entries.push({ meta: detected2.meta, detectedWallet: detected2 });
16687
+ }
16688
+ }
16689
+ return entries;
16690
+ }, [browserWallets, selectedNamespace]);
16691
+ const handleWalletSelect = (entry) => {
16692
+ const { meta: wallet, detectedWallet } = entry;
16314
16693
  if (wallet.id === "walletconnect") {
16315
16694
  handleWalletConnect();
16316
16695
  return;
16317
16696
  }
16697
+ if (detectedWallet) {
16698
+ void connectDetectedWallet2(detectedWallet);
16699
+ return;
16700
+ }
16318
16701
  if (wallet.deepLink) {
16319
16702
  const deepLinkUrl = wallet.deepLink(currentUrl);
16320
16703
  if (deepLinkUrl) {
@@ -16384,15 +16767,16 @@ function MobileWalletDropdownContent({
16384
16767
  scrollbarWidth: "thin",
16385
16768
  scrollbarColor: `${colors.muted} transparent`
16386
16769
  },
16387
- children: mobileWallets.map((wallet) => {
16770
+ children: mobileWallets.map((entry) => {
16771
+ const wallet = entry.meta;
16388
16772
  const isConnectedWallet = wallet.id === connectedWalletId;
16389
- const isDisabled = isConnected && !isConnectedWallet;
16773
+ const isDisabled = isConnected && !isConnectedWallet && !entry.detectedWallet;
16390
16774
  const isHovered = hoveredId === wallet.id;
16391
16775
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
16392
16776
  "button",
16393
16777
  {
16394
16778
  type: "button",
16395
- onClick: () => !isDisabled && handleWalletSelect(wallet),
16779
+ onClick: () => !isDisabled && handleWalletSelect(entry),
16396
16780
  onMouseEnter: () => !isDisabled && setHoveredId(wallet.id),
16397
16781
  onMouseLeave: () => setHoveredId(null),
16398
16782
  style: {
@@ -16468,7 +16852,7 @@ function MobileWalletDropdownContent({
16468
16852
  }
16469
16853
  }
16470
16854
  ),
16471
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { style: { fontSize: fontSize.xs, color: "#22c55e" }, children: "Connected" })
16855
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { style: { fontSize: fontSize.xs, color: "#22c55e" }, children: "Continue" })
16472
16856
  ]
16473
16857
  }
16474
16858
  )
@@ -16533,7 +16917,9 @@ function CryptoWalletDropdownContent({
16533
16917
  isMobile && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
16534
16918
  MobileWalletDropdownContent,
16535
16919
  {
16536
- handleWalletConnect
16920
+ browserWallets,
16921
+ handleWalletConnect,
16922
+ handleWalletSelect
16537
16923
  }
16538
16924
  )
16539
16925
  ] });
@@ -17075,9 +17461,11 @@ function useHomeWalletActions({
17075
17461
  const { selectedNamespace } = useDepositWallet();
17076
17462
  const browserWallets = (0, import_react35.useMemo)(() => {
17077
17463
  if (!detectedWallets?.length) return [];
17078
- return detectedWallets.filter(
17079
- (wallet) => wallet?.meta?.id !== "walletconnect" && wallet?.meta?.ecosystem.trim().toLowerCase() === selectedNamespace.trim().toLowerCase()
17080
- );
17464
+ return detectedWallets.filter((wallet) => {
17465
+ if (wallet?.meta?.id === "walletconnect") return false;
17466
+ const ecosystem = wallet?.meta?.ecosystem.trim().toLowerCase();
17467
+ return ecosystem === "multi" || ecosystem === selectedNamespace.trim().toLowerCase();
17468
+ });
17081
17469
  }, [detectedWallets, selectedNamespace]);
17082
17470
  return {
17083
17471
  browserWallets,
@@ -17113,10 +17501,113 @@ var init_wallet = __esm({
17113
17501
  });
17114
17502
 
17115
17503
  // src/widget/pages/Home.tsx
17504
+ function WalletConnectStatusBanner({
17505
+ status,
17506
+ errorMessage,
17507
+ onRetry,
17508
+ onDismiss
17509
+ }) {
17510
+ const isDone = status !== "connecting";
17511
+ const isFailed = status === "failed";
17512
+ const { text, icon } = wcBannerCopy[status];
17513
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
17514
+ "div",
17515
+ {
17516
+ style: {
17517
+ display: "flex",
17518
+ alignItems: "center",
17519
+ gap: spacing[2],
17520
+ width: "100%",
17521
+ padding: `${spacing[2.5]} ${spacing[3]}`,
17522
+ marginBottom: spacing[4],
17523
+ borderRadius: borderRadius.lg,
17524
+ backgroundColor: isFailed ? "rgba(239,68,68,0.1)" : isDone ? "rgba(234,179,8,0.1)" : colors.muted,
17525
+ border: isFailed ? "1px solid rgba(239,68,68,0.4)" : isDone ? "1px solid rgba(234,179,8,0.4)" : `1px solid ${colors.border}`
17526
+ },
17527
+ children: [
17528
+ icon === "spinner" ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17529
+ "div",
17530
+ {
17531
+ style: {
17532
+ width: "0.875rem",
17533
+ height: "0.875rem",
17534
+ border: `2px solid ${colors.mutedForeground}`,
17535
+ borderTopColor: "transparent",
17536
+ borderRadius: "9999px",
17537
+ animation: "tw-spin 1s linear infinite",
17538
+ flexShrink: 0
17539
+ }
17540
+ }
17541
+ ) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { style: { fontSize: fontSize.sm, flexShrink: 0 }, "aria-hidden": true, children: icon }),
17542
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
17543
+ "p",
17544
+ {
17545
+ style: {
17546
+ flex: 1,
17547
+ fontSize: fontSize.xs,
17548
+ color: isDone ? colors.foreground : colors.mutedForeground,
17549
+ margin: 0
17550
+ },
17551
+ children: [
17552
+ text,
17553
+ isFailed && errorMessage ? ` ${errorMessage}` : ""
17554
+ ]
17555
+ }
17556
+ ),
17557
+ isDone && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
17558
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17559
+ "button",
17560
+ {
17561
+ type: "button",
17562
+ onClick: onRetry,
17563
+ style: {
17564
+ fontSize: fontSize.xs,
17565
+ fontWeight: fontWeight.semibold,
17566
+ color: colors.primary,
17567
+ backgroundColor: "transparent",
17568
+ border: 0,
17569
+ cursor: "pointer",
17570
+ flexShrink: 0
17571
+ },
17572
+ children: "Retry"
17573
+ }
17574
+ ),
17575
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17576
+ "button",
17577
+ {
17578
+ type: "button",
17579
+ onClick: onDismiss,
17580
+ "aria-label": "Dismiss",
17581
+ style: {
17582
+ fontSize: fontSize.xs,
17583
+ color: colors.mutedForeground,
17584
+ backgroundColor: "transparent",
17585
+ border: 0,
17586
+ cursor: "pointer",
17587
+ flexShrink: 0,
17588
+ padding: 0,
17589
+ lineHeight: 1
17590
+ },
17591
+ children: "\xD7"
17592
+ }
17593
+ )
17594
+ ] })
17595
+ ]
17596
+ }
17597
+ );
17598
+ }
17116
17599
  function Home({ style: _style }) {
17117
17600
  const { amount, setAmount, amountInputMode, setAmountInputMode } = useDepositForm();
17118
17601
  const { setCurrentStep, setCurrentStepInternal } = useDepositNavigation();
17119
- const { connectWallet, WalletConnect, setWalletType } = useDepositWallet();
17602
+ const {
17603
+ connectWallet,
17604
+ WalletConnect,
17605
+ setWalletType,
17606
+ wcStatus,
17607
+ wcErrorMessage,
17608
+ retryWalletConnect,
17609
+ dismissWcStatus
17610
+ } = useDepositWallet();
17120
17611
  const { resolvedTheme } = useDepositUi();
17121
17612
  const { fixedFromAmountString, isFixedAmount, minAmountUsd, maxAmountUsd } = useAmountConstraints();
17122
17613
  const { detected: detectedWallets } = useWalletDetection();
@@ -17198,6 +17689,15 @@ function Home({ style: _style }) {
17198
17689
  position: "relative"
17199
17690
  },
17200
17691
  children: [
17692
+ wcStatus !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17693
+ WalletConnectStatusBanner,
17694
+ {
17695
+ status: wcStatus,
17696
+ errorMessage: wcErrorMessage,
17697
+ onRetry: retryWalletConnect,
17698
+ onDismiss: dismissWcStatus
17699
+ }
17700
+ ),
17201
17701
  /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17202
17702
  "p",
17203
17703
  {
@@ -17273,7 +17773,7 @@ function Home({ style: _style }) {
17273
17773
  }
17274
17774
  );
17275
17775
  }
17276
- var import_jsx_runtime44;
17776
+ var import_jsx_runtime44, wcBannerCopy;
17277
17777
  var init_Home = __esm({
17278
17778
  "src/widget/pages/Home.tsx"() {
17279
17779
  "use strict";
@@ -17284,6 +17784,20 @@ var init_Home = __esm({
17284
17784
  init_wallets();
17285
17785
  init_wallet();
17286
17786
  import_jsx_runtime44 = require("react/jsx-runtime");
17787
+ wcBannerCopy = {
17788
+ connecting: {
17789
+ text: "Waiting for wallet approval via WalletConnect\u2026",
17790
+ icon: "spinner"
17791
+ },
17792
+ timedOut: {
17793
+ text: "Still waiting on WalletConnect \u2014 this is taking longer than expected.",
17794
+ icon: "\u26A0\uFE0F"
17795
+ },
17796
+ failed: {
17797
+ text: "WalletConnect connection failed.",
17798
+ icon: "\u2715"
17799
+ }
17800
+ };
17287
17801
  }
17288
17802
  });
17289
17803
 
@@ -31093,7 +31607,7 @@ async function sendRouteAsUserOperation(params) {
31093
31607
  );
31094
31608
  }
31095
31609
  console.debug("[send] UserOp included", { userOpHash, txHash });
31096
- await submitReceipt(intentId, txHash, getSponsorshipRequestId());
31610
+ await submitReceipt(intentId, txHash, getSponsorshipRequestId(), eoaAddress);
31097
31611
  return { userOpHash, txHash, intentId };
31098
31612
  }
31099
31613
  var NATIVE_ADDRS;
@@ -33990,6 +34504,7 @@ function SwapWalletSelectorMobile({
33990
34504
  const { meta } = entry;
33991
34505
  const isWalletConnected = managerConnected && walletMetaId === meta.id;
33992
34506
  const isConnecting = connectingId === meta.id && walletStatus === "connecting";
34507
+ const isRowDisabled = managerConnected && !isWalletConnected && !entry.detectedWallet;
33993
34508
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
33994
34509
  "div",
33995
34510
  {
@@ -34007,7 +34522,8 @@ function SwapWalletSelectorMobile({
34007
34522
  isWalletConnected && {
34008
34523
  boxShadow: `0 0 0 2px ${colors.primary}`,
34009
34524
  border: `1px solid ${colors.primary}`
34010
- }
34525
+ },
34526
+ isRowDisabled && { opacity: 0.4 }
34011
34527
  ),
34012
34528
  children: [
34013
34529
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
@@ -34098,7 +34614,7 @@ function SwapWalletSelectorMobile({
34098
34614
  "button",
34099
34615
  {
34100
34616
  onClick: () => void handleClick(entry),
34101
- disabled: walletStatus === "connecting",
34617
+ disabled: walletStatus === "connecting" || isRowDisabled,
34102
34618
  style: mergeStyles(
34103
34619
  {
34104
34620
  padding: `${spacing[1.5]} ${spacing[3]}`,
@@ -34111,7 +34627,7 @@ function SwapWalletSelectorMobile({
34111
34627
  cursor: "pointer",
34112
34628
  flexShrink: 0
34113
34629
  },
34114
- walletStatus === "connecting" && {
34630
+ (walletStatus === "connecting" || isRowDisabled) && {
34115
34631
  opacity: 0.5,
34116
34632
  cursor: "not-allowed"
34117
34633
  }
@@ -34139,6 +34655,7 @@ function SwapWalletSelectorMobile({
34139
34655
  ),
34140
34656
  (() => {
34141
34657
  const wcConnected = managerConnected && connectedVia === "walletconnect";
34658
+ const wcRowDisabled = managerConnected && !wcConnected;
34142
34659
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
34143
34660
  "div",
34144
34661
  {
@@ -34157,9 +34674,10 @@ function SwapWalletSelectorMobile({
34157
34674
  wcConnected && {
34158
34675
  boxShadow: `0 0 0 2px ${colors.primary}`,
34159
34676
  border: `1px solid ${colors.primary}`
34160
- }
34677
+ },
34678
+ wcRowDisabled && { opacity: 0.4, cursor: "not-allowed" }
34161
34679
  ),
34162
- onClick: !wcConnected ? () => void handleWalletConnect() : void 0,
34680
+ onClick: !wcConnected && !wcRowDisabled ? () => void handleWalletConnect() : void 0,
34163
34681
  children: [
34164
34682
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
34165
34683
  "div",
@@ -34255,18 +34773,24 @@ function SwapWalletSelectorMobile({
34255
34773
  e2.stopPropagation();
34256
34774
  void handleWalletConnect();
34257
34775
  },
34258
- disabled: wcConnecting,
34259
- style: {
34260
- padding: `${spacing[1.5]} ${spacing[3]}`,
34261
- borderRadius: "9999px",
34262
- backgroundColor: "rgba(59,130,246,0.1)",
34263
- color: colors.primary,
34264
- fontSize: fontSize.xs,
34265
- fontWeight: fontWeight.medium,
34266
- border: 0,
34267
- cursor: "pointer",
34268
- flexShrink: 0
34269
- },
34776
+ disabled: wcConnecting || wcRowDisabled,
34777
+ style: mergeStyles(
34778
+ {
34779
+ padding: `${spacing[1.5]} ${spacing[3]}`,
34780
+ borderRadius: "9999px",
34781
+ backgroundColor: "rgba(59,130,246,0.1)",
34782
+ color: colors.primary,
34783
+ fontSize: fontSize.xs,
34784
+ fontWeight: fontWeight.medium,
34785
+ border: 0,
34786
+ cursor: "pointer",
34787
+ flexShrink: 0
34788
+ },
34789
+ (wcConnecting || wcRowDisabled) && {
34790
+ opacity: 0.5,
34791
+ cursor: "not-allowed"
34792
+ }
34793
+ ),
34270
34794
  children: "Connect"
34271
34795
  }
34272
34796
  )
@@ -35174,7 +35698,7 @@ function SwapMode({
35174
35698
  }).catch(() => {
35175
35699
  });
35176
35700
  }, [defaultDestRef, allChains]);
35177
- const { walletAddress, walletStatus, connectWallet, disconnectWallet } = useWalletSessionState();
35701
+ const { walletAddress, walletStatus, connectWallet } = useWalletSessionState();
35178
35702
  const setFromTokenStable = (0, import_react50.useCallback)(
35179
35703
  (t) => setFromToken(t),
35180
35704
  []
@@ -37252,7 +37776,7 @@ function SwapMode({
37252
37776
  walletAddress ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
37253
37777
  "button",
37254
37778
  {
37255
- onClick: () => void disconnectWallet(),
37779
+ onClick: handleConnectAndReview,
37256
37780
  style: {
37257
37781
  fontSize: fontSize.xs,
37258
37782
  color: colors.mutedForeground,
@@ -37263,8 +37787,7 @@ function SwapMode({
37263
37787
  children: [
37264
37788
  walletAddress.slice(0, 6),
37265
37789
  "...",
37266
- walletAddress.slice(-4),
37267
- " \xD7"
37790
+ walletAddress.slice(-4)
37268
37791
  ]
37269
37792
  }
37270
37793
  ) : /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
@@ -39364,7 +39887,7 @@ var init_TrustwareWidgetV2 = __esm({
39364
39887
  if (!isOpen) {
39365
39888
  return null;
39366
39889
  }
39367
- if (config.features.swapMode) {
39890
+ if (config.mode === "swap") {
39368
39891
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(SwapMode, { theme, style });
39369
39892
  }
39370
39893
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DepositProvider, { initialStep: effectiveInitialStep, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
@@ -39479,6 +40002,7 @@ __export(index_exports, {
39479
40002
  useWireDetectionIntoManager: () => useWireDetectionIntoManager,
39480
40003
  validateAddressForChain: () => validateAddressForChain,
39481
40004
  validateBtcAddress: () => validateBtcAddress,
40005
+ validateCosmosAddress: () => validateCosmosAddress,
39482
40006
  validateEvmAddress: () => validateEvmAddress,
39483
40007
  validateRouteAddresses: () => validateRouteAddresses,
39484
40008
  validateSeiAddress: () => validateSeiAddress,
@@ -39538,6 +40062,7 @@ init_index();
39538
40062
  useWireDetectionIntoManager,
39539
40063
  validateAddressForChain,
39540
40064
  validateBtcAddress,
40065
+ validateCosmosAddress,
39541
40066
  validateEvmAddress,
39542
40067
  validateRouteAddresses,
39543
40068
  validateSeiAddress,