@trustware/sdk-staging 1.1.9-staging.5 → 1.1.9-staging.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
@@ -430,7 +430,7 @@ var init_constants = __esm({
430
430
  "src/constants.ts"() {
431
431
  "use strict";
432
432
  SDK_NAME = "@trustware/sdk";
433
- SDK_VERSION = "1.1.9-staging.5";
433
+ SDK_VERSION = "1.1.9-staging.6";
434
434
  API_ROOT = "https://bv-staging-api.trustware.io";
435
435
  GTM_ID = "GTM-TZDGNCXB";
436
436
  API_PREFIX = "/api";
@@ -1035,21 +1035,28 @@ function formatDeepLink(id, currentUrl) {
1035
1035
  const enc = encodeURIComponent(currentUrl);
1036
1036
  switch (id) {
1037
1037
  // EVM
1038
+ // MetaMask's dapp browser also exposes its Wallet Standard Solana
1039
+ // provider in the same session, so "metamask-solana" reuses this link.
1038
1040
  case "metamask":
1041
+ case "metamask-solana":
1039
1042
  return `metamask://dapp/${currentUrl}`;
1040
1043
  case "coinbase":
1041
1044
  return `coinbase://wallet/dapp?url=${enc}`;
1042
1045
  case "rainbow":
1043
- return `rainbow://connect?uri=${enc}`;
1046
+ return `https://rainbow.me/dapp?url=${enc}`;
1044
1047
  case "trust":
1045
1048
  return `https://link.trustwallet.com/open_url?coin_id=60&url=${enc}`;
1046
1049
  case "okx":
1047
1050
  return `okx://wallet/dapp/url?dappUrl=${enc}`;
1048
1051
  // Solana
1052
+ // Phantom is one app with one in-app browser — browsing there injects
1053
+ // both window.ethereum and window.phantom.solana, so "phantom-evm"
1054
+ // reuses the same browse link as "phantom-solana".
1049
1055
  case "phantom-solana":
1050
- return `phantom://browse/${enc}`;
1056
+ case "phantom-evm":
1057
+ return `https://phantom.app/ul/browse/${enc}?ref=${enc}`;
1051
1058
  case "solflare":
1052
- return `solflare://ul/v1/browse/${enc}`;
1059
+ return `https://solflare.com/ul/v1/browse/${enc}?ref=${enc}`;
1053
1060
  case "backpack":
1054
1061
  return `https://backpack.app/ul/v1/browse/${enc}?ref=${enc}`;
1055
1062
  // No confirmed deep link scheme
@@ -1159,8 +1166,10 @@ var init_metadata = __esm({
1159
1166
  homepage: "https://phantom.app/",
1160
1167
  ios: "https://apps.apple.com/app/phantom-crypto-wallet/id1598432977",
1161
1168
  android: "https://play.google.com/store/apps/details?id=app.phantom",
1162
- detectFlags: ["isPhantom"]
1163
- // No EVM dapp browser deep linkfalls back to app store
1169
+ detectFlags: ["isPhantom"],
1170
+ // Same app/in-app browser as "phantom-solana"browsing there injects
1171
+ // window.ethereum too.
1172
+ deepLink: (url) => formatDeepLink("phantom-evm", url) ?? ""
1164
1173
  },
1165
1174
  {
1166
1175
  id: "phantom-solana",
@@ -1208,8 +1217,10 @@ var init_metadata = __esm({
1208
1217
  emoji: "\u{1F98A}",
1209
1218
  homepage: "https://metamask.io/",
1210
1219
  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
1220
+ android: "https://play.google.com/store/apps/details?id=io.metamask",
1221
+ // Same app/in-app browser as "metamask" — its Wallet Standard Solana
1222
+ // provider is exposed in that same browse session.
1223
+ deepLink: (url) => formatDeepLink("metamask-solana", url) ?? ""
1213
1224
  },
1214
1225
  // ── Extension/desktop only — hidden on mobile ─────────────────────────────
1215
1226
  {
@@ -2798,7 +2809,7 @@ var init_walletconnect = __esm({
2798
2809
  solanaMainnet = {
2799
2810
  id: 900,
2800
2811
  chainNamespace: "solana",
2801
- caipNetworkId: "solana:5eykt4UsFv8P8NJdTREpY1vzqAQ3H1FQ",
2812
+ caipNetworkId: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
2802
2813
  name: "Solana Mainnet",
2803
2814
  nativeCurrency: {
2804
2815
  name: "Solana",
@@ -3676,8 +3687,62 @@ function getChainMeta(chainId) {
3676
3687
  rpcUrls: chain.rpcUrls.default.http
3677
3688
  };
3678
3689
  }
3679
- async function buildWalletConnectAPI(walletCfg) {
3690
+ function extractSolanaAddress(connector) {
3691
+ const caipAccount = connector.provider.session?.namespaces?.solana?.accounts?.[0];
3692
+ if (!caipAccount) return null;
3693
+ return caipAccount.split(":")[2] ?? null;
3694
+ }
3695
+ function buildWalletConnectSolanaProvider(connector) {
3696
+ return {
3697
+ get publicKey() {
3698
+ const address = extractSolanaAddress(connector);
3699
+ return address ? { toString: () => address } : void 0;
3700
+ },
3701
+ async connect() {
3702
+ const address = extractSolanaAddress(connector);
3703
+ if (!address) {
3704
+ throw new Error(
3705
+ "This wallet did not approve a Solana account over WalletConnect."
3706
+ );
3707
+ }
3708
+ return { publicKey: { toString: () => address } };
3709
+ },
3710
+ async disconnect() {
3711
+ },
3712
+ async signTransaction(transaction) {
3713
+ const tx = transaction;
3714
+ const rawBytes = "version" in tx ? tx.serialize() : tx.serialize({
3715
+ requireAllSignatures: false,
3716
+ verifySignatures: false
3717
+ });
3718
+ const result = await connector.provider.request(
3719
+ {
3720
+ method: "solana_signTransaction",
3721
+ params: { transaction: encodeBase64(rawBytes) }
3722
+ },
3723
+ solanaMainnet.caipNetworkId
3724
+ );
3725
+ if (!result.transaction) {
3726
+ throw new Error(
3727
+ "WalletConnect wallet did not return a signed Solana transaction."
3728
+ );
3729
+ }
3730
+ const signedBytes = decodeBase64(result.transaction);
3731
+ return { serialize: () => signedBytes };
3732
+ },
3733
+ on() {
3734
+ },
3735
+ off() {
3736
+ },
3737
+ removeListener() {
3738
+ }
3739
+ };
3740
+ }
3741
+ async function buildWalletConnectAPI(walletCfg, ecosystem = "evm") {
3680
3742
  const connector = await getUniversalConnector(walletCfg);
3743
+ if (ecosystem === "solana") {
3744
+ return toSolanaWalletInterface(buildWalletConnectSolanaProvider(connector));
3745
+ }
3681
3746
  const provider = connector.provider;
3682
3747
  const api = {
3683
3748
  ecosystem: "evm",
@@ -3753,7 +3818,7 @@ function useWireDetectionIntoManager() {
3753
3818
  function useWalletConnectConnect(walletCfg) {
3754
3819
  const cfgRef = { current: walletCfg };
3755
3820
  return (0, import_react2.useCallback)(
3756
- () => walletManager.connectWalletConnect(cfgRef.current),
3821
+ (ecosystem) => walletManager.connectWalletConnect(cfgRef.current, ecosystem),
3757
3822
  []
3758
3823
  );
3759
3824
  }
@@ -3773,6 +3838,7 @@ function useWalletInfo(wagmi) {
3773
3838
  connectedVia: snapshot.connectedVia,
3774
3839
  walletType: snapshot.walletType,
3775
3840
  status: snapshot.status,
3841
+ detected: snapshot.detected,
3776
3842
  disconnect
3777
3843
  };
3778
3844
  }
@@ -3925,44 +3991,39 @@ var init_manager = __esm({
3925
3991
  this.emit();
3926
3992
  }
3927
3993
  }
3928
- async connectWalletConnect(walletCfg) {
3929
- if (this._status === "connected" && this._connectedVia === "walletconnect" && this._wallet) {
3994
+ async connectWalletConnect(walletCfg, ecosystem = "evm") {
3995
+ if (this._status === "connected" && this._connectedVia === "walletconnect" && this._wallet && this._wallet.ecosystem === ecosystem) {
3930
3996
  this.emit();
3931
3997
  return { error: null, api: this._wallet };
3932
3998
  }
3999
+ if (this._connectedVia === "walletconnect" && this._wallet) {
4000
+ await this._wallet.disconnect?.().catch(() => {
4001
+ });
4002
+ resetUniversalConnector();
4003
+ }
3933
4004
  this._status = "connecting";
3934
4005
  this.clearConnectedState();
3935
4006
  this.emit();
3936
4007
  try {
3937
4008
  const connector = await getUniversalConnector(walletCfg);
3938
4009
  await connector.connect();
3939
- const api = await buildWalletConnectAPI(walletCfg);
4010
+ const api = await buildWalletConnectAPI(walletCfg, ecosystem);
4011
+ try {
4012
+ await api.getAddress();
4013
+ } catch {
4014
+ await api.disconnect?.().catch(() => {
4015
+ });
4016
+ resetUniversalConnector();
4017
+ throw new Error(
4018
+ `This wallet did not approve a${ecosystem === "evm" ? "n" : ""} ${ecosystem === "evm" ? "EVM" : "Solana"} account over WalletConnect.`
4019
+ );
4020
+ }
3940
4021
  this._wallet = api;
3941
4022
  this._connectedVia = "walletconnect";
3942
4023
  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
- });
4024
+ this._providerCleanup = this.bindWalletConnectProviderEvents(
4025
+ connector.provider
4026
+ );
3966
4027
  await this.syncIdentityFromWallet("walletconnect");
3967
4028
  this._status = "connected";
3968
4029
  this._error = null;
@@ -3977,6 +4038,100 @@ var init_manager = __esm({
3977
4038
  return { error: message, api: null };
3978
4039
  }
3979
4040
  }
4041
+ bindWalletConnectProviderEvents(provider) {
4042
+ return bindWalletConnectEvents(provider, {
4043
+ onAccountsChanged: (accounts) => {
4044
+ if (accounts.length === 0) {
4045
+ this.fullReset();
4046
+ this.triggerExternalDisconnect();
4047
+ this.emit();
4048
+ return;
4049
+ }
4050
+ void this.syncIdentityFromWallet("walletconnect");
4051
+ this.emit();
4052
+ },
4053
+ onChainChanged: () => {
4054
+ void this.syncIdentityFromWallet("walletconnect");
4055
+ this.emit();
4056
+ },
4057
+ onDisconnect: () => {
4058
+ this.fullReset();
4059
+ resetUniversalConnector();
4060
+ this.triggerExternalDisconnect();
4061
+ this.emit();
4062
+ }
4063
+ });
4064
+ }
4065
+ // WalletConnect's own SignClient auto-restores the last persisted session
4066
+ // from storage on every init — including after a fresh page load — but
4067
+ // that restoration happens silently inside the library. Nothing calls back
4068
+ // into our code for it. On mobile, backgrounding the tab to approve in a
4069
+ // wallet app can cause the OS to reload the page before the original
4070
+ // connect() promise ever resolves, so the connect flow that triggered the
4071
+ // approval never gets to record it as "connected" here — even though
4072
+ // WalletConnect itself already has a live, approved session sitting in
4073
+ // storage. Call this on mount to pick that back up.
4074
+ async restoreWalletConnectSession(walletCfg) {
4075
+ if (this._status === "connected" && this._connectedVia === "walletconnect") {
4076
+ return this._wallet?.ecosystem === "solana" ? "solana" : "evm";
4077
+ }
4078
+ if (typeof window === "undefined") return null;
4079
+ try {
4080
+ if (!Object.keys(window.localStorage).some((key) => key.startsWith("wc@2"))) {
4081
+ return null;
4082
+ }
4083
+ } catch {
4084
+ }
4085
+ let connector;
4086
+ try {
4087
+ connector = await getUniversalConnector(walletCfg);
4088
+ } catch (e2) {
4089
+ console.warn(
4090
+ "[Trustware SDK] Failed to restore WalletConnect session:",
4091
+ e2
4092
+ );
4093
+ return null;
4094
+ }
4095
+ const session = connector.provider.session;
4096
+ if (!session) return null;
4097
+ const ecosystem = session.namespaces?.solana?.accounts?.length ? "solana" : session.namespaces?.eip155?.accounts?.length ? "evm" : null;
4098
+ if (!ecosystem) return null;
4099
+ try {
4100
+ const api = await buildWalletConnectAPI(walletCfg, ecosystem);
4101
+ this._wallet = api;
4102
+ this._connectedVia = "walletconnect";
4103
+ this._connectedWalletId = "walletconnect";
4104
+ this._providerCleanup = this.bindWalletConnectProviderEvents(
4105
+ connector.provider
4106
+ );
4107
+ await this.syncIdentityFromWallet("walletconnect");
4108
+ this._status = "connected";
4109
+ this._error = null;
4110
+ this.emit();
4111
+ return ecosystem;
4112
+ } catch {
4113
+ return null;
4114
+ }
4115
+ }
4116
+ // Forcibly abandon an in-progress connect() call the caller has decided is
4117
+ // stuck (e.g. the UI's own connect timeout elapsed with no response).
4118
+ // There's no clean way to cancel a pending WalletConnect pairing proposal
4119
+ // from this side, so this tears down the whole connector — the next
4120
+ // connect attempt starts against a brand new SignClient/pairing instead of
4121
+ // racing the abandoned one, which would otherwise risk reproducing the
4122
+ // "No matching key. proposal" class of error a real retry needs to avoid.
4123
+ cancelWalletConnectAttempt() {
4124
+ if (this._connectedVia === "walletconnect" && this._status === "connected") {
4125
+ return;
4126
+ }
4127
+ resetUniversalConnector();
4128
+ if (this._status === "connecting") {
4129
+ this.clearConnectedState();
4130
+ this._status = "idle";
4131
+ this._error = null;
4132
+ this.emit();
4133
+ }
4134
+ }
3980
4135
  async disconnect(wagmi) {
3981
4136
  if (wagmi && this._connectedVia === "extension") {
3982
4137
  await wagmi.disconnect().catch(() => {
@@ -7674,12 +7829,71 @@ var init_useWalletSessionState = __esm({
7674
7829
  // src/widget/state/deposit/useWalletConnect.ts
7675
7830
  function useWalletConnect({
7676
7831
  setWalletType,
7677
- setCurrentStep
7832
+ setCurrentStep,
7833
+ selectedNamespace,
7834
+ setSelectedNamespace
7678
7835
  }) {
7679
7836
  const walletConnectCfg = TrustwareConfigStore.peek()?.walletConnect;
7680
7837
  const connectWC = useWalletConnectConnect(walletConnectCfg);
7838
+ const ecosystem = selectedNamespace.trim().toLowerCase() === "solana" ? "solana" : "evm";
7839
+ const [wcStatus, setWcStatus] = (0, import_react9.useState)("idle");
7840
+ const [wcErrorMessage, setWcErrorMessage] = (0, import_react9.useState)(null);
7841
+ const wcTimeoutRef = (0, import_react9.useRef)(null);
7842
+ const clearWcTimeout = (0, import_react9.useCallback)(() => {
7843
+ if (wcTimeoutRef.current !== null) {
7844
+ clearTimeout(wcTimeoutRef.current);
7845
+ wcTimeoutRef.current = null;
7846
+ }
7847
+ }, []);
7848
+ const beginWcAttempt = (0, import_react9.useCallback)(() => {
7849
+ setWcStatus("connecting");
7850
+ setWcErrorMessage(null);
7851
+ clearWcTimeout();
7852
+ wcTimeoutRef.current = setTimeout(() => {
7853
+ wcTimeoutRef.current = null;
7854
+ setWcStatus((prev) => prev === "connecting" ? "timedOut" : prev);
7855
+ }, WC_CONNECT_TIMEOUT_MS);
7856
+ }, [clearWcTimeout]);
7857
+ const resolveWcAttempt = (0, import_react9.useCallback)(() => {
7858
+ clearWcTimeout();
7859
+ setWcStatus("idle");
7860
+ setWcErrorMessage(null);
7861
+ }, [clearWcTimeout]);
7862
+ const failWcAttempt = (0, import_react9.useCallback)(
7863
+ (message) => {
7864
+ clearWcTimeout();
7865
+ setWcStatus("failed");
7866
+ setWcErrorMessage(message);
7867
+ },
7868
+ [clearWcTimeout]
7869
+ );
7870
+ const dismissWcStatus = (0, import_react9.useCallback)(() => {
7871
+ clearWcTimeout();
7872
+ setWcStatus("idle");
7873
+ setWcErrorMessage(null);
7874
+ }, [clearWcTimeout]);
7875
+ (0, import_react9.useEffect)(() => clearWcTimeout, [clearWcTimeout]);
7876
+ (0, import_react9.useEffect)(() => {
7877
+ let cancelled = false;
7878
+ beginWcAttempt();
7879
+ void (async () => {
7880
+ const restoredEcosystem = await walletManager.restoreWalletConnectSession(walletConnectCfg);
7881
+ if (cancelled) return;
7882
+ resolveWcAttempt();
7883
+ if (!restoredEcosystem) return;
7884
+ setWalletType("walletconnect");
7885
+ if (restoredEcosystem === "solana") {
7886
+ setSelectedNamespace("Solana");
7887
+ }
7888
+ const address = walletManager.identity?.addresses[0]?.address ?? null;
7889
+ if (address) setCurrentStep("crypto-pay");
7890
+ })();
7891
+ return () => {
7892
+ cancelled = true;
7893
+ };
7894
+ }, []);
7681
7895
  const WalletConnect = (0, import_react9.useCallback)(async () => {
7682
- if (walletManager.status === "connected" && walletManager.connectedVia === "walletconnect") {
7896
+ if (walletManager.status === "connected" && walletManager.connectedVia === "walletconnect" && walletManager.wallet?.ecosystem === ecosystem) {
7683
7897
  const address = walletManager.identity?.addresses[0]?.address ?? null;
7684
7898
  if (address) {
7685
7899
  setWalletType("walletconnect");
@@ -7688,35 +7902,60 @@ function useWalletConnect({
7688
7902
  }
7689
7903
  }
7690
7904
  setWalletType("walletconnect");
7691
- const { error } = await connectWC();
7905
+ beginWcAttempt();
7906
+ const { error } = await connectWC(ecosystem);
7692
7907
  if (!error) {
7693
7908
  const address = walletManager.identity?.addresses[0]?.address ?? null;
7694
7909
  if (address) {
7910
+ resolveWcAttempt();
7695
7911
  setCurrentStep("crypto-pay");
7912
+ } else {
7913
+ const message = `WalletConnect session established but no address resolved for ecosystem "${ecosystem}".`;
7914
+ console.error(`[Trustware SDK] ${message}`);
7915
+ failWcAttempt(message);
7696
7916
  }
7697
7917
  } else {
7918
+ console.error("[Trustware SDK] WalletConnect connection failed:", error);
7919
+ failWcAttempt(error);
7698
7920
  setWalletType("other");
7699
7921
  }
7700
- }, [connectWC, setCurrentStep, setWalletType]);
7922
+ }, [
7923
+ beginWcAttempt,
7924
+ connectWC,
7925
+ ecosystem,
7926
+ failWcAttempt,
7927
+ resolveWcAttempt,
7928
+ setCurrentStep,
7929
+ setWalletType
7930
+ ]);
7931
+ const retryWalletConnect = (0, import_react9.useCallback)(() => {
7932
+ walletManager.cancelWalletConnectAttempt();
7933
+ void WalletConnect();
7934
+ }, [WalletConnect]);
7701
7935
  const disconnectWalletConnect = (0, import_react9.useCallback)(async () => {
7702
7936
  await walletManager.disconnect();
7703
7937
  setWalletType("other");
7704
7938
  setCurrentStep("home");
7705
7939
  }, [setCurrentStep, setWalletType]);
7706
- const walletConnectAddress = walletManager.status === "connected" && walletManager.connectedVia === "walletconnect" ? walletManager.wallet?.ecosystem === "evm" ? walletManager.identity?.addresses[0]?.address ?? null : null : null;
7940
+ const walletConnectAddress = walletManager.status === "connected" && walletManager.connectedVia === "walletconnect" ? walletManager.identity?.addresses[0]?.address ?? null : null;
7707
7941
  return {
7708
7942
  walletConnectAddress,
7709
7943
  WalletConnect,
7710
- disconnectWalletConnect
7944
+ disconnectWalletConnect,
7945
+ wcStatus,
7946
+ wcErrorMessage,
7947
+ retryWalletConnect,
7948
+ dismissWcStatus
7711
7949
  };
7712
7950
  }
7713
- var import_react9;
7951
+ var import_react9, WC_CONNECT_TIMEOUT_MS;
7714
7952
  var init_useWalletConnect = __esm({
7715
7953
  "src/widget/state/deposit/useWalletConnect.ts"() {
7716
7954
  "use strict";
7717
7955
  import_react9 = require("react");
7718
7956
  init_config2();
7719
7957
  init_wallets();
7958
+ WC_CONNECT_TIMEOUT_MS = 3e4;
7720
7959
  }
7721
7960
  });
7722
7961
 
@@ -7807,14 +8046,24 @@ function DepositProvider({
7807
8046
  const [walletType, setWalletType] = (0, import_react11.useState)(
7808
8047
  "other"
7809
8048
  );
7810
- const { walletConnectAddress, WalletConnect, disconnectWalletConnect } = useWalletConnect({
8049
+ const [selectedNamespace, setSelectedNamespace] = (0, import_react11.useState)("evm");
8050
+ const {
8051
+ walletConnectAddress,
8052
+ WalletConnect,
8053
+ disconnectWalletConnect,
8054
+ wcStatus,
8055
+ wcErrorMessage,
8056
+ retryWalletConnect,
8057
+ dismissWcStatus
8058
+ } = useWalletConnect({
7811
8059
  setWalletType,
7812
- setCurrentStep
8060
+ setCurrentStep,
8061
+ selectedNamespace,
8062
+ setSelectedNamespace
7813
8063
  });
7814
8064
  const [selectedToken, setSelectedToken] = (0, import_react11.useState)(null);
7815
8065
  const [selectedChain, setSelectedChain] = (0, import_react11.useState)(null);
7816
8066
  const [amount, setAmount] = (0, import_react11.useState)("");
7817
- const [selectedNamespace, setSelectedNamespace] = (0, import_react11.useState)("evm");
7818
8067
  const walletAddress = (0, import_react11.useMemo)(
7819
8068
  () => walletType === "walletconnect" ? walletConnectAddress : otherWalletAddress,
7820
8069
  [walletType, walletConnectAddress, otherWalletAddress]
@@ -7886,7 +8135,11 @@ function DepositProvider({
7886
8135
  setWalletType,
7887
8136
  walletType,
7888
8137
  selectedNamespace,
7889
- setSelectedNamespace
8138
+ setSelectedNamespace,
8139
+ wcStatus,
8140
+ wcErrorMessage,
8141
+ retryWalletConnect,
8142
+ dismissWcStatus
7890
8143
  }),
7891
8144
  [
7892
8145
  WalletConnect,
@@ -7902,7 +8155,11 @@ function DepositProvider({
7902
8155
  yourWalletTokens,
7903
8156
  yourWalletTokensLoading,
7904
8157
  selectedNamespace,
7905
- setSelectedNamespace
8158
+ setSelectedNamespace,
8159
+ wcStatus,
8160
+ wcErrorMessage,
8161
+ retryWalletConnect,
8162
+ dismissWcStatus
7906
8163
  ]
7907
8164
  );
7908
8165
  const formValue = (0, import_react11.useMemo)(
@@ -16218,6 +16475,18 @@ var init_WalletNamespaceTabs = __esm({
16218
16475
  });
16219
16476
 
16220
16477
  // src/widget/features/wallet/components/CryptoWalletDropdownContent.tsx
16478
+ function ecosystemToNamespace(ecosystem) {
16479
+ switch (ecosystem.trim().toLowerCase()) {
16480
+ case "evm":
16481
+ return "evm";
16482
+ case "solana":
16483
+ return "Solana";
16484
+ case "bitcoin":
16485
+ return "bitcoin";
16486
+ default:
16487
+ return null;
16488
+ }
16489
+ }
16221
16490
  function DesktopWalletDropdownContent({
16222
16491
  browserWallets,
16223
16492
  handleWalletConnect,
@@ -16283,11 +16552,13 @@ function DesktopWalletDropdownContent({
16283
16552
  );
16284
16553
  }
16285
16554
  function MobileWalletDropdownContent({
16286
- handleWalletConnect
16555
+ browserWallets,
16556
+ handleWalletConnect,
16557
+ handleWalletSelect: connectDetectedWallet2
16287
16558
  }) {
16288
16559
  const { setCurrentStep } = useDepositNavigation();
16289
- const { selectedNamespace } = useDepositWallet();
16290
- const { walletMetaId, isConnected, status } = useWalletInfo();
16560
+ const { selectedNamespace, setSelectedNamespace } = useDepositWallet();
16561
+ const { walletMetaId, isConnected, status, detected } = useWalletInfo();
16291
16562
  const [hoveredId, setHoveredId] = (0, import_react34.useState)(null);
16292
16563
  const storeFallbackTimeoutRef = (0, import_react34.useRef)(
16293
16564
  null
@@ -16299,22 +16570,52 @@ function MobileWalletDropdownContent({
16299
16570
  }
16300
16571
  };
16301
16572
  }, []);
16573
+ (0, import_react34.useEffect)(() => {
16574
+ if (browserWallets.length > 0) return;
16575
+ const otherEcosystemWallet = detected.find((d) => {
16576
+ if (d.meta.id === "walletconnect") return false;
16577
+ const ecosystem = d.meta.ecosystem.trim().toLowerCase();
16578
+ return ecosystem !== "multi" && ecosystem !== selectedNamespace.trim().toLowerCase();
16579
+ });
16580
+ if (!otherEcosystemWallet) return;
16581
+ const nextNamespace = ecosystemToNamespace(
16582
+ otherEcosystemWallet.meta.ecosystem
16583
+ );
16584
+ if (nextNamespace) setSelectedNamespace(nextNamespace);
16585
+ }, [browserWallets, detected, selectedNamespace, setSelectedNamespace]);
16302
16586
  const connectedWalletId = isConnected ? walletMetaId : null;
16303
16587
  const currentUrl = window.location.href;
16304
- const mobileWallets = (0, import_react34.useMemo)(
16305
- () => WALLETS.filter((w) => {
16306
- if (w.id === "walletconnect") return true;
16588
+ const mobileWallets = (0, import_react34.useMemo)(() => {
16589
+ const entries = WALLETS.filter((w) => {
16590
+ if (w.id === "walletconnect") {
16591
+ return selectedNamespace.trim().toLowerCase() === "evm";
16592
+ }
16593
+ const isDetected = browserWallets.some((d) => d.meta.id === w.id);
16307
16594
  const hasMobileLink = Boolean(w.deepLink);
16308
- if (!hasMobileLink) return false;
16595
+ if (!hasMobileLink && !isDetected) return false;
16309
16596
  return w.ecosystem.trim().toLowerCase() === "multi" || w.ecosystem.trim().toLowerCase() === selectedNamespace.trim().toLowerCase();
16310
- }),
16311
- [selectedNamespace]
16312
- );
16313
- const handleWalletSelect = (wallet) => {
16597
+ }).map((meta) => ({
16598
+ meta,
16599
+ detectedWallet: browserWallets.find((d) => d.meta.id === meta.id) ?? null
16600
+ }));
16601
+ const listedIds = new Set(entries.map((e2) => e2.meta.id));
16602
+ for (const detected2 of browserWallets) {
16603
+ if (!listedIds.has(detected2.meta.id)) {
16604
+ entries.push({ meta: detected2.meta, detectedWallet: detected2 });
16605
+ }
16606
+ }
16607
+ return entries;
16608
+ }, [browserWallets, selectedNamespace]);
16609
+ const handleWalletSelect = (entry) => {
16610
+ const { meta: wallet, detectedWallet } = entry;
16314
16611
  if (wallet.id === "walletconnect") {
16315
16612
  handleWalletConnect();
16316
16613
  return;
16317
16614
  }
16615
+ if (detectedWallet) {
16616
+ void connectDetectedWallet2(detectedWallet);
16617
+ return;
16618
+ }
16318
16619
  if (wallet.deepLink) {
16319
16620
  const deepLinkUrl = wallet.deepLink(currentUrl);
16320
16621
  if (deepLinkUrl) {
@@ -16384,15 +16685,16 @@ function MobileWalletDropdownContent({
16384
16685
  scrollbarWidth: "thin",
16385
16686
  scrollbarColor: `${colors.muted} transparent`
16386
16687
  },
16387
- children: mobileWallets.map((wallet) => {
16688
+ children: mobileWallets.map((entry) => {
16689
+ const wallet = entry.meta;
16388
16690
  const isConnectedWallet = wallet.id === connectedWalletId;
16389
- const isDisabled = isConnected && !isConnectedWallet;
16691
+ const isDisabled = isConnected && !isConnectedWallet && !entry.detectedWallet;
16390
16692
  const isHovered = hoveredId === wallet.id;
16391
16693
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
16392
16694
  "button",
16393
16695
  {
16394
16696
  type: "button",
16395
- onClick: () => !isDisabled && handleWalletSelect(wallet),
16697
+ onClick: () => !isDisabled && handleWalletSelect(entry),
16396
16698
  onMouseEnter: () => !isDisabled && setHoveredId(wallet.id),
16397
16699
  onMouseLeave: () => setHoveredId(null),
16398
16700
  style: {
@@ -16468,7 +16770,7 @@ function MobileWalletDropdownContent({
16468
16770
  }
16469
16771
  }
16470
16772
  ),
16471
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { style: { fontSize: fontSize.xs, color: "#22c55e" }, children: "Connected" })
16773
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { style: { fontSize: fontSize.xs, color: "#22c55e" }, children: "Continue" })
16472
16774
  ]
16473
16775
  }
16474
16776
  )
@@ -16533,7 +16835,9 @@ function CryptoWalletDropdownContent({
16533
16835
  isMobile && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
16534
16836
  MobileWalletDropdownContent,
16535
16837
  {
16536
- handleWalletConnect
16838
+ browserWallets,
16839
+ handleWalletConnect,
16840
+ handleWalletSelect
16537
16841
  }
16538
16842
  )
16539
16843
  ] });
@@ -17075,9 +17379,11 @@ function useHomeWalletActions({
17075
17379
  const { selectedNamespace } = useDepositWallet();
17076
17380
  const browserWallets = (0, import_react35.useMemo)(() => {
17077
17381
  if (!detectedWallets?.length) return [];
17078
- return detectedWallets.filter(
17079
- (wallet) => wallet?.meta?.id !== "walletconnect" && wallet?.meta?.ecosystem.trim().toLowerCase() === selectedNamespace.trim().toLowerCase()
17080
- );
17382
+ return detectedWallets.filter((wallet) => {
17383
+ if (wallet?.meta?.id === "walletconnect") return false;
17384
+ const ecosystem = wallet?.meta?.ecosystem.trim().toLowerCase();
17385
+ return ecosystem === "multi" || ecosystem === selectedNamespace.trim().toLowerCase();
17386
+ });
17081
17387
  }, [detectedWallets, selectedNamespace]);
17082
17388
  return {
17083
17389
  browserWallets,
@@ -17113,10 +17419,113 @@ var init_wallet = __esm({
17113
17419
  });
17114
17420
 
17115
17421
  // src/widget/pages/Home.tsx
17422
+ function WalletConnectStatusBanner({
17423
+ status,
17424
+ errorMessage,
17425
+ onRetry,
17426
+ onDismiss
17427
+ }) {
17428
+ const isDone = status !== "connecting";
17429
+ const isFailed = status === "failed";
17430
+ const { text, icon } = wcBannerCopy[status];
17431
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
17432
+ "div",
17433
+ {
17434
+ style: {
17435
+ display: "flex",
17436
+ alignItems: "center",
17437
+ gap: spacing[2],
17438
+ width: "100%",
17439
+ padding: `${spacing[2.5]} ${spacing[3]}`,
17440
+ marginBottom: spacing[4],
17441
+ borderRadius: borderRadius.lg,
17442
+ backgroundColor: isFailed ? "rgba(239,68,68,0.1)" : isDone ? "rgba(234,179,8,0.1)" : colors.muted,
17443
+ border: isFailed ? "1px solid rgba(239,68,68,0.4)" : isDone ? "1px solid rgba(234,179,8,0.4)" : `1px solid ${colors.border}`
17444
+ },
17445
+ children: [
17446
+ icon === "spinner" ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17447
+ "div",
17448
+ {
17449
+ style: {
17450
+ width: "0.875rem",
17451
+ height: "0.875rem",
17452
+ border: `2px solid ${colors.mutedForeground}`,
17453
+ borderTopColor: "transparent",
17454
+ borderRadius: "9999px",
17455
+ animation: "tw-spin 1s linear infinite",
17456
+ flexShrink: 0
17457
+ }
17458
+ }
17459
+ ) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { style: { fontSize: fontSize.sm, flexShrink: 0 }, "aria-hidden": true, children: icon }),
17460
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
17461
+ "p",
17462
+ {
17463
+ style: {
17464
+ flex: 1,
17465
+ fontSize: fontSize.xs,
17466
+ color: isDone ? colors.foreground : colors.mutedForeground,
17467
+ margin: 0
17468
+ },
17469
+ children: [
17470
+ text,
17471
+ isFailed && errorMessage ? ` ${errorMessage}` : ""
17472
+ ]
17473
+ }
17474
+ ),
17475
+ isDone && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
17476
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17477
+ "button",
17478
+ {
17479
+ type: "button",
17480
+ onClick: onRetry,
17481
+ style: {
17482
+ fontSize: fontSize.xs,
17483
+ fontWeight: fontWeight.semibold,
17484
+ color: colors.primary,
17485
+ backgroundColor: "transparent",
17486
+ border: 0,
17487
+ cursor: "pointer",
17488
+ flexShrink: 0
17489
+ },
17490
+ children: "Retry"
17491
+ }
17492
+ ),
17493
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17494
+ "button",
17495
+ {
17496
+ type: "button",
17497
+ onClick: onDismiss,
17498
+ "aria-label": "Dismiss",
17499
+ style: {
17500
+ fontSize: fontSize.xs,
17501
+ color: colors.mutedForeground,
17502
+ backgroundColor: "transparent",
17503
+ border: 0,
17504
+ cursor: "pointer",
17505
+ flexShrink: 0,
17506
+ padding: 0,
17507
+ lineHeight: 1
17508
+ },
17509
+ children: "\xD7"
17510
+ }
17511
+ )
17512
+ ] })
17513
+ ]
17514
+ }
17515
+ );
17516
+ }
17116
17517
  function Home({ style: _style }) {
17117
17518
  const { amount, setAmount, amountInputMode, setAmountInputMode } = useDepositForm();
17118
17519
  const { setCurrentStep, setCurrentStepInternal } = useDepositNavigation();
17119
- const { connectWallet, WalletConnect, setWalletType } = useDepositWallet();
17520
+ const {
17521
+ connectWallet,
17522
+ WalletConnect,
17523
+ setWalletType,
17524
+ wcStatus,
17525
+ wcErrorMessage,
17526
+ retryWalletConnect,
17527
+ dismissWcStatus
17528
+ } = useDepositWallet();
17120
17529
  const { resolvedTheme } = useDepositUi();
17121
17530
  const { fixedFromAmountString, isFixedAmount, minAmountUsd, maxAmountUsd } = useAmountConstraints();
17122
17531
  const { detected: detectedWallets } = useWalletDetection();
@@ -17198,6 +17607,15 @@ function Home({ style: _style }) {
17198
17607
  position: "relative"
17199
17608
  },
17200
17609
  children: [
17610
+ wcStatus !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17611
+ WalletConnectStatusBanner,
17612
+ {
17613
+ status: wcStatus,
17614
+ errorMessage: wcErrorMessage,
17615
+ onRetry: retryWalletConnect,
17616
+ onDismiss: dismissWcStatus
17617
+ }
17618
+ ),
17201
17619
  /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17202
17620
  "p",
17203
17621
  {
@@ -17273,7 +17691,7 @@ function Home({ style: _style }) {
17273
17691
  }
17274
17692
  );
17275
17693
  }
17276
- var import_jsx_runtime44;
17694
+ var import_jsx_runtime44, wcBannerCopy;
17277
17695
  var init_Home = __esm({
17278
17696
  "src/widget/pages/Home.tsx"() {
17279
17697
  "use strict";
@@ -17284,6 +17702,20 @@ var init_Home = __esm({
17284
17702
  init_wallets();
17285
17703
  init_wallet();
17286
17704
  import_jsx_runtime44 = require("react/jsx-runtime");
17705
+ wcBannerCopy = {
17706
+ connecting: {
17707
+ text: "Waiting for wallet approval via WalletConnect\u2026",
17708
+ icon: "spinner"
17709
+ },
17710
+ timedOut: {
17711
+ text: "Still waiting on WalletConnect \u2014 this is taking longer than expected.",
17712
+ icon: "\u26A0\uFE0F"
17713
+ },
17714
+ failed: {
17715
+ text: "WalletConnect connection failed.",
17716
+ icon: "\u2715"
17717
+ }
17718
+ };
17287
17719
  }
17288
17720
  });
17289
17721
 
@@ -33990,6 +34422,7 @@ function SwapWalletSelectorMobile({
33990
34422
  const { meta } = entry;
33991
34423
  const isWalletConnected = managerConnected && walletMetaId === meta.id;
33992
34424
  const isConnecting = connectingId === meta.id && walletStatus === "connecting";
34425
+ const isRowDisabled = managerConnected && !isWalletConnected && !entry.detectedWallet;
33993
34426
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
33994
34427
  "div",
33995
34428
  {
@@ -34007,7 +34440,8 @@ function SwapWalletSelectorMobile({
34007
34440
  isWalletConnected && {
34008
34441
  boxShadow: `0 0 0 2px ${colors.primary}`,
34009
34442
  border: `1px solid ${colors.primary}`
34010
- }
34443
+ },
34444
+ isRowDisabled && { opacity: 0.4 }
34011
34445
  ),
34012
34446
  children: [
34013
34447
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
@@ -34098,7 +34532,7 @@ function SwapWalletSelectorMobile({
34098
34532
  "button",
34099
34533
  {
34100
34534
  onClick: () => void handleClick(entry),
34101
- disabled: walletStatus === "connecting",
34535
+ disabled: walletStatus === "connecting" || isRowDisabled,
34102
34536
  style: mergeStyles(
34103
34537
  {
34104
34538
  padding: `${spacing[1.5]} ${spacing[3]}`,
@@ -34111,7 +34545,7 @@ function SwapWalletSelectorMobile({
34111
34545
  cursor: "pointer",
34112
34546
  flexShrink: 0
34113
34547
  },
34114
- walletStatus === "connecting" && {
34548
+ (walletStatus === "connecting" || isRowDisabled) && {
34115
34549
  opacity: 0.5,
34116
34550
  cursor: "not-allowed"
34117
34551
  }
@@ -34139,6 +34573,7 @@ function SwapWalletSelectorMobile({
34139
34573
  ),
34140
34574
  (() => {
34141
34575
  const wcConnected = managerConnected && connectedVia === "walletconnect";
34576
+ const wcRowDisabled = managerConnected && !wcConnected;
34142
34577
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
34143
34578
  "div",
34144
34579
  {
@@ -34157,9 +34592,10 @@ function SwapWalletSelectorMobile({
34157
34592
  wcConnected && {
34158
34593
  boxShadow: `0 0 0 2px ${colors.primary}`,
34159
34594
  border: `1px solid ${colors.primary}`
34160
- }
34595
+ },
34596
+ wcRowDisabled && { opacity: 0.4, cursor: "not-allowed" }
34161
34597
  ),
34162
- onClick: !wcConnected ? () => void handleWalletConnect() : void 0,
34598
+ onClick: !wcConnected && !wcRowDisabled ? () => void handleWalletConnect() : void 0,
34163
34599
  children: [
34164
34600
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
34165
34601
  "div",
@@ -34255,18 +34691,24 @@ function SwapWalletSelectorMobile({
34255
34691
  e2.stopPropagation();
34256
34692
  void handleWalletConnect();
34257
34693
  },
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
- },
34694
+ disabled: wcConnecting || wcRowDisabled,
34695
+ style: mergeStyles(
34696
+ {
34697
+ padding: `${spacing[1.5]} ${spacing[3]}`,
34698
+ borderRadius: "9999px",
34699
+ backgroundColor: "rgba(59,130,246,0.1)",
34700
+ color: colors.primary,
34701
+ fontSize: fontSize.xs,
34702
+ fontWeight: fontWeight.medium,
34703
+ border: 0,
34704
+ cursor: "pointer",
34705
+ flexShrink: 0
34706
+ },
34707
+ (wcConnecting || wcRowDisabled) && {
34708
+ opacity: 0.5,
34709
+ cursor: "not-allowed"
34710
+ }
34711
+ ),
34270
34712
  children: "Connect"
34271
34713
  }
34272
34714
  )
@@ -35174,7 +35616,7 @@ function SwapMode({
35174
35616
  }).catch(() => {
35175
35617
  });
35176
35618
  }, [defaultDestRef, allChains]);
35177
- const { walletAddress, walletStatus, connectWallet, disconnectWallet } = useWalletSessionState();
35619
+ const { walletAddress, walletStatus, connectWallet } = useWalletSessionState();
35178
35620
  const setFromTokenStable = (0, import_react50.useCallback)(
35179
35621
  (t) => setFromToken(t),
35180
35622
  []
@@ -37252,7 +37694,7 @@ function SwapMode({
37252
37694
  walletAddress ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
37253
37695
  "button",
37254
37696
  {
37255
- onClick: () => void disconnectWallet(),
37697
+ onClick: handleConnectAndReview,
37256
37698
  style: {
37257
37699
  fontSize: fontSize.xs,
37258
37700
  color: colors.mutedForeground,
@@ -37263,8 +37705,7 @@ function SwapMode({
37263
37705
  children: [
37264
37706
  walletAddress.slice(0, 6),
37265
37707
  "...",
37266
- walletAddress.slice(-4),
37267
- " \xD7"
37708
+ walletAddress.slice(-4)
37268
37709
  ]
37269
37710
  }
37270
37711
  ) : /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(