@unifold/connect-react 0.1.48 → 0.1.50

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.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
3
  import { ThemeMode, ThemeConfig, FontConfig, ComponentConfig, DepositModalInitialScreen, ChainType, DepositConfirmationMode, WithdrawTransactionInfo, AllowedCountryResult } from '@unifold/ui-react';
4
- export { AllowedCountryResult, BrowserWalletAmountQuickSelect, Button, ButtonProps, ButtonTokens, CardTokens, ComponentConfig, ComponentTokens, ConfirmingView, ContainerTokens, CustomThemeColors, DepositConfirmationMode, DepositModalInitialScreen as DepositInitialScreen, FontConfig, HeaderTokens, InputTokens, ListTokens, SearchTokens, ThemeColors, ThemeConfig, ThemeMode, WithdrawTransactionInfo } from '@unifold/ui-react';
4
+ export { AllowedCountryResult, BrowserWalletAmountQuickSelect, Button, ButtonProps, ButtonTokens, CardTokens, ComponentConfig, ComponentTokens, ConfirmingView, ContainerTokens, CustomThemeColors, DepositConfirmationMode, DepositModalInitialScreen as DepositInitialScreen, FontConfig, HeaderTokens, InputTokens, ListTokens, SearchTokens, ThemeColors, ThemeConfig, ThemeMode, UseSupportedDepositTokensOptions, WithdrawTransactionInfo, useSupportedDepositTokens } from '@unifold/ui-react';
5
5
  import { DepositEvent } from '@unifold/core';
6
- export { ActionType, AutoSwapRequest, AutoSwapResponse, ChainType, CreateDepositAddressRequest, DefaultTokenChain, DefaultTokenMetadata, DefaultTokenResponse, DepositAddressResponse, DepositEvent, DepositEventType, DestinationToken, DestinationTokenChain, ExecutionStatus, FeaturedToken, FiatCurrenciesResponse, FiatCurrency, I18nStrings, IconUrl, IpAddressResponse, OnrampQuote, OnrampQuotesRequest, OnrampQuotesResponse, OnrampSessionCreatedData, OnrampSessionCreatedEvent, OnrampSessionRequest, OnrampSessionResponse, PaymentIntent, PaymentIntentDepositAddress, PaymentNetwork, ProjectConfigResponse, QueryExecutionsRequest, QueryExecutionsResponse, SOLANA_USDC_ADDRESS, SendSolanaTransactionRequest, SendSolanaTransactionResponse, SupportedChain, SupportedDepositTokensResponse, SupportedDestinationTokensResponse, SupportedToken, TokenChain, TokenChainIconUrl, TokenChainsResponse, UserIpInfo, Wallet, createDepositAddress, createOnrampSession, generatePrefixedKSUID, getApiBaseUrl, getChainName, getDefaultOnrampToken, getFiatCurrencies, getIconUrl, getIconUrlWithCdn, getIpAddress, getOnrampQuotes, getPreferredIconUrl, getProjectConfig, getSupportedDepositTokens, getSupportedDestinationTokens, getTokenChains, getWalletByChainType, i18n, queryExecutions, sendSolanaTransaction, setApiConfig, useUserIp } from '@unifold/core';
6
+ export { ActionType, AutoSwapRequest, AutoSwapResponse, ChainType, CreateDepositAddressRequest, DefaultTokenChain, DefaultTokenMetadata, DefaultTokenResponse, DepositAddressResponse, DepositEvent, DepositEventType, DepositQuote, DepositQuoteRequest, DestinationToken, DestinationTokenChain, ExecutionStatus, FeaturedToken, FiatCurrenciesResponse, FiatCurrency, I18nStrings, IconUrl, IpAddressResponse, LockedQuoteLimits, LockedQuotePreview, LockedQuotePreviewRequest, OnrampQuote, OnrampQuotesRequest, OnrampQuotesResponse, OnrampSessionCreatedData, OnrampSessionCreatedEvent, OnrampSessionRequest, OnrampSessionResponse, PaymentIntent, PaymentIntentDepositAddress, PaymentIntentStatus, PaymentIntentType, PaymentNetwork, ProjectConfigResponse, QueryExecutionsRequest, QueryExecutionsResponse, SOLANA_USDC_ADDRESS, SendSolanaTransactionRequest, SendSolanaTransactionResponse, SourceToken, SourceTokenNetwork, SupportedChain, SupportedDepositTokensResponse, SupportedDestinationTokensResponse, SupportedSourceTokensQuery, SupportedSourceTokensResponse, SupportedToken, TokenChain, TokenChainIconUrl, TokenChainsResponse, UserIpInfo, Wallet, createDepositAddress, createOnrampSession, generatePrefixedKSUID, getApiBaseUrl, getChainName, getDefaultOnrampToken, getDepositQuote, getFiatCurrencies, getIconUrl, getIconUrlWithCdn, getIpAddress, getOnrampQuotes, getPreferredIconUrl, getProjectConfig, getSupportedDepositTokens, getSupportedDestinationTokens, getTokenChains, getWalletByChainType, i18n, queryExecutions, retrievePaymentIntent, sendSolanaTransaction, setApiConfig, useUserIp } from '@unifold/core';
7
7
 
