@unifold/connect-react 0.1.56 → 0.1.57

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.mjs CHANGED
@@ -1147,7 +1147,7 @@ ${new this._window.XMLSerializer().serializeToString(e3)}`;
1147
1147
  import React38, {
1148
1148
  useState as useState30,
1149
1149
  useCallback as useCallback13,
1150
- useMemo as useMemo15,
1150
+ useMemo as useMemo16,
1151
1151
  useEffect as useEffect33
1152
1152
  } from "react";
1153
1153
 
@@ -1230,7 +1230,7 @@ import {
1230
1230
  useLayoutEffect as useLayoutEffect22,
1231
1231
  useCallback as useCallback62,
1232
1232
  useRef as useRef82,
1233
- useMemo as useMemo92
1233
+ useMemo as useMemo10
1234
1234
  } from "react";
1235
1235
 
1236
1236
  // ../../node_modules/.pnpm/lucide-react@0.454.0_react@18.3.1/node_modules/lucide-react/dist/esm/createLucideIcon.js
@@ -6746,6 +6746,20 @@ async function refreshIntegrationToken(accessToken, publishableKey) {
6746
6746
  }
6747
6747
  return response.json();
6748
6748
  }
6749
+ async function revokeIntegrationToken(accessToken, publishableKey) {
6750
+ const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6751
+ validatePublishableKey(pk);
6752
+ await fetch(`${API_BASE_URL}/v1/public/integrations/token/revoke`, {
6753
+ method: "POST",
6754
+ headers: {
6755
+ accept: "application/json",
6756
+ "x-publishable-key": pk,
6757
+ "Content-Type": "application/json"
6758
+ },
6759
+ body: JSON.stringify({ access_token: accessToken })
6760
+ }).catch(() => {
6761
+ });
6762
+ }
6749
6763
  async function getIntegrationHoldings(provider, accessToken, publishableKey) {
6750
6764
  const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6751
6765
  validatePublishableKey(pk);
@@ -7373,21 +7387,22 @@ import * as React232 from "react";
7373
7387
  import { jsx as jsx34, jsxs as jsxs30 } from "react/jsx-runtime";
7374
7388
  import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
7375
7389
  import { jsx as jsx36, jsxs as jsxs322 } from "react/jsx-runtime";
7376
- import { useState as useState202, useEffect as useEffect162, useCallback as useCallback22, useRef as useRef52 } from "react";
7390
+ import { useState as useState202, useEffect as useEffect162, useCallback as useCallback22, useMemo as useMemo32, useRef as useRef52 } from "react";
7377
7391
  import { useQuery as useQuery4 } from "@tanstack/react-query";
7378
- import { Fragment as Fragment42, jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
7379
7392
  import { useQuery as useQuery5 } from "@tanstack/react-query";
7380
7393
  import { useQuery as useQuery6 } from "@tanstack/react-query";
7394
+ import { Fragment as Fragment42, jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
7381
7395
  import { useQuery as useQuery7 } from "@tanstack/react-query";
7382
7396
  import { useQuery as useQuery8 } from "@tanstack/react-query";
7383
7397
  import { useQuery as useQuery9 } from "@tanstack/react-query";
7384
- import { useState as useState26, useEffect as useEffect212, useMemo as useMemo52 } from "react";
7398
+ import { useQuery as useQuery10 } from "@tanstack/react-query";
7399
+ import { useState as useState26, useEffect as useEffect212, useMemo as useMemo62 } from "react";
7385
7400
  import { useEffect as useEffect182, useState as useState212 } from "react";
7386
7401
  import * as React262 from "react";
7387
7402
  import { jsx as jsx38 } from "react/jsx-runtime";
7388
7403
  import { jsx as jsx39, jsxs as jsxs34 } from "react/jsx-runtime";
7389
7404
  import { Fragment as Fragment52, jsx as jsx40, jsxs as jsxs35 } from "react/jsx-runtime";
7390
- import { useState as useState222, useMemo as useMemo42, useEffect as useEffect192 } from "react";
7405
+ import { useState as useState222, useMemo as useMemo52, useEffect as useEffect192 } from "react";
7391
7406
  import { jsx as jsx41, jsxs as jsxs36 } from "react/jsx-runtime";
7392
7407
  import { useState as useState232, useEffect as useEffect202, useRef as useRef62 } from "react";
7393
7408
  import { jsx as jsx422, jsxs as jsxs37 } from "react/jsx-runtime";
@@ -10131,10 +10146,10 @@ var Content22 = TooltipContent;
10131
10146
 
10132
10147
  // ../ui-react/dist/index.mjs
10133
10148
  import { jsx as jsx44 } from "react/jsx-runtime";
10134
- import { useQuery as useQuery10 } from "@tanstack/react-query";
10149
+ import { useQuery as useQuery11 } from "@tanstack/react-query";
10135
10150
  import { jsx as jsx45, jsxs as jsxs39 } from "react/jsx-runtime";
10136
10151
  import { Fragment as Fragment72, jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
10137
- import { useState as useState272, useEffect as useEffect222, useMemo as useMemo62 } from "react";
10152
+ import { useState as useState272, useEffect as useEffect222, useMemo as useMemo72 } from "react";
10138
10153
  import * as React282 from "react";
10139
10154
 
10140
10155
  // ../../node_modules/.pnpm/@radix-ui+react-select@2.2.6_@types+react-dom@19.2.3_@types+react@19.2.9__@types+react@19.2.9_5n4syhs66qrtkkphe44qzgdimq/node_modules/@radix-ui/react-select/dist/index.mjs
@@ -11373,7 +11388,7 @@ var Separator = SelectSeparator;
11373
11388
  import { jsx as jsx47, jsxs as jsxs41 } from "react/jsx-runtime";
11374
11389
  import { jsx as jsx48, jsxs as jsxs422 } from "react/jsx-runtime";
11375
11390
  import * as React292 from "react";
11376
- import { useQuery as useQuery11 } from "@tanstack/react-query";
11391
+ import { useQuery as useQuery12 } from "@tanstack/react-query";
11377
11392
  import { jsx as jsx49 } from "react/jsx-runtime";
11378
11393
  import { jsx as jsx50, jsxs as jsxs43 } from "react/jsx-runtime";
11379
11394
  import { Fragment as Fragment82, jsx as jsx51, jsxs as jsxs44 } from "react/jsx-runtime";
@@ -11390,9 +11405,9 @@ import {
11390
11405
  useLayoutEffect as useLayoutEffect32,
11391
11406
  useCallback as useCallback72,
11392
11407
  useRef as useRef92,
11393
- useMemo as useMemo102
11408
+ useMemo as useMemo112
11394
11409
  } from "react";
11395
- import { useQuery as useQuery12 } from "@tanstack/react-query";
11410
+ import { useQuery as useQuery13 } from "@tanstack/react-query";
11396
11411
  import { Fragment as Fragment13, jsx as jsx57, jsxs as jsxs50 } from "react/jsx-runtime";
11397
11412
  import {
11398
11413
  useState as useState36,
@@ -11401,22 +11416,22 @@ import {
11401
11416
  useCallback as useCallback92,
11402
11417
  useRef as useRef112
11403
11418
  } from "react";
11404
- import { useQuery as useQuery13 } from "@tanstack/react-query";
11405
11419
  import { useQuery as useQuery14 } from "@tanstack/react-query";
11406
11420
  import { useQuery as useQuery15 } from "@tanstack/react-query";
11407
11421
  import { useQuery as useQuery16 } from "@tanstack/react-query";
11422
+ import { useQuery as useQuery17 } from "@tanstack/react-query";
11408
11423
  import { useState as useState33, useEffect as useEffect282, useRef as useRef102 } from "react";
11409
11424
  import { jsx as jsx58, jsxs as jsxs51 } from "react/jsx-runtime";
11410
- import { useState as useState34, useCallback as useCallback82, useMemo as useMemo122, useEffect as useEffect292 } from "react";
11411
- import { useQuery as useQuery17 } from "@tanstack/react-query";
11412
- import { useMemo as useMemo112 } from "react";
11425
+ import { useState as useState34, useCallback as useCallback82, useMemo as useMemo132, useEffect as useEffect292 } from "react";
11413
11426
  import { useQuery as useQuery18 } from "@tanstack/react-query";
11427
+ import { useMemo as useMemo122 } from "react";
11428
+ import { useQuery as useQuery19 } from "@tanstack/react-query";
11414
11429
  import { Fragment as Fragment14, jsx as jsx59, jsxs as jsxs52 } from "react/jsx-runtime";
11415
11430
  import { jsx as jsx60, jsxs as jsxs53 } from "react/jsx-runtime";
11416
11431
  import { useState as useState35, useEffect as useEffect302 } from "react";
11417
11432
  import { Fragment as Fragment15, jsx as jsx61, jsxs as jsxs54 } from "react/jsx-runtime";
11418
11433
  import { Fragment as Fragment16, jsx as jsx622, jsxs as jsxs55 } from "react/jsx-runtime";
11419
- import { useState as useState37, useMemo as useMemo132 } from "react";
11434
+ import { useState as useState37, useMemo as useMemo142 } from "react";
11420
11435
  import { jsx as jsx63, jsxs as jsxs56 } from "react/jsx-runtime";
11421
11436
  function cn(...inputs) {
11422
11437
  return twMerge(clsx(inputs));
@@ -12759,7 +12774,8 @@ var en_default2 = {
12759
12774
  title: "Transfer Failed",
12760
12775
  tryAgain: "Try Again"
12761
12776
  },
12762
- continue: "Continue"
12777
+ continue: "Continue",
12778
+ disconnect: "Disconnect"
12763
12779
  },
12764
12780
  buyWithCard: {
12765
12781
  onramp: {
@@ -16006,6 +16022,7 @@ function PayWithExchangeButton({
16006
16022
  }
16007
16023
  function ConnectExchangeButton({
16008
16024
  onClick,
16025
+ onDisconnect,
16009
16026
  title,
16010
16027
  subtitle,
16011
16028
  exchanges,
@@ -16018,6 +16035,109 @@ function ConnectExchangeButton({
16018
16035
  setIsTouchDevice("ontouchstart" in window || navigator.maxTouchPoints > 0);
16019
16036
  }, []);
16020
16037
  const isConnected = connectedExchange != null;
16038
+ const handleDisconnectClick = (e) => {
16039
+ e.preventDefault();
16040
+ e.stopPropagation();
16041
+ onDisconnect?.();
16042
+ };
16043
+ const rowSurfaceStyle = {
16044
+ backgroundColor: isHovered ? colors2.cardHover : components.card.backgroundColor,
16045
+ borderRadius: components.card.borderRadius,
16046
+ border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
16047
+ };
16048
+ const iconBlock = isConnected ? connectedExchange.iconUrl ? /* @__PURE__ */ jsx19(
16049
+ "img",
16050
+ {
16051
+ src: connectedExchange.iconUrl,
16052
+ alt: connectedExchange.name,
16053
+ width: 36,
16054
+ height: 36,
16055
+ className: "uf-rounded-lg"
16056
+ }
16057
+ ) : /* @__PURE__ */ jsx19(
16058
+ "div",
16059
+ {
16060
+ className: "uf-w-9 uf-h-9 uf-rounded-lg uf-flex uf-items-center uf-justify-center",
16061
+ style: { backgroundColor: colors2.card },
16062
+ children: /* @__PURE__ */ jsx19(
16063
+ "span",
16064
+ {
16065
+ className: "uf-text-xs uf-font-medium",
16066
+ style: { color: components.card.iconColor },
16067
+ children: connectedExchange.name.slice(0, 2).toUpperCase()
16068
+ }
16069
+ )
16070
+ }
16071
+ ) : /* @__PURE__ */ jsx19("div", { className: "uf-rounded-lg uf-p-2", children: /* @__PURE__ */ jsx19(
16072
+ Link2,
16073
+ {
16074
+ className: "uf-w-5 uf-h-5",
16075
+ style: { color: components.card.iconColor }
16076
+ }
16077
+ ) });
16078
+ const titleSubtitleBlock = /* @__PURE__ */ jsxs16("div", { className: "uf-text-left", children: [
16079
+ /* @__PURE__ */ jsx19(
16080
+ "div",
16081
+ {
16082
+ className: "uf-text-sm uf-font-light uf-mb-0.5",
16083
+ style: {
16084
+ color: components.card.titleColor,
16085
+ fontFamily: fonts.regular
16086
+ },
16087
+ children: isConnected ? connectedExchange.name : title
16088
+ }
16089
+ ),
16090
+ isConnected && connectedExchange.isLoading ? /* @__PURE__ */ jsx19("div", { className: "uf-h-3 uf-w-24 uf-bg-muted uf-rounded uf-animate-pulse" }) : /* @__PURE__ */ jsx19(
16091
+ "div",
16092
+ {
16093
+ className: "uf-text-xs uf-font-light",
16094
+ style: {
16095
+ color: components.card.subtitleColor,
16096
+ fontFamily: fonts.regular
16097
+ },
16098
+ children: isConnected ? connectedExchange.balanceUsd ? `$${connectedExchange.balanceUsd} \u2022 2 min` : "Deposit from exchange" : subtitle
16099
+ }
16100
+ )
16101
+ ] });
16102
+ if (isConnected && onDisconnect) {
16103
+ return /* @__PURE__ */ jsxs16(
16104
+ "div",
16105
+ {
16106
+ onMouseEnter: () => !isTouchDevice && setIsHovered(true),
16107
+ onMouseLeave: () => setIsHovered(false),
16108
+ onTouchStart: () => setIsHovered(false),
16109
+ className: "uf-w-full uf-transition-colors uf-flex uf-items-stretch uf-group",
16110
+ style: rowSurfaceStyle,
16111
+ children: [
16112
+ /* @__PURE__ */ jsxs16(
16113
+ "button",
16114
+ {
16115
+ type: "button",
16116
+ onClick,
16117
+ className: "uf-min-w-0 uf-flex-1 uf-flex uf-items-center uf-gap-3 uf-p-3 uf-pr-1 uf-text-left uf-border-0 uf-bg-transparent hover:uf-bg-transparent",
16118
+ children: [
16119
+ iconBlock,
16120
+ titleSubtitleBlock
16121
+ ]
16122
+ }
16123
+ ),
16124
+ /* @__PURE__ */ jsx19("div", { className: "uf-flex uf-items-center uf-gap-1 uf-shrink-0 uf-pr-2 uf-pl-0", children: /* @__PURE__ */ jsx19(
16125
+ "button",
16126
+ {
16127
+ type: "button",
16128
+ onClick: handleDisconnectClick,
16129
+ className: "uf-h-auto uf-min-h-8 uf-py-1.5 uf-px-2 uf-text-xs uf-font-light uf-shrink-0 uf-border-0 uf-bg-transparent uf-cursor-pointer hover:uf-opacity-80 uf-transition-opacity",
16130
+ style: {
16131
+ color: colors2.error,
16132
+ fontFamily: fonts.regular
16133
+ },
16134
+ children: i18n2.connectExchange.disconnect
16135
+ }
16136
+ ) })
16137
+ ]
16138
+ }
16139
+ );
16140
+ }
16021
16141
  return /* @__PURE__ */ jsxs16(
16022
16142
  "button",
16023
16143
  {
@@ -16026,67 +16146,11 @@ function ConnectExchangeButton({
16026
16146
  onMouseLeave: () => setIsHovered(false),
16027
16147
  onTouchStart: () => setIsHovered(false),
16028
16148
  className: "uf-w-full uf-transition-colors uf-p-3 uf-flex uf-items-center uf-justify-between uf-group",
16029
- style: {
16030
- backgroundColor: isHovered ? colors2.cardHover : components.card.backgroundColor,
16031
- borderRadius: components.card.borderRadius,
16032
- border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
16033
- },
16149
+ style: rowSurfaceStyle,
16034
16150
  children: [
16035
16151
  /* @__PURE__ */ jsxs16("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
16036
- isConnected ? connectedExchange.iconUrl ? /* @__PURE__ */ jsx19(
16037
- "img",
16038
- {
16039
- src: connectedExchange.iconUrl,
16040
- alt: connectedExchange.name,
16041
- width: 36,
16042
- height: 36,
16043
- className: "uf-rounded-lg"
16044
- }
16045
- ) : /* @__PURE__ */ jsx19(
16046
- "div",
16047
- {
16048
- className: "uf-w-9 uf-h-9 uf-rounded-lg uf-flex uf-items-center uf-justify-center",
16049
- style: { backgroundColor: colors2.card },
16050
- children: /* @__PURE__ */ jsx19(
16051
- "span",
16052
- {
16053
- className: "uf-text-xs uf-font-medium",
16054
- style: { color: components.card.iconColor },
16055
- children: connectedExchange.name.slice(0, 2).toUpperCase()
16056
- }
16057
- )
16058
- }
16059
- ) : /* @__PURE__ */ jsx19("div", { className: "uf-rounded-lg uf-p-2", children: /* @__PURE__ */ jsx19(
16060
- Link2,
16061
- {
16062
- className: "uf-w-5 uf-h-5",
16063
- style: { color: components.card.iconColor }
16064
- }
16065
- ) }),
16066
- /* @__PURE__ */ jsxs16("div", { className: "uf-text-left", children: [
16067
- /* @__PURE__ */ jsx19(
16068
- "div",
16069
- {
16070
- className: "uf-text-sm uf-font-light uf-mb-0.5",
16071
- style: {
16072
- color: components.card.titleColor,
16073
- fontFamily: fonts.regular
16074
- },
16075
- children: isConnected ? connectedExchange.name : title
16076
- }
16077
- ),
16078
- isConnected && connectedExchange.isLoading ? /* @__PURE__ */ jsx19("div", { className: "uf-h-3 uf-w-24 uf-bg-muted uf-rounded uf-animate-pulse" }) : /* @__PURE__ */ jsx19(
16079
- "div",
16080
- {
16081
- className: "uf-text-xs uf-font-light",
16082
- style: {
16083
- color: components.card.subtitleColor,
16084
- fontFamily: fonts.regular
16085
- },
16086
- children: isConnected ? connectedExchange.balanceUsd ? `$${connectedExchange.balanceUsd} \u2022 2 min` : "Deposit from exchange" : subtitle
16087
- }
16088
- )
16089
- ] })
16152
+ iconBlock,
16153
+ titleSubtitleBlock
16090
16154
  ] }),
16091
16155
  /* @__PURE__ */ jsxs16("div", { className: "uf-flex uf-items-center uf-gap-1.5", children: [
16092
16156
  !isConnected && exchanges && exchanges.length > 0 ? exchanges.slice(0, 4).map((ex, i) => {
@@ -18891,6 +18955,65 @@ function useProjectConfig({
18891
18955
  });
18892
18956
  return { projectConfig, isLoading };
18893
18957
  }
18958
+ function useSupportedDepositTokens(publishableKey, options) {
18959
+ const hasDestination = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type;
18960
+ const filteredOptions = {
18961
+ ...hasDestination ? {
18962
+ destination_token_address: options.destination_token_address,
18963
+ destination_chain_id: options.destination_chain_id,
18964
+ destination_chain_type: options.destination_chain_type
18965
+ } : {},
18966
+ ...options?.product_type ? { product_type: options.product_type } : {}
18967
+ };
18968
+ const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
18969
+ return useQuery5({
18970
+ queryKey: [
18971
+ "unifold",
18972
+ "supportedDepositTokens",
18973
+ publishableKey,
18974
+ filteredOptions?.destination_token_address ?? null,
18975
+ filteredOptions?.destination_chain_id ?? null,
18976
+ filteredOptions?.destination_chain_type ?? null,
18977
+ filteredOptions?.product_type ?? null
18978
+ ],
18979
+ queryFn: () => getSupportedDepositTokens(
18980
+ publishableKey,
18981
+ hasFilteredOptions ? filteredOptions : void 0
18982
+ ),
18983
+ staleTime: 1e3 * 60 * 5,
18984
+ // 5 minutes — token list rarely changes
18985
+ gcTime: 1e3 * 60 * 30,
18986
+ // 30 minutes in cache
18987
+ refetchOnMount: false,
18988
+ refetchOnWindowFocus: false
18989
+ });
18990
+ }
18991
+ function useIntegrationTransferDefaultToken({
18992
+ params,
18993
+ publishableKey,
18994
+ enabled = true
18995
+ }) {
18996
+ return useQuery6({
18997
+ queryKey: [
18998
+ "unifold",
18999
+ "integrationTransferDefaultToken",
19000
+ publishableKey,
19001
+ params?.integration_provider ?? null,
19002
+ params?.source_currency ?? null,
19003
+ params?.destination_token_address ?? null,
19004
+ params?.destination_chain_id ?? null,
19005
+ params?.destination_chain_type ?? null,
19006
+ params?.country_code ?? null,
19007
+ params?.subdivision_code ?? null
19008
+ ],
19009
+ queryFn: () => getIntegrationTransferDefaultToken(params, publishableKey),
19010
+ enabled: enabled && !!params,
19011
+ staleTime: 1e3 * 60 * 5,
19012
+ gcTime: 1e3 * 60 * 30,
19013
+ refetchOnMount: false,
19014
+ refetchOnWindowFocus: false
19015
+ });
19016
+ }
18894
19017
  var INTEGRATIONS_STORAGE_KEY = "unifold:integrations:connected";
18895
19018
  function getStoredIntegrations() {
18896
19019
  try {
@@ -18935,6 +19058,23 @@ function CoinbaseConnect({
18935
19058
  const { colors: colors2, fonts, components } = useTheme();
18936
19059
  const { projectConfig } = useProjectConfig({ publishableKey });
18937
19060
  const { userIpInfo } = useUserIp2();
19061
+ const { data: supportedTokensData, isLoading: supportedTokensLoading } = useSupportedDepositTokens(publishableKey, {
19062
+ destination_token_address: destinationTokenAddress,
19063
+ destination_chain_id: destinationChainId,
19064
+ destination_chain_type: destinationChainType
19065
+ });
19066
+ const supportedSymbols = useMemo32(() => {
19067
+ const set = /* @__PURE__ */ new Set();
19068
+ supportedTokensData?.data.forEach((token) => set.add(token.symbol.toLowerCase()));
19069
+ return set;
19070
+ }, [supportedTokensData]);
19071
+ const stablecoinSymbols = useMemo32(() => {
19072
+ const set = /* @__PURE__ */ new Set();
19073
+ supportedTokensData?.data.forEach((token) => {
19074
+ if (token.is_stablecoin) set.add(token.symbol.toLowerCase());
19075
+ });
19076
+ return set;
19077
+ }, [supportedTokensData]);
18938
19078
  const appName = projectConfig?.project_name ?? "Unifold";
18939
19079
  const t12 = i18n2.connectExchange;
18940
19080
  const initialView = skipToHoldings && getStoredIntegrationToken(IntegrationProvider.COINBASE) ? "holdings" : "select_exchange";
@@ -18957,7 +19097,43 @@ function CoinbaseConnect({
18957
19097
  const [confirmResult, setConfirmResult] = useState202(null);
18958
19098
  const [showTransferDetails, setShowTransferDetails] = useState202(false);
18959
19099
  const [transferDepositWalletId, setTransferDepositWalletId] = useState202(void 0);
18960
- const [minDepositUsd, setMinDepositUsd] = useState202(0);
19100
+ const exchangeSupportedCurrencies = useMemo32(() => {
19101
+ const set = /* @__PURE__ */ new Set();
19102
+ selectedExchange?.supported_currencies.forEach((c) => set.add(c.toLowerCase()));
19103
+ return set;
19104
+ }, [selectedExchange]);
19105
+ const defaultTokenParams = useMemo32(
19106
+ () => selectedAsset ? {
19107
+ integration_provider: IntegrationProvider.COINBASE,
19108
+ source_currency: selectedAsset.currency.toLowerCase(),
19109
+ destination_token_address: destinationTokenAddress,
19110
+ destination_chain_id: destinationChainId,
19111
+ destination_chain_type: destinationChainType,
19112
+ country_code: userIpInfo?.alpha2,
19113
+ subdivision_code: userIpInfo?.subdivisionCode ?? void 0
19114
+ } : null,
19115
+ [selectedAsset, destinationTokenAddress, destinationChainId, destinationChainType, userIpInfo?.alpha2, userIpInfo?.subdivisionCode]
19116
+ );
19117
+ const { data: defaultTokenData, isLoading: defaultTokenLoading } = useIntegrationTransferDefaultToken({
19118
+ params: defaultTokenParams,
19119
+ publishableKey
19120
+ });
19121
+ const sortedHoldings = useMemo32(() => {
19122
+ const supported = [];
19123
+ const unsupported = [];
19124
+ holdings.forEach((account) => {
19125
+ const currencyLower = account.currency.toLowerCase();
19126
+ const isSupported = (supportedSymbols.size === 0 || supportedSymbols.has(currencyLower)) && (exchangeSupportedCurrencies.size === 0 || exchangeSupportedCurrencies.has(currencyLower));
19127
+ if (isSupported) supported.push(account);
19128
+ else unsupported.push(account);
19129
+ });
19130
+ return [...supported, ...unsupported];
19131
+ }, [holdings, supportedSymbols, exchangeSupportedCurrencies]);
19132
+ const selectedHoldingIsSupported = useMemo32(() => {
19133
+ if (!selectedHolding) return false;
19134
+ const currencyLower = selectedHolding.currency.toLowerCase();
19135
+ return (supportedSymbols.size === 0 || supportedSymbols.has(currencyLower)) && (exchangeSupportedCurrencies.size === 0 || exchangeSupportedCurrencies.has(currencyLower));
19136
+ }, [selectedHolding, supportedSymbols, exchangeSupportedCurrencies]);
18961
19137
  const exchangeName = selectedExchange?.service_provider_display_name || "Exchange";
18962
19138
  const {
18963
19139
  executions: depositExecutions,
@@ -19073,53 +19249,17 @@ function CoinbaseConnect({
19073
19249
  if (pollRef.current) clearInterval(pollRef.current);
19074
19250
  };
19075
19251
  }, []);
19076
- useEffect162(() => {
19077
- if (view !== "enter_amount" || !selectedAsset) return;
19078
- let cancelled = false;
19079
- const fetchMinDeposit = async () => {
19080
- try {
19081
- const [defaultToken, supportedTokens] = await Promise.all([
19082
- getIntegrationTransferDefaultToken(
19083
- {
19084
- integration_provider: IntegrationProvider.COINBASE,
19085
- source_currency: selectedAsset.currency.toLowerCase(),
19086
- destination_token_address: destinationTokenAddress,
19087
- destination_chain_id: destinationChainId,
19088
- destination_chain_type: destinationChainType,
19089
- country_code: userIpInfo?.alpha2,
19090
- subdivision_code: userIpInfo?.subdivisionCode ?? void 0
19091
- },
19092
- publishableKey
19093
- ),
19094
- getSupportedDepositTokens(publishableKey, {
19095
- destination_token_address: destinationTokenAddress,
19096
- destination_chain_id: destinationChainId,
19097
- destination_chain_type: destinationChainType
19098
- })
19099
- ]);
19100
- if (cancelled) return;
19101
- const supportedToken = supportedTokens.data.find(
19102
- (t13) => t13.symbol.toLowerCase() === selectedAsset.currency.toLowerCase()
19103
- );
19104
- if (supportedToken && supportedToken.chains.length > 0) {
19105
- const matchingChain = supportedToken.chains.find(
19106
- (c) => c.chain_name.toLowerCase() === defaultToken.source_network.toLowerCase()
19107
- );
19108
- setMinDepositUsd(
19109
- matchingChain?.minimum_deposit_amount_usd ?? Math.min(...supportedToken.chains.map((c) => c.minimum_deposit_amount_usd))
19110
- );
19111
- } else {
19112
- setMinDepositUsd(0);
19113
- }
19114
- } catch {
19115
- if (!cancelled) setMinDepositUsd(0);
19116
- }
19117
- };
19118
- fetchMinDeposit();
19119
- return () => {
19120
- cancelled = true;
19121
- };
19122
- }, [view, selectedAsset, publishableKey, destinationTokenAddress, destinationChainId, destinationChainType, userIpInfo?.alpha2, userIpInfo?.subdivisionCode]);
19252
+ const minDepositUsd = useMemo32(() => {
19253
+ if (!selectedAsset || !defaultTokenData) return 0;
19254
+ const supportedToken = supportedTokensData?.data.find(
19255
+ (t13) => t13.symbol.toLowerCase() === selectedAsset.currency.toLowerCase()
19256
+ );
19257
+ if (!supportedToken || supportedToken.chains.length === 0) return 0;
19258
+ const matchingChain = supportedToken.chains.find(
19259
+ (c) => c.chain_name.toLowerCase() === defaultTokenData.source_network.toLowerCase()
19260
+ );
19261
+ return matchingChain?.minimum_deposit_amount_usd ?? Math.min(...supportedToken.chains.map((c) => c.minimum_deposit_amount_usd));
19262
+ }, [selectedAsset, supportedTokensData, defaultTokenData]);
19123
19263
  const handleSelectExchange = (exchange) => {
19124
19264
  if (!exchange.enabled) return;
19125
19265
  setSelectedExchange(exchange);
@@ -19164,7 +19304,6 @@ function CoinbaseConnect({
19164
19304
  const handleSelectAsset = (asset) => {
19165
19305
  setSelectedAsset(asset);
19166
19306
  setSendAmount("");
19167
- setMinDepositUsd(0);
19168
19307
  transitionTo("enter_amount");
19169
19308
  };
19170
19309
  const handleCreateTransfer = async () => {
@@ -19176,18 +19315,10 @@ function CoinbaseConnect({
19176
19315
  const cryptoAmount = (usdAmount / rate).toFixed(8);
19177
19316
  setIsLoading(true);
19178
19317
  try {
19179
- const { source_network, source_chain_type } = await getIntegrationTransferDefaultToken(
19180
- {
19181
- integration_provider: IntegrationProvider.COINBASE,
19182
- source_currency: selectedAsset.currency.toLowerCase(),
19183
- destination_token_address: destinationTokenAddress,
19184
- destination_chain_id: destinationChainId,
19185
- destination_chain_type: destinationChainType,
19186
- country_code: userIpInfo?.alpha2,
19187
- subdivision_code: userIpInfo?.subdivisionCode ?? void 0
19188
- },
19189
- publishableKey
19190
- );
19318
+ if (!defaultTokenData) {
19319
+ throw new Error("Transfer details not ready. Please try again.");
19320
+ }
19321
+ const { source_network, source_chain_type } = defaultTokenData;
19191
19322
  const matchingWallet = wallets.find((w) => w.chain_type === source_chain_type);
19192
19323
  const depositAddress = matchingWallet?.address ?? recipientAddress ?? "";
19193
19324
  if (!depositAddress) {
@@ -19339,13 +19470,12 @@ function CoinbaseConnect({
19339
19470
  break;
19340
19471
  }
19341
19472
  };
19342
- const STABLECOIN_SYMBOLS = /* @__PURE__ */ new Set(["USDC", "USDT", "DAI", "BUSD", "TUSD", "USDP", "GUSD", "FRAX", "LUSD", "PYUSD", "EURC", "USDS"]);
19343
19473
  const formatCryptoAmount = (amount, currency) => {
19344
19474
  const num = parseFloat(amount);
19345
19475
  if (isNaN(num)) return `${amount} ${currency.toUpperCase()}`;
19346
- const isStable = STABLECOIN_SYMBOLS.has(currency.toUpperCase());
19347
- const maxDecimals = isStable ? 2 : 8;
19348
- return `${num.toLocaleString(void 0, { minimumFractionDigits: isStable ? 2 : 0, maximumFractionDigits: maxDecimals })} ${currency.toUpperCase()}`;
19476
+ const isStable = stablecoinSymbols.has(currency.toLowerCase());
19477
+ const maxDecimals = isStable ? 2 : 6;
19478
+ return `${num.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: maxDecimals })} ${currency.toUpperCase()}`;
19349
19479
  };
19350
19480
  const viewTransitionStyle = {
19351
19481
  opacity: isTransitioning ? 0 : 1,
@@ -19947,7 +20077,7 @@ function CoinbaseConnect({
19947
20077
  className: "uf-w-6 uf-h-6 uf-animate-spin",
19948
20078
  style: { color: colors2.foregroundMuted }
19949
20079
  }
19950
- ) }) : holdings.length === 0 ? /* @__PURE__ */ jsx37("div", { className: "uf-text-center uf-py-8", children: /* @__PURE__ */ jsx37(
20080
+ ) }) : sortedHoldings.length === 0 ? /* @__PURE__ */ jsx37("div", { className: "uf-text-center uf-py-8", children: /* @__PURE__ */ jsx37(
19951
20081
  "div",
19952
20082
  {
19953
20083
  className: "uf-text-sm",
@@ -19957,17 +20087,19 @@ function CoinbaseConnect({
19957
20087
  },
19958
20088
  children: "No holdings found"
19959
20089
  }
19960
- ) }) : holdings.map((account) => {
20090
+ ) }) : sortedHoldings.map((account) => {
19961
20091
  const iconUrl = account.icon_urls?.find((u) => u.format === "svg")?.url || account.icon_urls?.find((u) => u.format === "png")?.url || account.icon_url;
19962
- const isSelected = selectedHolding?.id === account.id;
20092
+ const currencyLower = account.currency.toLowerCase();
20093
+ const isSupported = (supportedSymbols.size === 0 || supportedSymbols.has(currencyLower)) && (exchangeSupportedCurrencies.size === 0 || exchangeSupportedCurrencies.has(currencyLower));
20094
+ const isSelected = isSupported && selectedHolding?.id === account.id;
19963
20095
  const usdValue = account.amount_usd ? parseFloat(account.amount_usd) : null;
19964
- const formattedUsd = usdValue != null && usdValue > 0 ? `$${usdValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : null;
20096
+ const formattedUsd = usdValue != null && usdValue >= 0.01 ? `$${usdValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : usdValue != null && usdValue < 0.01 && usdValue > 0 ? "< $0.01" : "$0.00";
19965
20097
  return /* @__PURE__ */ jsxs33(
19966
20098
  "button",
19967
20099
  {
19968
20100
  onClick: () => setSelectedHolding(account),
19969
- disabled: isLoading,
19970
- className: "uf-w-full uf-transition-colors uf-p-3 uf-flex uf-items-center uf-justify-between",
20101
+ disabled: isLoading || !isSupported,
20102
+ className: `uf-w-full uf-transition-colors uf-p-3 uf-flex uf-items-center uf-justify-between ${!isSupported ? "uf-cursor-not-allowed uf-opacity-50" : ""}`,
19971
20103
  style: {
19972
20104
  backgroundColor: isSelected ? colors2.primary + "20" : components.card.backgroundColor,
19973
20105
  borderRadius: components.list.rowBorderRadius,
@@ -20057,9 +20189,9 @@ function CoinbaseConnect({
20057
20189
  "button",
20058
20190
  {
20059
20191
  onClick: () => {
20060
- if (selectedHolding) handleSelectAsset(selectedHolding);
20192
+ if (selectedHolding && selectedHoldingIsSupported) handleSelectAsset(selectedHolding);
20061
20193
  },
20062
- disabled: !selectedHolding || isLoading,
20194
+ disabled: !selectedHolding || isLoading || supportedTokensLoading || exchangesLoading || !selectedHoldingIsSupported,
20063
20195
  className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
20064
20196
  style: {
20065
20197
  backgroundColor: colors2.primary,
@@ -20083,22 +20215,16 @@ function CoinbaseConnect({
20083
20215
  const isValidAmount = inputUsdNum > 0 && (maxUsdAmount == null || inputUsdNum <= maxUsdAmount) && inputUsdNum >= minDepositUsd;
20084
20216
  const displayValue = sendAmount || "0";
20085
20217
  const formattedBalance = formatCryptoAmount(selectedAsset.amount, selectedAsset.currency);
20086
- const balanceDisplay = maxUsdAmount != null && maxUsdAmount > 0 ? `$${maxUsdAmount.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (${formattedBalance})` : formattedBalance;
20218
+ const balanceSubtitle = maxUsdAmount != null && maxUsdAmount > 0 ? `Balance: $${maxUsdAmount.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (${formattedBalance})` : `Balance: ${formattedBalance}`;
20087
20219
  return /* @__PURE__ */ jsxs33(Fragment42, { children: [
20088
20220
  /* @__PURE__ */ jsx37(
20089
20221
  DepositHeader,
20090
20222
  {
20091
20223
  title: "Enter Amount",
20224
+ subtitle: balanceSubtitle,
20092
20225
  showBack: true,
20093
20226
  onBack: handleBack,
20094
- onClose,
20095
- showBalance: true,
20096
- balanceAddress: recipientAddress,
20097
- balanceChainType: destinationChainType === "ethereum" || destinationChainType === "solana" || destinationChainType === "bitcoin" ? destinationChainType : void 0,
20098
- balanceChainId: destinationChainId,
20099
- balanceTokenAddress: destinationTokenAddress,
20100
- projectName: projectConfig?.project_name,
20101
- publishableKey
20227
+ onClose
20102
20228
  }
20103
20229
  ),
20104
20230
  /* @__PURE__ */ jsxs33("div", { className: "uf-flex uf-flex-col uf-pb-4", style: viewTransitionStyle, children: [
@@ -20220,7 +20346,7 @@ function CoinbaseConnect({
20220
20346
  "button",
20221
20347
  {
20222
20348
  onClick: handleCreateTransfer,
20223
- disabled: !isValidAmount || isLoading,
20349
+ disabled: !isValidAmount || isLoading || defaultTokenLoading || !defaultTokenData,
20224
20350
  className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed uf-flex uf-items-center uf-justify-center uf-gap-2",
20225
20351
  style: {
20226
20352
  backgroundColor: colors2.primary,
@@ -20229,7 +20355,7 @@ function CoinbaseConnect({
20229
20355
  borderRadius: components.button.borderRadius,
20230
20356
  border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
20231
20357
  },
20232
- children: isLoading ? /* @__PURE__ */ jsx37(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }) : "Review"
20358
+ children: isLoading || defaultTokenLoading ? /* @__PURE__ */ jsx37(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }) : "Review"
20233
20359
  }
20234
20360
  )
20235
20361
  ] })
@@ -20700,7 +20826,7 @@ function useExchanges({
20700
20826
  publishableKey,
20701
20827
  enabled = true
20702
20828
  }) {
20703
- const { data: exchanges = [], isLoading } = useQuery5({
20829
+ const { data: exchanges = [], isLoading } = useQuery7({
20704
20830
  queryKey: ["unifold", "exchanges", publishableKey],
20705
20831
  queryFn: () => getExchanges(void 0, publishableKey).then((res) => res.data),
20706
20832
  enabled,
@@ -20719,7 +20845,7 @@ function useDefaultOnrampToken({
20719
20845
  subdivisionCode,
20720
20846
  enabled = true
20721
20847
  }) {
20722
- const { data: defaultToken, isLoading } = useQuery6({
20848
+ const { data: defaultToken, isLoading } = useQuery8({
20723
20849
  queryKey: [
20724
20850
  "unifold",
20725
20851
  "defaultOnrampToken",
@@ -20752,7 +20878,7 @@ function useAllowedCountry(publishableKey) {
20752
20878
  data: ipData,
20753
20879
  isLoading: isIpLoading,
20754
20880
  error: ipError
20755
- } = useQuery7({
20881
+ } = useQuery9({
20756
20882
  queryKey: ["unifold", "ipAddress"],
20757
20883
  queryFn: () => getIpAddress(),
20758
20884
  refetchOnMount: false,
@@ -20767,7 +20893,7 @@ function useAllowedCountry(publishableKey) {
20767
20893
  data: configData,
20768
20894
  isLoading: isConfigLoading,
20769
20895
  error: configError
20770
- } = useQuery7({
20896
+ } = useQuery9({
20771
20897
  queryKey: ["unifold", "projectConfig", publishableKey],
20772
20898
  queryFn: () => getProjectConfig(publishableKey),
20773
20899
  refetchOnMount: false,
@@ -20818,7 +20944,7 @@ function useAddressValidation({
20818
20944
  refetchOnMount = false
20819
20945
  }) {
20820
20946
  const shouldValidate = enabled && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
20821
- const { data, isLoading, error } = useQuery8({
20947
+ const { data, isLoading, error } = useQuery10({
20822
20948
  queryKey: [
20823
20949
  "unifold",
20824
20950
  "addressValidation",
@@ -20862,39 +20988,6 @@ function useAddressValidation({
20862
20988
  error: error ?? null
20863
20989
  };
20864
20990
  }
20865
- function useSupportedDepositTokens(publishableKey, options) {
20866
- const hasDestination = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type;
20867
- const filteredOptions = {
20868
- ...hasDestination ? {
20869
- destination_token_address: options.destination_token_address,
20870
- destination_chain_id: options.destination_chain_id,
20871
- destination_chain_type: options.destination_chain_type
20872
- } : {},
20873
- ...options?.product_type ? { product_type: options.product_type } : {}
20874
- };
20875
- const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
20876
- return useQuery9({
20877
- queryKey: [
20878
- "unifold",
20879
- "supportedDepositTokens",
20880
- publishableKey,
20881
- filteredOptions?.destination_token_address ?? null,
20882
- filteredOptions?.destination_chain_id ?? null,
20883
- filteredOptions?.destination_chain_type ?? null,
20884
- filteredOptions?.product_type ?? null
20885
- ],
20886
- queryFn: () => getSupportedDepositTokens(
20887
- publishableKey,
20888
- hasFilteredOptions ? filteredOptions : void 0
20889
- ),
20890
- staleTime: 1e3 * 60 * 5,
20891
- // 5 minutes — token list rarely changes
20892
- gcTime: 1e3 * 60 * 30,
20893
- // 30 minutes in cache
20894
- refetchOnMount: false,
20895
- refetchOnWindowFocus: false
20896
- });
20897
- }
20898
20991
  function ThemeStyleInjector({
20899
20992
  children,
20900
20993
  className
@@ -21202,7 +21295,7 @@ function TokenSelectorSheet({
21202
21295
  useEffect192(() => {
21203
21296
  setRecentTokens(getRecentTokens());
21204
21297
  }, []);
21205
- const allOptions = useMemo42(() => {
21298
+ const allOptions = useMemo52(() => {
21206
21299
  const options = [];
21207
21300
  tokens.forEach((token) => {
21208
21301
  token.chains.forEach((chain) => {
@@ -21211,7 +21304,7 @@ function TokenSelectorSheet({
21211
21304
  });
21212
21305
  return options;
21213
21306
  }, [tokens]);
21214
- const quickSelectOptions = useMemo42(() => {
21307
+ const quickSelectOptions = useMemo52(() => {
21215
21308
  const result = [];
21216
21309
  const seen = /* @__PURE__ */ new Set();
21217
21310
  const addOption = (symbol, chainType, chainId, isRecent) => {
@@ -21243,7 +21336,7 @@ function TokenSelectorSheet({
21243
21336
  });
21244
21337
  setRecentTokens(updated);
21245
21338
  };
21246
- const filteredOptions = useMemo42(() => {
21339
+ const filteredOptions = useMemo52(() => {
21247
21340
  if (!searchQuery.trim()) return allOptions;
21248
21341
  const query = searchQuery.toLowerCase();
21249
21342
  return allOptions.filter(
@@ -21954,7 +22047,7 @@ function useHypercoreActivation(params) {
21954
22047
  const recipient = recipientAddress?.trim() ?? "";
21955
22048
  const source = sourceAddress?.trim() ?? "";
21956
22049
  const hasAddresses = !!recipient && !!source;
21957
- const { data, isLoading } = useQuery10({
22050
+ const { data, isLoading } = useQuery11({
21958
22051
  queryKey: [
21959
22052
  "unifold",
21960
22053
  "hypercoreActivation",
@@ -22083,7 +22176,7 @@ function TransferCryptoSingleInput({
22083
22176
  const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
22084
22177
  const loading = externalWallets?.length ? false : walletsLoading;
22085
22178
  const error = walletsError?.message ?? null;
22086
- const allAvailableChains = useMemo52(() => {
22179
+ const allAvailableChains = useMemo62(() => {
22087
22180
  const chainsMap = /* @__PURE__ */ new Map();
22088
22181
  supportedTokens.forEach((t12) => {
22089
22182
  t12.chains.forEach((c) => {
@@ -22740,7 +22833,7 @@ function TransferCryptoDoubleInput({
22740
22833
  const wallets = externalWallets?.length ? externalWallets : depositAddressResponse?.data ?? [];
22741
22834
  const loading = externalWallets?.length ? false : walletsLoading;
22742
22835
  const error = walletsError?.message ?? null;
22743
- const allAvailableChains = useMemo62(() => {
22836
+ const allAvailableChains = useMemo72(() => {
22744
22837
  const chainsMap = /* @__PURE__ */ new Map();
22745
22838
  supportedTokens.forEach((t12) => {
22746
22839
  t12.chains.forEach((c) => {
@@ -23171,7 +23264,7 @@ function useDepositQuote(params) {
23171
23264
  ...adjustForSlippage ? { adjust_for_slippage: true } : {},
23172
23265
  ...stablecoinParity ? { stablecoin_parity: true } : {}
23173
23266
  };
23174
- return useQuery11({
23267
+ return useQuery12({
23175
23268
  queryKey: [
23176
23269
  "unifold",
23177
23270
  "depositQuote",
@@ -23279,7 +23372,7 @@ function SelectTokenView({
23279
23372
  ),
23280
23373
  walletInfoProp ? /* @__PURE__ */ jsx50("div", { className: "uf-flex uf-w-full uf-justify-center uf-mb-6", children: /* @__PURE__ */ jsx50(WalletWithNetworkBadge, { walletInfo: walletInfoProp }) }) : null,
23281
23374
  /* @__PURE__ */ jsxs43("div", { className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col", children: [
23282
- /* @__PURE__ */ jsx50("div", { className: "uf-h-[220px] uf-shrink-0 uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: /* @__PURE__ */ jsx50("div", { className: "uf-space-y-2", children: isLoading ? /* @__PURE__ */ jsx50("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-12", children: /* @__PURE__ */ jsx50(
23375
+ /* @__PURE__ */ jsx50("div", { className: "uf-h-[300px] uf-shrink-0 uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: /* @__PURE__ */ jsx50("div", { className: "uf-space-y-2", children: isLoading ? /* @__PURE__ */ jsx50("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-12", children: /* @__PURE__ */ jsx50(
23283
23376
  LoaderCircle,
23284
23377
  {
23285
23378
  className: "uf-w-6 uf-h-6 uf-animate-spin",
@@ -25659,7 +25752,7 @@ function DepositModal({
25659
25752
  depositTrackerSubTitle = t7.depositTracker.subtitle
25660
25753
  }) {
25661
25754
  const { colors: colors2, fonts, components } = useTheme();
25662
- const effectiveInitialScreen = useMemo92(() => {
25755
+ const effectiveInitialScreen = useMemo10(() => {
25663
25756
  const s = initialScreen ?? "main";
25664
25757
  if (s === "tracker" && hideDepositTracker) return "main";
25665
25758
  if (s === "cashapp" && !enableCashApp) return "main";
@@ -25718,11 +25811,12 @@ function DepositModal({
25718
25811
  return sum + (isNaN(usd) ? 0 : usd);
25719
25812
  }, 0);
25720
25813
  const balanceUsd = totalUsd > 0 ? totalUsd.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : null;
25721
- setConnectedExchange((prev) => ({ ...prev, balanceUsd, isLoading: false }));
25814
+ setConnectedExchange((prev) => prev ? { ...prev, balanceUsd, isLoading: false } : null);
25722
25815
  };
25723
25816
  getIntegrationHoldings(IntegrationProvider.COINBASE, stored.access_token, publishableKey).then(processHoldings).catch(async () => {
25724
25817
  try {
25725
25818
  const refreshResult = await refreshIntegrationToken(stored.access_token, publishableKey);
25819
+ if (!getStoredIntegrationToken(IntegrationProvider.COINBASE)) return;
25726
25820
  setStoredIntegrationToken({
25727
25821
  integration_provider: IntegrationProvider.COINBASE,
25728
25822
  access_token: refreshResult.access_token,
@@ -25731,6 +25825,7 @@ function DepositModal({
25731
25825
  const retryResult = await getIntegrationHoldings(IntegrationProvider.COINBASE, refreshResult.access_token, publishableKey);
25732
25826
  processHoldings(retryResult);
25733
25827
  } catch {
25828
+ if (!getStoredIntegrationToken(IntegrationProvider.COINBASE)) return;
25734
25829
  clearStoredIntegrationToken(IntegrationProvider.COINBASE);
25735
25830
  setConnectedExchange(null);
25736
25831
  }
@@ -25898,6 +25993,14 @@ function DepositModal({
25898
25993
  setBrowserWalletInfo(null);
25899
25994
  setBrowserWalletModalOpen(false);
25900
25995
  };
25996
+ const handleExchangeDisconnect = () => {
25997
+ const stored = getStoredIntegrationToken(IntegrationProvider.COINBASE);
25998
+ if (stored) {
25999
+ revokeIntegrationToken(stored.access_token, publishableKey);
26000
+ }
26001
+ clearStoredIntegrationToken(IntegrationProvider.COINBASE);
26002
+ setConnectedExchange(null);
26003
+ };
25901
26004
  const handleClose = () => {
25902
26005
  onOpenChange(false);
25903
26006
  if (resetViewTimeoutRef.current) {
@@ -26103,6 +26206,7 @@ function DepositModal({
26103
26206
  setCoinbaseSkipToHoldings(true);
26104
26207
  setView("coinbase_connect");
26105
26208
  },
26209
+ onDisconnect: handleExchangeDisconnect,
26106
26210
  title: i18n2.connectExchange.title,
26107
26211
  subtitle: i18n2.connectExchange.subtitle,
26108
26212
  exchanges: integrationExchanges,
@@ -26307,34 +26411,37 @@ function DepositModal({
26307
26411
  ),
26308
26412
  depositPoweredByFooter
26309
26413
  ] })
26310
- ] }) : view === "coinbase_connect" ? /* @__PURE__ */ jsx56(
26311
- CoinbaseConnect,
26312
- {
26313
- publishableKey,
26314
- userId,
26315
- wallets,
26316
- recipientAddress,
26317
- destinationTokenAddress: destinationTokenAddress ?? "",
26318
- destinationChainId: destinationChainId ?? "",
26319
- destinationChainType: destinationChainType ?? "",
26320
- onTransferSuccess: (result) => {
26321
- onDepositSuccess?.({
26322
- message: "Transfer completed via Coinbase Connect",
26323
- transaction: result
26324
- });
26325
- },
26326
- onTransferError: (error) => {
26327
- onDepositError?.({
26328
- message: error.message,
26329
- error
26330
- });
26331
- },
26332
- onBack: handleBack,
26333
- onClose: handleClose,
26334
- skipToHoldings: coinbaseSkipToHoldings,
26335
- onExecutionsChange: setDepositExecutions
26336
- }
26337
- ) : view === "cashapp" ? /* @__PURE__ */ jsxs49(Fragment12, { children: [
26414
+ ] }) : view === "coinbase_connect" ? /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
26415
+ /* @__PURE__ */ jsx56(
26416
+ CoinbaseConnect,
26417
+ {
26418
+ publishableKey,
26419
+ userId,
26420
+ wallets,
26421
+ recipientAddress,
26422
+ destinationTokenAddress: destinationTokenAddress ?? "",
26423
+ destinationChainId: destinationChainId ?? "",
26424
+ destinationChainType: destinationChainType ?? "",
26425
+ onTransferSuccess: (result) => {
26426
+ onDepositSuccess?.({
26427
+ message: "Transfer completed via Coinbase Connect",
26428
+ transaction: result
26429
+ });
26430
+ },
26431
+ onTransferError: (error) => {
26432
+ onDepositError?.({
26433
+ message: error.message,
26434
+ error
26435
+ });
26436
+ },
26437
+ onBack: handleBack,
26438
+ onClose: handleClose,
26439
+ skipToHoldings: coinbaseSkipToHoldings,
26440
+ onExecutionsChange: setDepositExecutions
26441
+ }
26442
+ ),
26443
+ depositPoweredByFooter
26444
+ ] }) : view === "cashapp" ? /* @__PURE__ */ jsxs49(Fragment12, { children: [
26338
26445
  /* @__PURE__ */ jsx56(
26339
26446
  DepositHeader,
26340
26447
  {
@@ -26427,7 +26534,7 @@ function usePaymentIntent(params) {
26427
26534
  enabled = true,
26428
26535
  pollingInterval = 3e3
26429
26536
  } = params;
26430
- return useQuery12({
26537
+ return useQuery13({
26431
26538
  queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
26432
26539
  queryFn: () => retrievePaymentIntent(clientSecret, publishableKey),
26433
26540
  enabled: enabled && !!clientSecret && !!publishableKey,
@@ -26539,14 +26646,14 @@ function CheckoutModal({
26539
26646
  });
26540
26647
  }
26541
26648
  }, [paymentIntent, onCheckoutSuccess, browserWalletModalOpen]);
26542
- const wallets = useMemo102(() => {
26649
+ const wallets = useMemo112(() => {
26543
26650
  if (!paymentIntent) return [];
26544
26651
  return mapDepositAddressesToWallets(
26545
26652
  paymentIntent.deposit_addresses,
26546
26653
  paymentIntent
26547
26654
  );
26548
26655
  }, [paymentIntent]);
26549
- const formatCryptoAmount = useMemo102(() => {
26656
+ const formatCryptoAmount = useMemo112(() => {
26550
26657
  if (!paymentIntent) return (_) => "";
26551
26658
  const decimals = paymentIntent.destination_token_decimals ?? 6;
26552
26659
  const symbol = paymentIntent.currency.toUpperCase();
@@ -26556,7 +26663,7 @@ function CheckoutModal({
26556
26663
  return `${formatted} ${symbol}`;
26557
26664
  };
26558
26665
  }, [paymentIntent]);
26559
- const remainingAmountUsd = useMemo102(() => {
26666
+ const remainingAmountUsd = useMemo112(() => {
26560
26667
  if (!paymentIntent) return void 0;
26561
26668
  const total = parseFloat(paymentIntent.destination_amount_usd || paymentIntent.amount_usd);
26562
26669
  const received = parseFloat(paymentIntent.destination_amount_received_usd || paymentIntent.amount_received_usd);
@@ -26564,7 +26671,7 @@ function CheckoutModal({
26564
26671
  const remaining = total - received;
26565
26672
  return remaining > 0 ? remaining.toFixed(2) : "0.00";
26566
26673
  }, [paymentIntent]);
26567
- const remainingCrypto = useMemo102(() => {
26674
+ const remainingCrypto = useMemo112(() => {
26568
26675
  if (!paymentIntent) return void 0;
26569
26676
  const total = BigInt(paymentIntent.destination_amount || paymentIntent.amount);
26570
26677
  const received = BigInt(paymentIntent.destination_amount_received || paymentIntent.amount_received);
@@ -26572,7 +26679,7 @@ function CheckoutModal({
26572
26679
  return remaining > 0n ? remaining.toString() : "0";
26573
26680
  }, [paymentIntent]);
26574
26681
  const [selectedSource, setSelectedSource] = useState32(null);
26575
- const remainingDestinationAmount = useMemo102(() => {
26682
+ const remainingDestinationAmount = useMemo112(() => {
26576
26683
  if (!paymentIntent) return "0";
26577
26684
  const remaining = BigInt(paymentIntent.destination_amount) - BigInt(paymentIntent.destination_amount_received);
26578
26685
  return remaining > 0n ? remaining.toString() : "0";
@@ -26590,7 +26697,7 @@ function CheckoutModal({
26590
26697
  stablecoinParity: paymentIntent?.stablecoin_parity ?? false,
26591
26698
  enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && remainingDestinationAmount !== "0"
26592
26699
  });
26593
- const effectiveCheckoutQuote = useMemo102(() => {
26700
+ const effectiveCheckoutQuote = useMemo112(() => {
26594
26701
  if (!sourceQuote || !selectedSource) return null;
26595
26702
  const baseQuote = {
26596
26703
  sourceAmount: sourceQuote.source_amount,
@@ -27076,7 +27183,7 @@ function CheckoutModal({
27076
27183
  ] }) });
27077
27184
  }
27078
27185
  function useSupportedDestinationTokens(publishableKey, enabled = true) {
27079
- return useQuery13({
27186
+ return useQuery14({
27080
27187
  queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
27081
27188
  queryFn: () => getSupportedDestinationTokens(publishableKey),
27082
27189
  staleTime: 1e3 * 60 * 5,
@@ -27111,7 +27218,7 @@ function useSourceTokenValidation(params) {
27111
27218
  enabled = true
27112
27219
  } = params;
27113
27220
  const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
27114
- return useQuery14({
27221
+ return useQuery15({
27115
27222
  queryKey: [
27116
27223
  "unifold",
27117
27224
  "sourceTokenValidation",
@@ -27167,7 +27274,7 @@ function useAddressBalance(params) {
27167
27274
  enabled = true
27168
27275
  } = params;
27169
27276
  const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
27170
- return useQuery15({
27277
+ return useQuery16({
27171
27278
  queryKey: [
27172
27279
  "unifold",
27173
27280
  "addressBalance",
@@ -27216,7 +27323,7 @@ function useAddressBalance(params) {
27216
27323
  }
27217
27324
  function useExecutions(userId, publishableKey, options) {
27218
27325
  const actionType = options?.actionType ?? ActionType.Deposit;
27219
- return useQuery16({
27326
+ return useQuery17({
27220
27327
  queryKey: ["unifold", "executions", actionType, userId, publishableKey],
27221
27328
  queryFn: () => queryExecutions(userId, publishableKey, actionType),
27222
27329
  enabled: (options?.enabled ?? true) && !!userId,
@@ -27499,7 +27606,7 @@ function useVerifyRecipientAddress(params) {
27499
27606
  } = params;
27500
27607
  const trimmedAddress = recipientAddress?.trim() || "";
27501
27608
  const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
27502
- return useQuery17({
27609
+ return useQuery18({
27503
27610
  queryKey: [
27504
27611
  "unifold",
27505
27612
  "verifyRecipientAddress",
@@ -27541,7 +27648,7 @@ function useGetDepositAddress(params) {
27541
27648
  enabled = true
27542
27649
  } = params;
27543
27650
  const canFire = !!userId && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
27544
- return useQuery18({
27651
+ return useQuery19({
27545
27652
  queryKey: [
27546
27653
  "unifold",
27547
27654
  "getDepositAddress",
@@ -27608,7 +27715,7 @@ function useHypercoreWithdrawActivation(params) {
27608
27715
  actionType: ActionType.Withdraw,
27609
27716
  enabled: enabled && isHypercore(sourceChainId)
27610
27717
  });
27611
- const depositWalletAddress = useMemo112(() => {
27718
+ const depositWalletAddress = useMemo122(() => {
27612
27719
  const wallets = depositWalletLookup.data?.data ?? [];
27613
27720
  return wallets.find((w) => w.chain_type === sourceChainType)?.address;
27614
27721
  }, [depositWalletLookup.data, sourceChainType]);
@@ -27731,7 +27838,7 @@ function WithdrawForm({
27731
27838
  enabled: debouncedAddress.length > 5 && !!selectedChain
27732
27839
  });
27733
27840
  const isDebouncing = trimmedAddress !== debouncedAddress;
27734
- const addressError = useMemo122(() => {
27841
+ const addressError = useMemo132(() => {
27735
27842
  if (!trimmedAddress || trimmedAddress.length <= 5) return null;
27736
27843
  if (isDebouncing || isVerifyingAddress) return null;
27737
27844
  if (verifyError) return t9.invalidAddress;
@@ -27757,33 +27864,33 @@ function WithdrawForm({
27757
27864
  destinationTokenAddress: selectedChain?.token_address,
27758
27865
  enabled: isAddressValid
27759
27866
  });
27760
- const exchangeRate = useMemo122(() => {
27867
+ const exchangeRate = useMemo132(() => {
27761
27868
  if (!balanceData?.exchangeRate) return 0;
27762
27869
  return parseFloat(balanceData.exchangeRate);
27763
27870
  }, [balanceData]);
27764
- const balanceCrypto = useMemo122(() => {
27871
+ const balanceCrypto = useMemo132(() => {
27765
27872
  if (!balanceData?.balanceHuman) return 0;
27766
27873
  return parseFloat(balanceData.balanceHuman);
27767
27874
  }, [balanceData]);
27768
- const balanceUsdNum = useMemo122(() => {
27875
+ const balanceUsdNum = useMemo132(() => {
27769
27876
  if (!balanceData?.balanceUsd) return 0;
27770
27877
  return parseFloat(balanceData.balanceUsd);
27771
27878
  }, [balanceData]);
27772
27879
  const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
27773
27880
  const sourceDecimals = balanceData?.decimals ?? 6;
27774
- const cryptoAmountFromInput = useMemo122(() => {
27881
+ const cryptoAmountFromInput = useMemo132(() => {
27775
27882
  const val = parseFloat(amount);
27776
27883
  if (!val || val <= 0) return 0;
27777
27884
  if (inputUnit === "crypto") return val;
27778
27885
  return exchangeRate > 0 ? val / exchangeRate : 0;
27779
27886
  }, [amount, inputUnit, exchangeRate]);
27780
- const fiatAmountFromInput = useMemo122(() => {
27887
+ const fiatAmountFromInput = useMemo132(() => {
27781
27888
  const val = parseFloat(amount);
27782
27889
  if (!val || val <= 0) return 0;
27783
27890
  if (inputUnit === "fiat") return val;
27784
27891
  return val * exchangeRate;
27785
27892
  }, [amount, inputUnit, exchangeRate]);
27786
- const convertedDisplay = useMemo122(() => {
27893
+ const convertedDisplay = useMemo132(() => {
27787
27894
  if (!amount || parseFloat(amount) <= 0) return null;
27788
27895
  if (inputUnit === "crypto") {
27789
27896
  return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
@@ -27792,7 +27899,7 @@ function WithdrawForm({
27792
27899
  const displayDecimals = isStablecoin ? 2 : 6;
27793
27900
  return `${cryptoDisplay.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: displayDecimals })} ${tokenSymbol}`;
27794
27901
  }, [amount, inputUnit, fiatAmountFromInput, cryptoAmountFromInput, balanceCrypto, balanceData, tokenSymbol, isMaxed, isStablecoin]);
27795
- const balanceDisplay = useMemo122(() => {
27902
+ const balanceDisplay = useMemo132(() => {
27796
27903
  if (isLoadingBalance || !balanceData) return null;
27797
27904
  if (inputUnit === "crypto") {
27798
27905
  const displayDecimals = isStablecoin ? 2 : 6;
@@ -29002,7 +29109,7 @@ function UnifoldProvider2({
29002
29109
  withdrawPromiseRef.current = null;
29003
29110
  }
29004
29111
  }, []);
29005
- const contextValue = useMemo15(
29112
+ const contextValue = useMemo16(
29006
29113
  () => ({
29007
29114
  beginDeposit,
29008
29115
  closeDeposit,