8
8
  interface UnifoldConnectProviderConfig {
9
9
  publishableKey: string;
@@ -149,6 +149,18 @@ interface WithdrawConfig {
149
149
  sourceTokenSymbol?: string;
150
150
  /** Optional: pre-fill the recipient address the user is withdrawing to */
151
151
  recipientAddress?: string;
152
+ /**
153
+ * Pre-select the destination (receive) token/chain in the withdraw view.
154
+ * All four props are optional. To match a specific token, provide `chainType` + `chainId` + (`symbol` OR `tokenAddress`).
155
+ * If omitted or no match is found in `/supported_destination_tokens`, the first available token and chain are used.
156
+ */
157
+ defaultDestinationChainType?: string;
158
+ /** Destination chain ID (e.g. `"mainnet"`, `"137"`). Must be paired with `defaultDestinationChainType` + symbol or token address. */
159
+ defaultDestinationChainId?: string;
160
+ /** Destination token contract address. Must be paired with `defaultDestinationChainType` + `defaultDestinationChainId`. */
161
+ defaultDestinationTokenAddress?: string;
162
+ /** Destination token symbol (e.g. `"USDC"`). Must be paired with `defaultDestinationChainType` + `defaultDestinationChainId`. */
163
+ defaultDestinationSymbol?: string;
152
164
  /**
153
165
  * The user's wallet address (the sender). Used to:
154
166
  * 1. Fetch balance for quick-select chips (25%/50%/75%/MAX)
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
3
  import { ThemeMode, ThemeConfig, FontConfig, ComponentConfig, DepositModalInitialScreen, ChainType, DepositConfirmationMode, WithdrawTransactionInfo, AllowedCountryResult } from '@unifold/ui-react';
4
- export { AllowedCountryResult, BrowserWalletAmountQuickSelect, Button, ButtonProps, ButtonTokens, CardTokens, ComponentConfig, ComponentTokens, ConfirmingView, ContainerTokens, CustomThemeColors, DepositConfirmationMode, DepositModalInitialScreen as DepositInitialScreen, FontConfig, HeaderTokens, InputTokens, ListTokens, SearchTokens, ThemeColors, ThemeConfig, ThemeMode, WithdrawTransactionInfo } from '@unifold/ui-react';
4
+ export { AllowedCountryResult, BrowserWalletAmountQuickSelect, Button, ButtonProps, ButtonTokens, CardTokens, ComponentConfig, ComponentTokens, ConfirmingView, ContainerTokens, CustomThemeColors, DepositConfirmationMode, DepositModalInitialScreen as DepositInitialScreen, FontConfig, HeaderTokens, InputTokens, ListTokens, SearchTokens, ThemeColors, ThemeConfig, ThemeMode, UseSupportedDepositTokensOptions, WithdrawTransactionInfo, useSupportedDepositTokens } from '@unifold/ui-react';
5
5
  import { DepositEvent } from '@unifold/core';
6
- export { ActionType, AutoSwapRequest, AutoSwapResponse, ChainType, CreateDepositAddressRequest, DefaultTokenChain, DefaultTokenMetadata, DefaultTokenResponse, DepositAddressResponse, DepositEvent, DepositEventType, DestinationToken, DestinationTokenChain, ExecutionStatus, FeaturedToken, FiatCurrenciesResponse, FiatCurrency, I18nStrings, IconUrl, IpAddressResponse, OnrampQuote, OnrampQuotesRequest, OnrampQuotesResponse, OnrampSessionCreatedData, OnrampSessionCreatedEvent, OnrampSessionRequest, OnrampSessionResponse, PaymentIntent, PaymentIntentDepositAddress, PaymentNetwork, ProjectConfigResponse, QueryExecutionsRequest, QueryExecutionsResponse, SOLANA_USDC_ADDRESS, SendSolanaTransactionRequest, SendSolanaTransactionResponse, SupportedChain, SupportedDepositTokensResponse, SupportedDestinationTokensResponse, SupportedToken, TokenChain, TokenChainIconUrl, TokenChainsResponse, UserIpInfo, Wallet, createDepositAddress, createOnrampSession, generatePrefixedKSUID, getApiBaseUrl, getChainName, getDefaultOnrampToken, getFiatCurrencies, getIconUrl, getIconUrlWithCdn, getIpAddress, getOnrampQuotes, getPreferredIconUrl, getProjectConfig, getSupportedDepositTokens, getSupportedDestinationTokens, getTokenChains, getWalletByChainType, i18n, queryExecutions, sendSolanaTransaction, setApiConfig, useUserIp } from '@unifold/core';
6
+ export { ActionType, AutoSwapRequest, AutoSwapResponse, ChainType, CreateDepositAddressRequest, DefaultTokenChain, DefaultTokenMetadata, DefaultTokenResponse, DepositAddressResponse, DepositEvent, DepositEventType, DepositQuote, DepositQuoteRequest, DestinationToken, DestinationTokenChain, ExecutionStatus, FeaturedToken, FiatCurrenciesResponse, FiatCurrency, I18nStrings, IconUrl, IpAddressResponse, LockedQuoteLimits, LockedQuotePreview, LockedQuotePreviewRequest, OnrampQuote, OnrampQuotesRequest, OnrampQuotesResponse, OnrampSessionCreatedData, OnrampSessionCreatedEvent, OnrampSessionRequest, OnrampSessionResponse, PaymentIntent, PaymentIntentDepositAddress, PaymentIntentStatus, PaymentIntentType, PaymentNetwork, ProjectConfigResponse, QueryExecutionsRequest, QueryExecutionsResponse, SOLANA_USDC_ADDRESS, SendSolanaTransactionRequest, SendSolanaTransactionResponse, SourceToken, SourceTokenNetwork, SupportedChain, SupportedDepositTokensResponse, SupportedDestinationTokensResponse, SupportedSourceTokensQuery, SupportedSourceTokensResponse, SupportedToken, TokenChain, TokenChainIconUrl, TokenChainsResponse, UserIpInfo, Wallet, createDepositAddress, createOnrampSession, generatePrefixedKSUID, getApiBaseUrl, getChainName, getDefaultOnrampToken, getDepositQuote, getFiatCurrencies, getIconUrl, getIconUrlWithCdn, getIpAddress, getOnrampQuotes, getPreferredIconUrl, getProjectConfig, getSupportedDepositTokens, getSupportedDestinationTokens, getTokenChains, getWalletByChainType, i18n, queryExecutions, retrievePaymentIntent, sendSolanaTransaction, setApiConfig, useUserIp } from '@unifold/core';
7
7
 
8
8
  interface UnifoldConnectProviderConfig {
9
9
  publishableKey: string;
@@ -149,6 +149,18 @@ interface WithdrawConfig {
149
149
  sourceTokenSymbol?: string;
150
150
  /** Optional: pre-fill the recipient address the user is withdrawing to */
151
151
  recipientAddress?: string;
152
+ /**
153
+ * Pre-select the destination (receive) token/chain in the withdraw view.
154
+ * All four props are optional. To match a specific token, provide `chainType` + `chainId` + (`symbol` OR `tokenAddress`).
155
+ * If omitted or no match is found in `/supported_destination_tokens`, the first available token and chain are used.
156
+ */
157
+ defaultDestinationChainType?: string;
158
+ /** Destination chain ID (e.g. `"mainnet"`, `"137"`). Must be paired with `defaultDestinationChainType` + symbol or token address. */
159
+ defaultDestinationChainId?: string;
160
+ /** Destination token contract address. Must be paired with `defaultDestinationChainType` + `defaultDestinationChainId`. */
161
+ defaultDestinationTokenAddress?: string;
162
+ /** Destination token symbol (e.g. `"USDC"`). Must be paired with `defaultDestinationChainType` + `defaultDestinationChainId`. */
163
+ defaultDestinationSymbol?: string;
152
164
  /**
153
165
  * The user's wallet address (the sender). Used to:
154
166
  * 1. Fetch balance for quick-select chips (25%/50%/75%/MAX)
package/dist/index.js CHANGED
@@ -1165,6 +1165,7 @@ __export(index_exports, {
1165
1165
  getApiBaseUrl: () => getApiBaseUrl,
1166
1166
  getChainName: () => getChainName,
1167
1167
  getDefaultOnrampToken: () => getDefaultOnrampToken,
1168
+ getDepositQuote: () => getDepositQuote,
1168
1169
  getFiatCurrencies: () => getFiatCurrencies,
1169
1170
  getIconUrl: () => getIconUrl,
1170
1171
  getIconUrlWithCdn: () => getIconUrlWithCdn,
@@ -1178,9 +1179,11 @@ __export(index_exports, {
1178
1179
  getWalletByChainType: () => getWalletByChainType,
1179
1180
  i18n: () => i18n,
1180
1181
  queryExecutions: () => queryExecutions,
1182
+ retrievePaymentIntent: () => retrievePaymentIntent,
1181
1183
  sendSolanaTransaction: () => sendSolanaTransaction,
1182
1184
  setApiConfig: () => setApiConfig,
1183
1185
  useAllowedCountry: () => useAllowedCountry2,
1186
+ useSupportedDepositTokens: () => useSupportedDepositTokens,
1184
1187
  useUnifold: () => useUnifold2,
1185
1188
  useUserIp: () => useUserIp
1186
1189
  });
@@ -6397,6 +6400,9 @@ function getOnrampSessionStartUrl(request, publishableKey) {
6397
6400
  if (request.external_id) {
6398
6401
  params.append("external_id", request.external_id);
6399
6402
  }
6403
+ if (request.email) {
6404
+ params.append("email", request.email);
6405
+ }
6400
6406
  return `${API_BASE_URL}/v1/public/onramps/sessions/start?${params.toString()}`;
6401
6407
  }
6402
6408
  async function getDefaultOnrampToken(params, publishableKey) {
@@ -13663,31 +13669,29 @@ function BuyWithCard({
13663
13669
  );
13664
13670
  if (manualProviderStillExists) {
13665
13671
  setSelectedProvider(manualProviderStillExists);
13666
- const bestProvider = response.data.reduce(
13667
- (best, current) => current.destination_amount > best.destination_amount ? current : best
13668
- );
13672
+ const firstProvider = response.data[0];
13669
13673
  if (!autoSelectedProvider) {
13670
- setAutoSelectedProvider(bestProvider.service_provider);
13674
+ setAutoSelectedProvider(firstProvider.service_provider);
13671
13675
  }
13672
13676
  setIsAutoSelected(
13673
13677
  manualProviderStillExists.service_provider === autoSelectedProvider
13674
13678
  );
13675
- } else {
13676
- const bestProvider = response.data.reduce(
13677
- (best, current) => current.destination_amount > best.destination_amount ? current : best
13678
- );
13679
- setSelectedProvider(bestProvider);
13680
- setAutoSelectedProvider(bestProvider.service_provider);
13679
+ } else if (response.data.length > 0) {
13680
+ const firstProvider = response.data[0];
13681
+ setSelectedProvider(firstProvider);
13682
+ setAutoSelectedProvider(firstProvider.service_provider);
13681
13683
  setIsAutoSelected(true);
13682
13684
  setHasManualSelection(false);
13685
+ } else {
13686
+ setSelectedProvider(null);
13687
+ setIsAutoSelected(false);
13688
+ setHasManualSelection(false);
13683
13689
  }
13684
13690
  } else {
13685
13691
  if (response.data.length > 0) {
13686
- const bestProvider = response.data.reduce(
13687
- (best, current) => current.destination_amount > best.destination_amount ? current : best
13688
- );
13689
- setSelectedProvider(bestProvider);
13690
- setAutoSelectedProvider(bestProvider.service_provider);
13692
+ const firstProvider = response.data[0];
13693
+ setSelectedProvider(firstProvider);
13694
+ setAutoSelectedProvider(firstProvider.service_provider);
13691
13695
  setIsAutoSelected(true);
13692
13696
  }
13693
13697
  }
@@ -13783,19 +13787,7 @@ function BuyWithCard({
13783
13787
  window.open(sessionStartUrl, "_blank");
13784
13788
  handleViewChange("onramp");
13785
13789
  };
13786
- const getProviderBadges = (quote, allQuotes) => {
13787
- const badges = [];
13788
- const maxDestination = Math.max(
13789
- ...allQuotes.map((q) => q.destination_amount)
13790
- );
13791
- if (quote.destination_amount === maxDestination) {
13792
- badges.push("Best price");
13793
- }
13794
- return badges;
13795
- };
13796
- const sortedQuotes = [...quotes].sort(
13797
- (a, b) => b.destination_amount - a.destination_amount
13798
- );
13790
+ const sortedQuotes = quotes;
13799
13791
  const currencySymbol = getCurrencySymbol(currency);
13800
13792
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
13801
13793
  "div",
@@ -13997,31 +13989,7 @@ function BuyWithCard({
13997
13989
  children: selectedProvider.service_provider_display_name
13998
13990
  }
13999
13991
  ),
14000
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-0.5", children: [
14001
- isAutoSelected && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14002
- "span",
14003
- {
14004
- className: "uf-text-[10px] uf-font-normal",
14005
- style: {
14006
- color: colors2.success,
14007
- fontFamily: fonts.regular
14008
- },
14009
- children: "Best price"
14010
- }
14011
- ),
14012
- isAutoSelected && selectedProvider.low_kyc === false && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14013
- "span",
14014
- {
14015
- className: "uf-text-[10px]",
14016
- style: {
14017
- color: components.card.labelColor,
14018
- fontFamily: fonts.regular
14019
- },
14020
- children: "\u2022"
14021
- }
14022
- ),
14023
- selectedProvider.low_kyc === false && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "uf-text-[10px] uf-text-muted-foreground uf-font-normal", children: "No document upload" })
14024
- ] })
13992
+ selectedProvider.low_kyc === false && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "uf-text-[10px] uf-text-muted-foreground uf-font-normal", children: "No document upload" }) })
14025
13993
  ] }),
14026
13994
  quotes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14027
13995
  ChevronRight,
@@ -14085,7 +14053,6 @@ function BuyWithCard({
14085
14053
  {
14086
14054
  className: `uf-transition-all uf-duration-300 uf-min-h-[420px] uf-flex uf-flex-col ${showQuotesView && !showOnrampView ? "uf-opacity-100" : "uf-opacity-0 uf-pointer-events-none uf-absolute uf-inset-0"}`,
14087
14055
  children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "uf-space-y-2 uf-pt-2 uf-pb-8 uf-overflow-y-auto uf-flex-1 uf-min-h-0", children: sortedQuotes.map((quote, index2) => {
14088
- const badges = getProviderBadges(quote, sortedQuotes);
14089
14056
  const displayName = quote.service_provider_display_name;
14090
14057
  const isSelected = selectedProvider?.service_provider === quote.service_provider;
14091
14058
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
@@ -14128,39 +14095,17 @@ function BuyWithCard({
14128
14095
  children: displayName
14129
14096
  }
14130
14097
  ),
14131
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-0.5", children: [
14132
- badges.map((badge, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
14133
- "span",
14134
- {
14135
- className: "uf-text-[10px] uf-font-normal",
14136
- style: { color: colors2.success },
14137
- children: [
14138
- badge,
14139
- i < badges.length - 1 && ","
14140
- ]
14098
+ quote.low_kyc === false && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14099
+ "span",
14100
+ {
14101
+ className: "uf-text-[10px] uf-font-normal",
14102
+ style: {
14103
+ color: components.card.subtextRightColor,
14104
+ fontFamily: fonts.regular
14141
14105
  },
14142
- i
14143
- )),
14144
- quote.low_kyc === false && badges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14145
- "span",
14146
- {
14147
- className: "uf-text-[10px]",
14148
- style: { color: components.card.subtextRightColor },
14149
- children: "\u2022"
14150
- }
14151
- ),
14152
- quote.low_kyc === false && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
14153
- "span",
14154
- {
14155
- className: "uf-text-[10px] uf-font-normal",
14156
- style: {
14157
- color: components.card.subtextRightColor,
14158
- fontFamily: fonts.regular
14159
- },
14160
- children: "No document upload"
14161
- }
14162
- )
14163
- ] })
14106
+ children: "No document upload"
14107
+ }
14108
+ ) })
14164
14109
  ] })
14165
14110
  ] }),
14166
14111
  /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "uf-text-right", children: [
@@ -17834,14 +17779,23 @@ function useAllowedCountry(publishableKey) {
17834
17779
  let isAllowed = null;
17835
17780
  if (ipData && configData) {
17836
17781
  const blockedCodes = configData.blocked_country_codes || [];
17782
+ const blockedSubdivisions = configData.blocked_country_subdivisions || [];
17837
17783
  const userCountryUpper = ipData.alpha2.toUpperCase();
17838
- isAllowed = !blockedCodes.some(
17784
+ const userSubdivision = ipData.subdivision_code || ipData.state || "";
17785
+ const userSubdivisionUpper = userSubdivision.toUpperCase();
17786
+ const isCountryBlocked = blockedCodes.some(
17839
17787
  (code) => code.toUpperCase() === userCountryUpper
17840
17788
  );
17789
+ const isSubdivisionBlocked = blockedSubdivisions.some((entry) => {
17790
+ if (entry.country_code.toUpperCase() !== userCountryUpper) return false;
17791
+ return entry.subdivision_codes.some(
17792
+ (code) => code.toUpperCase() === userSubdivisionUpper
17793
+ );
17794
+ });
17795
+ isAllowed = !isCountryBlocked && !isSubdivisionBlocked;
17841
17796
  }
17842
17797
  return {
17843
17798
  isAllowed,
17844
- // Return lowercase for consistency with useUserIp hook
17845
17799
  alpha2: ipData?.alpha2?.toLowerCase() ?? null,
17846
17800
  country: ipData?.country ?? null,
17847
17801
  isLoading,
@@ -18776,72 +18730,72 @@ function DepositPollingUi({
18776
18730
  var getChainKey = (chainId, chainType) => {
18777
18731
  return `${chainType}:${chainId}`;
18778
18732
  };
18779
- function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSourceChainId, defaultSourceTokenAddress, defaultSourceSymbol) {
18780
- if (!supportedTokens.length) return null;
18781
- let selectedTokenData;
18782
- let selectedChainData;
18783
- const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
18784
- if (defaultSourceTokenAddress && hasChainDefaults) {
18785
- for (const t11 of supportedTokens) {
18733
+ function resolveToken(tokens, defaultChainType, defaultChainId, defaultTokenAddress, defaultSymbol) {
18734
+ if (!tokens.length) return null;
18735
+ let selectedToken;
18736
+ let selectedChain;
18737
+ const hasChainDefaults = defaultChainType && defaultChainId;
18738
+ if (defaultTokenAddress && hasChainDefaults) {
18739
+ for (const t11 of tokens) {
18786
18740
  const matchingChain = t11.chains.find(
18787
- (c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
18741
+ (c) => c.token_address.toLowerCase() === defaultTokenAddress.toLowerCase() && c.chain_type === defaultChainType && c.chain_id === defaultChainId
18788
18742
  );
18789
18743
  if (matchingChain) {
18790
- selectedTokenData = t11;
18791
- selectedChainData = matchingChain;
18744
+ selectedToken = t11;
18745
+ selectedChain = matchingChain;
18792
18746
  break;
18793
18747
  }
18794
18748
  }
18795
18749
  }
18796
- if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
18797
- for (const t11 of supportedTokens) {
18798
- if (t11.symbol !== defaultSourceSymbol) continue;
18750
+ if (!selectedToken && defaultSymbol && hasChainDefaults) {
18751
+ for (const t11 of tokens) {
18752
+ if (t11.symbol !== defaultSymbol) continue;
18799
18753
  const matchedChain = t11.chains.find(
18800
- (c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
18754
+ (c) => c.chain_type === defaultChainType && c.chain_id === defaultChainId
18801
18755
  );
18802
18756
  if (matchedChain) {
18803
- selectedTokenData = t11;
18804
- selectedChainData = matchedChain;
18757
+ selectedToken = t11;
18758
+ selectedChain = matchedChain;
18805
18759
  break;
18806
18760
  }
18807
18761
  }
18808
18762
  }
18809
- if (!selectedTokenData) {
18810
- for (const t11 of supportedTokens) {
18763
+ if (!selectedToken) {
18764
+ for (const t11 of tokens) {
18811
18765
  if (t11.chains.length > 0) {
18812
- selectedTokenData = t11;
18813
- selectedChainData = t11.chains[0];
18766
+ selectedToken = t11;
18767
+ selectedChain = t11.chains[0];
18814
18768
  break;
18815
18769
  }
18816
18770
  }
18817
18771
  }
18818
- if (selectedTokenData && selectedChainData) {
18819
- return { token: selectedTokenData, chain: selectedChainData };
18772
+ if (selectedToken && selectedChain) {
18773
+ return { token: selectedToken, chain: selectedChain };
18820
18774
  }
18821
18775
  return null;
18822
18776
  }
18823
- function useDefaultSourceToken({
18824
- supportedTokens,
18825
- defaultSourceChainType,
18826
- defaultSourceChainId,
18827
- defaultSourceTokenAddress,
18828
- defaultSourceSymbol
18777
+ function useDefaultToken({
18778
+ tokens,
18779
+ defaultChainType,
18780
+ defaultChainId,
18781
+ defaultTokenAddress,
18782
+ defaultSymbol
18829
18783
  }) {
18830
18784
  const [token, setToken] = (0, import_react22.useState)(null);
18831
18785
  const [chain, setChain] = (0, import_react22.useState)(null);
18832
18786
  const [initialSelectionDone, setInitialSelectionDone] = (0, import_react22.useState)(false);
18833
18787
  const appliedDefaultsRef = (0, import_react22.useRef)("");
18834
18788
  (0, import_react22.useEffect)(() => {
18835
- if (!supportedTokens.length) return;
18836
- const defaultsKey = `${defaultSourceTokenAddress ?? ""}|${defaultSourceSymbol ?? ""}|${defaultSourceChainType ?? ""}|${defaultSourceChainId ?? ""}`;
18789
+ if (!tokens.length) return;
18790
+ const defaultsKey = `${defaultTokenAddress ?? ""}|${defaultSymbol ?? ""}|${defaultChainType ?? ""}|${defaultChainId ?? ""}`;
18837
18791
  const defaultsChanged = appliedDefaultsRef.current !== defaultsKey;
18838
18792
  if (initialSelectionDone && !defaultsChanged) return;
18839
- const result = resolveSourceToken(
18840
- supportedTokens,
18841
- defaultSourceChainType,
18842
- defaultSourceChainId,
18843
- defaultSourceTokenAddress,
18844
- defaultSourceSymbol
18793
+ const result = resolveToken(
18794
+ tokens,
18795
+ defaultChainType,
18796
+ defaultChainId,
18797
+ defaultTokenAddress,
18798
+ defaultSymbol
18845
18799
  );
18846
18800
  if (result) {
18847
18801
  setToken(result.token.symbol);
@@ -18850,16 +18804,16 @@ function useDefaultSourceToken({
18850
18804
  setInitialSelectionDone(true);
18851
18805
  }
18852
18806
  }, [
18853
- supportedTokens,
18854
- defaultSourceTokenAddress,
18855
- defaultSourceSymbol,
18856
- defaultSourceChainType,
18857
- defaultSourceChainId,
18807
+ tokens,
18808
+ defaultTokenAddress,
18809
+ defaultSymbol,
18810
+ defaultChainType,
18811
+ defaultChainId,
18858
18812
  initialSelectionDone
18859
18813
  ]);
18860
18814
  (0, import_react22.useEffect)(() => {
18861
- if (!supportedTokens.length || !token) return;
18862
- const currentToken = supportedTokens.find((t11) => t11.symbol === token);
18815
+ if (!tokens.length || !token) return;
18816
+ const currentToken = tokens.find((t11) => t11.symbol === token);
18863
18817
  if (!currentToken || currentToken.chains.length === 0) return;
18864
18818
  const isChainAvailable = chain && currentToken.chains.some((c) => {
18865
18819
  return getChainKey(c.chain_id, c.chain_type) === chain;
@@ -18868,9 +18822,24 @@ function useDefaultSourceToken({
18868
18822
  const firstChain = currentToken.chains[0];
18869
18823
  setChain(getChainKey(firstChain.chain_id, firstChain.chain_type));
18870
18824
  }
18871
- }, [token, supportedTokens, chain]);
18825
+ }, [token, tokens, chain]);
18872
18826
  return { token, chain, setToken, setChain, initialSelectionDone };
18873
18827
  }
18828
+ function useDefaultSourceToken({
18829
+ supportedTokens,
18830
+ defaultSourceChainType,
18831
+ defaultSourceChainId,
18832
+ defaultSourceTokenAddress,
18833
+ defaultSourceSymbol
18834
+ }) {
18835
+ return useDefaultToken({
18836
+ tokens: supportedTokens,
18837
+ defaultChainType: defaultSourceChainType,
18838
+ defaultChainId: defaultSourceChainId,
18839
+ defaultTokenAddress: defaultSourceTokenAddress,
18840
+ defaultSymbol: defaultSourceSymbol
18841
+ });
18842
+ }
18874
18843
  function DepositFooterLinks({
18875
18844
  onGlossaryClick
18876
18845
  }) {
@@ -23147,19 +23116,30 @@ function DepositModal({
23147
23116
  }
23148
23117
  ) });
23149
23118
  }
23119
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
23120
+ "succeeded",
23121
+ "expired",
23122
+ "refunded",
23123
+ "canceled"
23124
+ ]);
23150
23125
  function usePaymentIntent(params) {
23151
23126
  const {
23152
23127
  clientSecret,
23153
23128
  publishableKey,
23154
23129
  enabled = true,
23155
- pollingInterval = 5e3
23130
+ pollingInterval = 3e3
23156
23131
  } = params;
23157
23132
  return (0, import_react_query11.useQuery)({
23158
23133
  queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
23159
23134
  queryFn: () => retrievePaymentIntent(clientSecret, publishableKey),
23160
23135
  enabled: enabled && !!clientSecret && !!publishableKey,
23161
23136
  staleTime: 0,
23162
- refetchInterval: pollingInterval || false,
23137
+ refetchInterval: (query) => {
23138
+ if (!pollingInterval) return false;
23139
+ const status = query.state.data?.status;
23140
+ if (status && TERMINAL_STATUSES.has(status)) return false;
23141
+ return pollingInterval;
23142
+ },
23163
23143
  refetchOnWindowFocus: true,
23164
23144
  retry: 3,
23165
23145
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
@@ -23283,7 +23263,7 @@ function CheckoutModal({
23283
23263
  clientSecret,
23284
23264
  publishableKey,
23285
23265
  enabled: open && !!clientSecret,
23286
- pollingInterval: 5e3
23266
+ pollingInterval: 3e3
23287
23267
  });
23288
23268
  const { projectConfig } = useProjectConfig({
23289
23269
  publishableKey,
@@ -23824,6 +23804,21 @@ function useSupportedDestinationTokens(publishableKey, enabled = true) {
23824
23804
  enabled
23825
23805
  });
23826
23806
  }
23807
+ function useDefaultDestinationToken({
23808
+ destinationTokens,
23809
+ defaultDestinationChainType,
23810
+ defaultDestinationChainId,
23811
+ defaultDestinationTokenAddress,
23812
+ defaultDestinationSymbol
23813
+ }) {
23814
+ return useDefaultToken({
23815
+ tokens: destinationTokens,
23816
+ defaultChainType: defaultDestinationChainType,
23817
+ defaultChainId: defaultDestinationChainId,
23818
+ defaultTokenAddress: defaultDestinationTokenAddress,
23819
+ defaultSymbol: defaultDestinationSymbol
23820
+ });
23821
+ }
23827
23822
  function useSourceTokenValidation(params) {
23828
23823
  const {
23829
23824
  sourceChainType,
@@ -25070,6 +25065,10 @@ function WithdrawModal({
25070
25065
  sourceTokenSymbol,
25071
25066
  recipientAddress: recipientAddressProp,
25072
25067
  senderAddress,
25068
+ defaultDestinationChainType,
25069
+ defaultDestinationChainId,
25070
+ defaultDestinationTokenAddress,
25071
+ defaultDestinationSymbol,
25073
25072
  onWithdraw,
25074
25073
  onWithdrawSuccess,
25075
25074
  onWithdrawError,
@@ -25113,8 +25112,21 @@ function WithdrawModal({
25113
25112
  publishableKey,
25114
25113
  enabled: open
25115
25114
  });
25116
- const [selectedToken, setSelectedToken] = (0, import_react27.useState)(null);
25117
- const [selectedChain, setSelectedChain] = (0, import_react27.useState)(null);
25115
+ const {
25116
+ token: selectedTokenSymbol,
25117
+ chain: selectedChainKey,
25118
+ setToken: setSelectedTokenSymbol,
25119
+ setChain: setSelectedChainKey,
25120
+ initialSelectionDone
25121
+ } = useDefaultDestinationToken({
25122
+ destinationTokens,
25123
+ defaultDestinationChainType,
25124
+ defaultDestinationChainId,
25125
+ defaultDestinationTokenAddress,
25126
+ defaultDestinationSymbol
25127
+ });
25128
+ const selectedToken = selectedTokenSymbol ? destinationTokens.find((t11) => t11.symbol === selectedTokenSymbol) ?? null : null;
25129
+ const selectedChain = selectedToken && selectedChainKey ? selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === selectedChainKey) ?? null : null;
25118
25130
  const [view, setView] = (0, import_react27.useState)("form");
25119
25131
  const [withdrawDepositWalletId, setWithdrawDepositWalletId] = (0, import_react27.useState)();
25120
25132
  const [selectedExecution, setSelectedExecution] = (0, import_react27.useState)(null);
@@ -25156,21 +25168,11 @@ function WithdrawModal({
25156
25168
  setSubmittedTxInfo(txInfo);
25157
25169
  setView("confirming");
25158
25170
  }, []);
25159
- (0, import_react27.useEffect)(() => {
25160
- if (!destinationTokens.length || selectedToken) return;
25161
- const first = destinationTokens[0];
25162
- if (first?.chains.length > 0) {
25163
- setSelectedToken(first);
25164
- setSelectedChain(first.chains[0]);
25165
- }
25166
- }, [destinationTokens, selectedToken]);
25167
25171
  const resetViewTimeoutRef = (0, import_react27.useRef)(null);
25168
25172
  const handleClose = (0, import_react27.useCallback)(() => {
25169
25173
  onOpenChange(false);
25170
25174
  if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
25171
25175
  resetViewTimeoutRef.current = setTimeout(() => {
25172
- setSelectedToken(null);
25173
- setSelectedChain(null);
25174
25176
  setView("form");
25175
25177
  setSelectedExecution(null);
25176
25178
  setSubmittedTxInfo(null);
@@ -25184,8 +25186,6 @@ function WithdrawModal({
25184
25186
  clearTimeout(resetViewTimeoutRef.current);
25185
25187
  resetViewTimeoutRef.current = null;
25186
25188
  }
25187
- setSelectedToken(null);
25188
- setSelectedChain(null);
25189
25189
  setView("form");
25190
25190
  setSelectedExecution(null);
25191
25191
  setSubmittedTxInfo(null);
@@ -25195,19 +25195,13 @@ function WithdrawModal({
25195
25195
  if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
25196
25196
  }, []);
25197
25197
  const handleTokenSymbolChange = (0, import_react27.useCallback)((symbol) => {
25198
- const tok = destinationTokens.find((t11) => t11.symbol === symbol);
25199
- if (tok) {
25200
- setSelectedToken(tok);
25201
- if (tok.chains.length > 0) setSelectedChain(tok.chains[0]);
25202
- }
25203
- }, [destinationTokens]);
25198
+ setSelectedTokenSymbol(symbol);
25199
+ }, [setSelectedTokenSymbol]);
25204
25200
  const handleChainKeyChange = (0, import_react27.useCallback)((chainKey) => {
25205
- if (!selectedToken) return;
25206
- const chain = selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === chainKey);
25207
- if (chain) setSelectedChain(chain);
25208
- }, [selectedToken]);
25201
+ setSelectedChainKey(chainKey);
25202
+ }, [setSelectedChainKey]);
25209
25203
  const isSourceSupported = sourceValidation?.isSupported ?? null;
25210
- const isAnyLoading = tokensLoading || isCheckingSourceToken;
25204
+ const isAnyLoading = tokensLoading || isCheckingSourceToken || destinationTokens.length > 0 && !initialSelectionDone;
25211
25205
  const withdrawPoweredByFooter = /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
25212
25206
  return /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(Dialog2, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
25213
25207
  DialogContent2,
@@ -25620,6 +25614,10 @@ function UnifoldProvider2({
25620
25614
  sourceTokenAddress: withdrawConfig.sourceTokenAddress,
25621
25615
  sourceTokenSymbol: withdrawConfig.sourceTokenSymbol,
25622
25616
  recipientAddress: withdrawConfig.recipientAddress,
25617
+ defaultDestinationChainType: withdrawConfig.defaultDestinationChainType,
25618
+ defaultDestinationChainId: withdrawConfig.defaultDestinationChainId,
25619
+ defaultDestinationTokenAddress: withdrawConfig.defaultDestinationTokenAddress,
25620
+ defaultDestinationSymbol: withdrawConfig.defaultDestinationSymbol,
25623
25621
  senderAddress: withdrawConfig.senderAddress,
25624
25622
  onWithdraw: withdrawConfig.withdraw,
25625
25623
  onWithdrawSuccess: handleWithdrawSuccess,
@@ -25719,6 +25717,7 @@ function useAllowedCountry2() {
25719
25717
  getApiBaseUrl,
25720
25718
  getChainName,
25721
25719
  getDefaultOnrampToken,
25720
+ getDepositQuote,
25722
25721
  getFiatCurrencies,
25723
25722
  getIconUrl,
25724
25723
  getIconUrlWithCdn,
@@ -25732,9 +25731,11 @@ function useAllowedCountry2() {
25732
25731
  getWalletByChainType,
25733
25732
  i18n,
25734
25733
  queryExecutions,
25734
+ retrievePaymentIntent,
25735
25735
  sendSolanaTransaction,
25736
25736
  setApiConfig,
25737
25737
  useAllowedCountry,
25738
+ useSupportedDepositTokens,
25738
25739
  useUnifold,
25739
25740
  useUserIp
25740
25741
  });
package/dist/index.mjs CHANGED
@@ -6373,6 +6373,9 @@ function getOnrampSessionStartUrl(request, publishableKey) {
6373
6373
  if (request.external_id) {
6374
6374
  params.append("external_id", request.external_id);
6375
6375
  }
6376
+ if (request.email) {
6377
+ params.append("email", request.email);
6378
+ }
6376
6379
  return `${API_BASE_URL}/v1/public/onramps/sessions/start?${params.toString()}`;
6377
6380
  }
6378
6381
  async function getDefaultOnrampToken(params, publishableKey) {
@@ -13652,31 +13655,29 @@ function BuyWithCard({
13652
13655
  );
13653
13656
  if (manualProviderStillExists) {
13654
13657
  setSelectedProvider(manualProviderStillExists);
13655
- const bestProvider = response.data.reduce(
13656
- (best, current) => current.destination_amount > best.destination_amount ? current : best
13657
- );
13658
+ const firstProvider = response.data[0];
13658
13659
  if (!autoSelectedProvider) {
13659
- setAutoSelectedProvider(bestProvider.service_provider);
13660
+ setAutoSelectedProvider(firstProvider.service_provider);
13660
13661
  }
13661
13662
  setIsAutoSelected(
13662
13663
  manualProviderStillExists.service_provider === autoSelectedProvider
13663
13664
  );
13664
- } else {
13665
- const bestProvider = response.data.reduce(
13666
- (best, current) => current.destination_amount > best.destination_amount ? current : best
13667
- );
13668
- setSelectedProvider(bestProvider);
13669
- setAutoSelectedProvider(bestProvider.service_provider);
13665
+ } else if (response.data.length > 0) {
13666
+ const firstProvider = response.data[0];
13667
+ setSelectedProvider(firstProvider);
13668
+ setAutoSelectedProvider(firstProvider.service_provider);
13670
13669
  setIsAutoSelected(true);
13671
13670
  setHasManualSelection(false);
13671
+ } else {
13672
+ setSelectedProvider(null);
13673
+ setIsAutoSelected(false);
13674
+ setHasManualSelection(false);
13672
13675
  }
13673
13676
  } else {
13674
13677
  if (response.data.length > 0) {
13675
- const bestProvider = response.data.reduce(
13676
- (best, current) => current.destination_amount > best.destination_amount ? current : best
13677
- );
13678
- setSelectedProvider(bestProvider);
13679
- setAutoSelectedProvider(bestProvider.service_provider);
13678
+ const firstProvider = response.data[0];
13679
+ setSelectedProvider(firstProvider);
13680
+ setAutoSelectedProvider(firstProvider.service_provider);
13680
13681
  setIsAutoSelected(true);
13681
13682
  }
13682
13683
  }
@@ -13772,19 +13773,7 @@ function BuyWithCard({
13772
13773
  window.open(sessionStartUrl, "_blank");
13773
13774
  handleViewChange("onramp");
13774
13775
  };
13775
- const getProviderBadges = (quote, allQuotes) => {
13776
- const badges = [];
13777
- const maxDestination = Math.max(
13778
- ...allQuotes.map((q) => q.destination_amount)
13779
- );
13780
- if (quote.destination_amount === maxDestination) {
13781
- badges.push("Best price");
13782
- }
13783
- return badges;
13784
- };
13785
- const sortedQuotes = [...quotes].sort(
13786
- (a, b) => b.destination_amount - a.destination_amount
13787
- );
13776
+ const sortedQuotes = quotes;
13788
13777
  const currencySymbol = getCurrencySymbol(currency);
13789
13778
  return /* @__PURE__ */ jsxs8(
13790
13779
  "div",
@@ -13986,31 +13975,7 @@ function BuyWithCard({
13986
13975
  children: selectedProvider.service_provider_display_name
13987
13976
  }
13988
13977
  ),
13989
- /* @__PURE__ */ jsxs8("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-0.5", children: [
13990
- isAutoSelected && /* @__PURE__ */ jsx102(
13991
- "span",
13992
- {
13993
- className: "uf-text-[10px] uf-font-normal",
13994
- style: {
13995
- color: colors2.success,
13996
- fontFamily: fonts.regular
13997
- },
13998
- children: "Best price"
13999
- }
14000
- ),
14001
- isAutoSelected && selectedProvider.low_kyc === false && /* @__PURE__ */ jsx102(
14002
- "span",
14003
- {
14004
- className: "uf-text-[10px]",
14005
- style: {
14006
- color: components.card.labelColor,
14007
- fontFamily: fonts.regular
14008
- },
14009
- children: "\u2022"
14010
- }
14011
- ),
14012
- selectedProvider.low_kyc === false && /* @__PURE__ */ jsx102("span", { className: "uf-text-[10px] uf-text-muted-foreground uf-font-normal", children: "No document upload" })
14013
- ] })
13978
+ selectedProvider.low_kyc === false && /* @__PURE__ */ jsx102("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-0.5", children: /* @__PURE__ */ jsx102("span", { className: "uf-text-[10px] uf-text-muted-foreground uf-font-normal", children: "No document upload" }) })
14014
13979
  ] }),
14015
13980
  quotes.length > 0 && /* @__PURE__ */ jsx102(
14016
13981
  ChevronRight,
@@ -14074,7 +14039,6 @@ function BuyWithCard({
14074
14039
  {
14075
14040
  className: `uf-transition-all uf-duration-300 uf-min-h-[420px] uf-flex uf-flex-col ${showQuotesView && !showOnrampView ? "uf-opacity-100" : "uf-opacity-0 uf-pointer-events-none uf-absolute uf-inset-0"}`,
14076
14041
  children: /* @__PURE__ */ jsx102("div", { className: "uf-space-y-2 uf-pt-2 uf-pb-8 uf-overflow-y-auto uf-flex-1 uf-min-h-0", children: sortedQuotes.map((quote, index2) => {
14077
- const badges = getProviderBadges(quote, sortedQuotes);
14078
14042
  const displayName = quote.service_provider_display_name;
14079
14043
  const isSelected = selectedProvider?.service_provider === quote.service_provider;
14080
14044
  return /* @__PURE__ */ jsxs8(
@@ -14117,39 +14081,17 @@ function BuyWithCard({
14117
14081
  children: displayName
14118
14082
  }
14119
14083
  ),
14120
- /* @__PURE__ */ jsxs8("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-0.5", children: [
14121
- badges.map((badge, i) => /* @__PURE__ */ jsxs8(
14122
- "span",
14123
- {
14124
- className: "uf-text-[10px] uf-font-normal",
14125
- style: { color: colors2.success },
14126
- children: [
14127
- badge,
14128
- i < badges.length - 1 && ","
14129
- ]
14084
+ quote.low_kyc === false && /* @__PURE__ */ jsx102("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-0.5", children: /* @__PURE__ */ jsx102(
14085
+ "span",
14086
+ {
14087
+ className: "uf-text-[10px] uf-font-normal",
14088
+ style: {
14089
+ color: components.card.subtextRightColor,
14090
+ fontFamily: fonts.regular
14130
14091
  },
14131
- i
14132
- )),
14133
- quote.low_kyc === false && badges.length > 0 && /* @__PURE__ */ jsx102(
14134
- "span",
14135
- {
14136
- className: "uf-text-[10px]",
14137
- style: { color: components.card.subtextRightColor },
14138
- children: "\u2022"
14139
- }
14140
- ),
14141
- quote.low_kyc === false && /* @__PURE__ */ jsx102(
14142
- "span",
14143
- {
14144
- className: "uf-text-[10px] uf-font-normal",
14145
- style: {
14146
- color: components.card.subtextRightColor,
14147
- fontFamily: fonts.regular
14148
- },
14149
- children: "No document upload"
14150
- }
14151
- )
14152
- ] })
14092
+ children: "No document upload"
14093
+ }
14094
+ ) })
14153
14095
  ] })
14154
14096
  ] }),
14155
14097
  /* @__PURE__ */ jsxs8("div", { className: "uf-text-right", children: [
@@ -17823,14 +17765,23 @@ function useAllowedCountry(publishableKey) {
17823
17765
  let isAllowed = null;
17824
17766
  if (ipData && configData) {
17825
17767
  const blockedCodes = configData.blocked_country_codes || [];
17768
+ const blockedSubdivisions = configData.blocked_country_subdivisions || [];
17826
17769
  const userCountryUpper = ipData.alpha2.toUpperCase();
17827
- isAllowed = !blockedCodes.some(
17770
+ const userSubdivision = ipData.subdivision_code || ipData.state || "";
17771
+ const userSubdivisionUpper = userSubdivision.toUpperCase();
17772
+ const isCountryBlocked = blockedCodes.some(
17828
17773
  (code) => code.toUpperCase() === userCountryUpper
17829
17774
  );
17775
+ const isSubdivisionBlocked = blockedSubdivisions.some((entry) => {
17776
+ if (entry.country_code.toUpperCase() !== userCountryUpper) return false;
17777
+ return entry.subdivision_codes.some(
17778
+ (code) => code.toUpperCase() === userSubdivisionUpper
17779
+ );
17780
+ });
17781
+ isAllowed = !isCountryBlocked && !isSubdivisionBlocked;
17830
17782
  }
17831
17783
  return {
17832
17784
  isAllowed,
17833
- // Return lowercase for consistency with useUserIp hook
17834
17785
  alpha2: ipData?.alpha2?.toLowerCase() ?? null,
17835
17786
  country: ipData?.country ?? null,
17836
17787
  isLoading,
@@ -18765,72 +18716,72 @@ function DepositPollingUi({
18765
18716
  var getChainKey = (chainId, chainType) => {
18766
18717
  return `${chainType}:${chainId}`;
18767
18718
  };
18768
- function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSourceChainId, defaultSourceTokenAddress, defaultSourceSymbol) {
18769
- if (!supportedTokens.length) return null;
18770
- let selectedTokenData;
18771
- let selectedChainData;
18772
- const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
18773
- if (defaultSourceTokenAddress && hasChainDefaults) {
18774
- for (const t11 of supportedTokens) {
18719
+ function resolveToken(tokens, defaultChainType, defaultChainId, defaultTokenAddress, defaultSymbol) {
18720
+ if (!tokens.length) return null;
18721
+ let selectedToken;
18722
+ let selectedChain;
18723
+ const hasChainDefaults = defaultChainType && defaultChainId;
18724
+ if (defaultTokenAddress && hasChainDefaults) {
18725
+ for (const t11 of tokens) {
18775
18726
  const matchingChain = t11.chains.find(
18776
- (c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
18727
+ (c) => c.token_address.toLowerCase() === defaultTokenAddress.toLowerCase() && c.chain_type === defaultChainType && c.chain_id === defaultChainId
18777
18728
  );
18778
18729
  if (matchingChain) {
18779
- selectedTokenData = t11;
18780
- selectedChainData = matchingChain;
18730
+ selectedToken = t11;
18731
+ selectedChain = matchingChain;
18781
18732
  break;
18782
18733
  }
18783
18734
  }
18784
18735
  }
18785
- if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
18786
- for (const t11 of supportedTokens) {
18787
- if (t11.symbol !== defaultSourceSymbol) continue;
18736
+ if (!selectedToken && defaultSymbol && hasChainDefaults) {
18737
+ for (const t11 of tokens) {
18738
+ if (t11.symbol !== defaultSymbol) continue;
18788
18739
  const matchedChain = t11.chains.find(
18789
- (c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
18740
+ (c) => c.chain_type === defaultChainType && c.chain_id === defaultChainId
18790
18741
  );
18791
18742
  if (matchedChain) {
18792
- selectedTokenData = t11;
18793
- selectedChainData = matchedChain;
18743
+ selectedToken = t11;
18744
+ selectedChain = matchedChain;
18794
18745
  break;
18795
18746
  }
18796
18747
  }
18797
18748
  }
18798
- if (!selectedTokenData) {
18799
- for (const t11 of supportedTokens) {
18749
+ if (!selectedToken) {
18750
+ for (const t11 of tokens) {
18800
18751
  if (t11.chains.length > 0) {
18801
- selectedTokenData = t11;
18802
- selectedChainData = t11.chains[0];
18752
+ selectedToken = t11;
18753
+ selectedChain = t11.chains[0];
18803
18754
  break;
18804
18755
  }
18805
18756
  }
18806
18757
  }
18807
- if (selectedTokenData && selectedChainData) {
18808
- return { token: selectedTokenData, chain: selectedChainData };
18758
+ if (selectedToken && selectedChain) {
18759
+ return { token: selectedToken, chain: selectedChain };
18809
18760
  }
18810
18761
  return null;
18811
18762
  }
18812
- function useDefaultSourceToken({
18813
- supportedTokens,
18814
- defaultSourceChainType,
18815
- defaultSourceChainId,
18816
- defaultSourceTokenAddress,
18817
- defaultSourceSymbol
18763
+ function useDefaultToken({
18764
+ tokens,
18765
+ defaultChainType,
18766
+ defaultChainId,
18767
+ defaultTokenAddress,
18768
+ defaultSymbol
18818
18769
  }) {
18819
18770
  const [token, setToken] = useState192(null);
18820
18771
  const [chain, setChain] = useState192(null);
18821
18772
  const [initialSelectionDone, setInitialSelectionDone] = useState192(false);
18822
18773
  const appliedDefaultsRef = useRef52("");
18823
18774
  useEffect162(() => {
18824
- if (!supportedTokens.length) return;
18825
- const defaultsKey = `${defaultSourceTokenAddress ?? ""}|${defaultSourceSymbol ?? ""}|${defaultSourceChainType ?? ""}|${defaultSourceChainId ?? ""}`;
18775
+ if (!tokens.length) return;
18776
+ const defaultsKey = `${defaultTokenAddress ?? ""}|${defaultSymbol ?? ""}|${defaultChainType ?? ""}|${defaultChainId ?? ""}`;
18826
18777
  const defaultsChanged = appliedDefaultsRef.current !== defaultsKey;
18827
18778
  if (initialSelectionDone && !defaultsChanged) return;
18828
- const result = resolveSourceToken(
18829
- supportedTokens,
18830
- defaultSourceChainType,
18831
- defaultSourceChainId,
18832
- defaultSourceTokenAddress,
18833
- defaultSourceSymbol
18779
+ const result = resolveToken(
18780
+ tokens,
18781
+ defaultChainType,
18782
+ defaultChainId,
18783
+ defaultTokenAddress,
18784
+ defaultSymbol
18834
18785
  );
18835
18786
  if (result) {
18836
18787
  setToken(result.token.symbol);
@@ -18839,16 +18790,16 @@ function useDefaultSourceToken({
18839
18790
  setInitialSelectionDone(true);
18840
18791
  }
18841
18792
  }, [
18842
- supportedTokens,
18843
- defaultSourceTokenAddress,
18844
- defaultSourceSymbol,
18845
- defaultSourceChainType,
18846
- defaultSourceChainId,
18793
+ tokens,
18794
+ defaultTokenAddress,
18795
+ defaultSymbol,
18796
+ defaultChainType,
18797
+ defaultChainId,
18847
18798
  initialSelectionDone
18848
18799
  ]);
18849
18800
  useEffect162(() => {
18850
- if (!supportedTokens.length || !token) return;
18851
- const currentToken = supportedTokens.find((t11) => t11.symbol === token);
18801
+ if (!tokens.length || !token) return;
18802
+ const currentToken = tokens.find((t11) => t11.symbol === token);
18852
18803
  if (!currentToken || currentToken.chains.length === 0) return;
18853
18804
  const isChainAvailable = chain && currentToken.chains.some((c) => {
18854
18805
  return getChainKey(c.chain_id, c.chain_type) === chain;
@@ -18857,9 +18808,24 @@ function useDefaultSourceToken({
18857
18808
  const firstChain = currentToken.chains[0];
18858
18809
  setChain(getChainKey(firstChain.chain_id, firstChain.chain_type));
18859
18810
  }
18860
- }, [token, supportedTokens, chain]);
18811
+ }, [token, tokens, chain]);
18861
18812
  return { token, chain, setToken, setChain, initialSelectionDone };
18862
18813
  }
18814
+ function useDefaultSourceToken({
18815
+ supportedTokens,
18816
+ defaultSourceChainType,
18817
+ defaultSourceChainId,
18818
+ defaultSourceTokenAddress,
18819
+ defaultSourceSymbol
18820
+ }) {
18821
+ return useDefaultToken({
18822
+ tokens: supportedTokens,
18823
+ defaultChainType: defaultSourceChainType,
18824
+ defaultChainId: defaultSourceChainId,
18825
+ defaultTokenAddress: defaultSourceTokenAddress,
18826
+ defaultSymbol: defaultSourceSymbol
18827
+ });
18828
+ }
18863
18829
  function DepositFooterLinks({
18864
18830
  onGlossaryClick
18865
18831
  }) {
@@ -23136,19 +23102,30 @@ function DepositModal({
23136
23102
  }
23137
23103
  ) });
23138
23104
  }
23105
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
23106
+ "succeeded",
23107
+ "expired",
23108
+ "refunded",
23109
+ "canceled"
23110
+ ]);
23139
23111
  function usePaymentIntent(params) {
23140
23112
  const {
23141
23113
  clientSecret,
23142
23114
  publishableKey,
23143
23115
  enabled = true,
23144
- pollingInterval = 5e3
23116
+ pollingInterval = 3e3
23145
23117
  } = params;
23146
23118
  return useQuery9({
23147
23119
  queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
23148
23120
  queryFn: () => retrievePaymentIntent(clientSecret, publishableKey),
23149
23121
  enabled: enabled && !!clientSecret && !!publishableKey,
23150
23122
  staleTime: 0,
23151
- refetchInterval: pollingInterval || false,
23123
+ refetchInterval: (query) => {
23124
+ if (!pollingInterval) return false;
23125
+ const status = query.state.data?.status;
23126
+ if (status && TERMINAL_STATUSES.has(status)) return false;
23127
+ return pollingInterval;
23128
+ },
23152
23129
  refetchOnWindowFocus: true,
23153
23130
  retry: 3,
23154
23131
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
@@ -23272,7 +23249,7 @@ function CheckoutModal({
23272
23249
  clientSecret,
23273
23250
  publishableKey,
23274
23251
  enabled: open && !!clientSecret,
23275
- pollingInterval: 5e3
23252
+ pollingInterval: 3e3
23276
23253
  });
23277
23254
  const { projectConfig } = useProjectConfig({
23278
23255
  publishableKey,
@@ -23813,6 +23790,21 @@ function useSupportedDestinationTokens(publishableKey, enabled = true) {
23813
23790
  enabled
23814
23791
  });
23815
23792
  }
23793
+ function useDefaultDestinationToken({
23794
+ destinationTokens,
23795
+ defaultDestinationChainType,
23796
+ defaultDestinationChainId,
23797
+ defaultDestinationTokenAddress,
23798
+ defaultDestinationSymbol
23799
+ }) {
23800
+ return useDefaultToken({
23801
+ tokens: destinationTokens,
23802
+ defaultChainType: defaultDestinationChainType,
23803
+ defaultChainId: defaultDestinationChainId,
23804
+ defaultTokenAddress: defaultDestinationTokenAddress,
23805
+ defaultSymbol: defaultDestinationSymbol
23806
+ });
23807
+ }
23816
23808
  function useSourceTokenValidation(params) {
23817
23809
  const {
23818
23810
  sourceChainType,
@@ -25059,6 +25051,10 @@ function WithdrawModal({
25059
25051
  sourceTokenSymbol,
25060
25052
  recipientAddress: recipientAddressProp,
25061
25053
  senderAddress,
25054
+ defaultDestinationChainType,
25055
+ defaultDestinationChainId,
25056
+ defaultDestinationTokenAddress,
25057
+ defaultDestinationSymbol,
25062
25058
  onWithdraw,
25063
25059
  onWithdrawSuccess,
25064
25060
  onWithdrawError,
@@ -25102,8 +25098,21 @@ function WithdrawModal({
25102
25098
  publishableKey,
25103
25099
  enabled: open
25104
25100
  });
25105
- const [selectedToken, setSelectedToken] = useState32(null);
25106
- const [selectedChain, setSelectedChain] = useState32(null);
25101
+ const {
25102
+ token: selectedTokenSymbol,
25103
+ chain: selectedChainKey,
25104
+ setToken: setSelectedTokenSymbol,
25105
+ setChain: setSelectedChainKey,
25106
+ initialSelectionDone
25107
+ } = useDefaultDestinationToken({
25108
+ destinationTokens,
25109
+ defaultDestinationChainType,
25110
+ defaultDestinationChainId,
25111
+ defaultDestinationTokenAddress,
25112
+ defaultDestinationSymbol
25113
+ });
25114
+ const selectedToken = selectedTokenSymbol ? destinationTokens.find((t11) => t11.symbol === selectedTokenSymbol) ?? null : null;
25115
+ const selectedChain = selectedToken && selectedChainKey ? selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === selectedChainKey) ?? null : null;
25107
25116
  const [view, setView] = useState32("form");
25108
25117
  const [withdrawDepositWalletId, setWithdrawDepositWalletId] = useState32();
25109
25118
  const [selectedExecution, setSelectedExecution] = useState32(null);
@@ -25145,21 +25154,11 @@ function WithdrawModal({
25145
25154
  setSubmittedTxInfo(txInfo);
25146
25155
  setView("confirming");
25147
25156
  }, []);
25148
- useEffect272(() => {
25149
- if (!destinationTokens.length || selectedToken) return;
25150
- const first = destinationTokens[0];
25151
- if (first?.chains.length > 0) {
25152
- setSelectedToken(first);
25153
- setSelectedChain(first.chains[0]);
25154
- }
25155
- }, [destinationTokens, selectedToken]);
25156
25157
  const resetViewTimeoutRef = useRef102(null);
25157
25158
  const handleClose = useCallback72(() => {
25158
25159
  onOpenChange(false);
25159
25160
  if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
25160
25161
  resetViewTimeoutRef.current = setTimeout(() => {
25161
- setSelectedToken(null);
25162
- setSelectedChain(null);
25163
25162
  setView("form");
25164
25163
  setSelectedExecution(null);
25165
25164
  setSubmittedTxInfo(null);
@@ -25173,8 +25172,6 @@ function WithdrawModal({
25173
25172
  clearTimeout(resetViewTimeoutRef.current);
25174
25173
  resetViewTimeoutRef.current = null;
25175
25174
  }
25176
- setSelectedToken(null);
25177
- setSelectedChain(null);
25178
25175
  setView("form");
25179
25176
  setSelectedExecution(null);
25180
25177
  setSubmittedTxInfo(null);
@@ -25184,19 +25181,13 @@ function WithdrawModal({
25184
25181
  if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
25185
25182
  }, []);
25186
25183
  const handleTokenSymbolChange = useCallback72((symbol) => {
25187
- const tok = destinationTokens.find((t11) => t11.symbol === symbol);
25188
- if (tok) {
25189
- setSelectedToken(tok);
25190
- if (tok.chains.length > 0) setSelectedChain(tok.chains[0]);
25191
- }
25192
- }, [destinationTokens]);
25184
+ setSelectedTokenSymbol(symbol);
25185
+ }, [setSelectedTokenSymbol]);
25193
25186
  const handleChainKeyChange = useCallback72((chainKey) => {
25194
- if (!selectedToken) return;
25195
- const chain = selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === chainKey);
25196
- if (chain) setSelectedChain(chain);
25197
- }, [selectedToken]);
25187
+ setSelectedChainKey(chainKey);
25188
+ }, [setSelectedChainKey]);
25198
25189
  const isSourceSupported = sourceValidation?.isSupported ?? null;
25199
- const isAnyLoading = tokensLoading || isCheckingSourceToken;
25190
+ const isAnyLoading = tokensLoading || isCheckingSourceToken || destinationTokens.length > 0 && !initialSelectionDone;
25200
25191
  const withdrawPoweredByFooter = /* @__PURE__ */ jsx57("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx57(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
25201
25192
  return /* @__PURE__ */ jsx57(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ jsx57(Dialog2, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ jsx57(
25202
25193
  DialogContent2,
@@ -25609,6 +25600,10 @@ function UnifoldProvider2({
25609
25600
  sourceTokenAddress: withdrawConfig.sourceTokenAddress,
25610
25601
  sourceTokenSymbol: withdrawConfig.sourceTokenSymbol,
25611
25602
  recipientAddress: withdrawConfig.recipientAddress,
25603
+ defaultDestinationChainType: withdrawConfig.defaultDestinationChainType,
25604
+ defaultDestinationChainId: withdrawConfig.defaultDestinationChainId,
25605
+ defaultDestinationTokenAddress: withdrawConfig.defaultDestinationTokenAddress,
25606
+ defaultDestinationSymbol: withdrawConfig.defaultDestinationSymbol,
25612
25607
  senderAddress: withdrawConfig.senderAddress,
25613
25608
  onWithdraw: withdrawConfig.withdraw,
25614
25609
  onWithdrawSuccess: handleWithdrawSuccess,
@@ -25707,6 +25702,7 @@ export {
25707
25702
  getApiBaseUrl,
25708
25703
  getChainName,
25709
25704
  getDefaultOnrampToken,
25705
+ getDepositQuote,
25710
25706
  getFiatCurrencies,
25711
25707
  getIconUrl,
25712
25708
  getIconUrlWithCdn,
@@ -25720,9 +25716,11 @@ export {
25720
25716
  getWalletByChainType,
25721
25717
  i18n,
25722
25718
  queryExecutions,
25719
+ retrievePaymentIntent,
25723
25720
  sendSolanaTransaction,
25724
25721
  setApiConfig,
25725
25722
  useAllowedCountry2 as useAllowedCountry,
25723
+ useSupportedDepositTokens,
25726
25724
  useUnifold2 as useUnifold,
25727
25725
  useUserIp
25728
25726
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifold/connect-react",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
4
4
  "description": "Unifold Connect React - Complete React SDK with UI components for crypto deposits",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -26,9 +26,9 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@tanstack/react-query": "^5.90.11",
29
- "@unifold/core": "0.1.48",
30
- "@unifold/react-provider": "0.1.48",
31
- "@unifold/ui-react": "0.1.48"
29
+ "@unifold/core": "0.1.50",
30
+ "@unifold/react-provider": "0.1.50",
31
+ "@unifold/ui-react": "0.1.50"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/react": "^19.0.0",