@unifold/connect-react 0.1.52 → 0.1.53

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.
Files changed (3) hide show
  1. package/dist/index.js +157 -69
  2. package/dist/index.mjs +157 -69
  3. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -6271,13 +6271,18 @@ async function getSupportedDepositTokens(publishableKey, options) {
6271
6271
  const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6272
6272
  validatePublishableKey(pk);
6273
6273
  let url = `${API_BASE_URL}/v1/public/tokens/supported_deposit_tokens`;
6274
+ const params = new URLSearchParams();
6274
6275
  if (options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type) {
6275
- const params = new URLSearchParams({
6276
- destination_token_address: options.destination_token_address,
6277
- destination_chain_id: options.destination_chain_id,
6278
- destination_chain_type: options.destination_chain_type
6279
- });
6280
- url = `${url}?${params.toString()}`;
6276
+ params.set("destination_token_address", options.destination_token_address);
6277
+ params.set("destination_chain_id", options.destination_chain_id);
6278
+ params.set("destination_chain_type", options.destination_chain_type);
6279
+ }
6280
+ if (options?.product_type) {
6281
+ params.set("product_type", options.product_type);
6282
+ }
6283
+ const qs = params.toString();
6284
+ if (qs) {
6285
+ url = `${url}?${qs}`;
6281
6286
  }
6282
6287
  const response = await fetch(url, {
6283
6288
  method: "GET",
@@ -11088,6 +11093,7 @@ var Separator = SelectSeparator;
11088
11093
  var import_jsx_runtime59 = require("react/jsx-runtime");
11089
11094
  var import_jsx_runtime60 = require("react/jsx-runtime");
11090
11095
  var React262 = __toESM(require("react"), 1);
11096
+ var import_react_query11 = require("@tanstack/react-query");
11091
11097
  var import_jsx_runtime61 = require("react/jsx-runtime");
11092
11098
  var import_jsx_runtime62 = require("react/jsx-runtime");
11093
11099
  var import_jsx_runtime63 = require("react/jsx-runtime");
@@ -11099,7 +11105,6 @@ var React272 = __toESM(require("react"), 1);
11099
11105
  var import_jsx_runtime67 = require("react/jsx-runtime");
11100
11106
  var import_jsx_runtime68 = require("react/jsx-runtime");
11101
11107
  var import_react26 = require("react");
11102
- var import_react_query11 = require("@tanstack/react-query");
11103
11108
  var import_react_query12 = require("@tanstack/react-query");
11104
11109
  var import_jsx_runtime69 = require("react/jsx-runtime");
11105
11110
  var import_react27 = require("react");
@@ -13516,14 +13521,14 @@ function BuyWithCard({
13516
13521
  );
13517
13522
  if (matchingCurrency) {
13518
13523
  setCurrency(matchingCurrency.currency_code.toLowerCase());
13519
- if (!amount && !hasManualAmountEntry) {
13524
+ if (!amount && !hasManualAmountEntry && matchingCurrency.default_amount != null) {
13520
13525
  setAmount(matchingCurrency.default_amount.toString());
13521
13526
  }
13522
13527
  } else if (!amount && !hasManualAmountEntry) {
13523
13528
  const usdCurrency = fiatCurrencies.find(
13524
13529
  (c) => c.currency_code.toLowerCase() === "usd"
13525
13530
  );
13526
- if (usdCurrency) {
13531
+ if (usdCurrency?.default_amount != null) {
13527
13532
  setAmount(usdCurrency.default_amount.toString());
13528
13533
  }
13529
13534
  }
@@ -13541,7 +13546,7 @@ function BuyWithCard({
13541
13546
  const currentCurrency = fiatCurrencies.find(
13542
13547
  (c) => c.currency_code.toLowerCase() === currency.toLowerCase()
13543
13548
  );
13544
- if (currentCurrency) {
13549
+ if (currentCurrency?.default_amount != null) {
13545
13550
  setAmount(currentCurrency.default_amount.toString());
13546
13551
  }
13547
13552
  }
@@ -17866,11 +17871,16 @@ function useAddressValidation({
17866
17871
  };
17867
17872
  }
17868
17873
  function useSupportedDepositTokens(publishableKey, options) {
17869
- const filteredOptions = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type ? {
17870
- destination_token_address: options.destination_token_address,
17871
- destination_chain_id: options.destination_chain_id,
17872
- destination_chain_type: options.destination_chain_type
17873
- } : void 0;
17874
+ const hasDestination = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type;
17875
+ const filteredOptions = {
17876
+ ...hasDestination ? {
17877
+ destination_token_address: options.destination_token_address,
17878
+ destination_chain_id: options.destination_chain_id,
17879
+ destination_chain_type: options.destination_chain_type
17880
+ } : {},
17881
+ ...options?.product_type ? { product_type: options.product_type } : {}
17882
+ };
17883
+ const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
17874
17884
  return (0, import_react_query10.useQuery)({
17875
17885
  queryKey: [
17876
17886
  "unifold",
@@ -17878,9 +17888,13 @@ function useSupportedDepositTokens(publishableKey, options) {
17878
17888
  publishableKey,
17879
17889
  filteredOptions?.destination_token_address ?? null,
17880
17890
  filteredOptions?.destination_chain_id ?? null,
17881
- filteredOptions?.destination_chain_type ?? null
17891
+ filteredOptions?.destination_chain_type ?? null,
17892
+ filteredOptions?.product_type ?? null
17882
17893
  ],
17883
- queryFn: () => getSupportedDepositTokens(publishableKey, filteredOptions),
17894
+ queryFn: () => getSupportedDepositTokens(
17895
+ publishableKey,
17896
+ hasFilteredOptions ? filteredOptions : void 0
17897
+ ),
17884
17898
  staleTime: 1e3 * 60 * 5,
17885
17899
  // 5 minutes — token list rarely changes
17886
17900
  gcTime: 1e3 * 60 * 30,
@@ -19079,7 +19093,8 @@ function TransferCryptoSingleInput({
19079
19093
  onDepositError,
19080
19094
  wallets: externalWallets,
19081
19095
  onSourceTokenChange,
19082
- checkoutQuote
19096
+ checkoutQuote,
19097
+ productType
19083
19098
  }) {
19084
19099
  const { themeClass, colors: colors2, fonts, components } = useTheme();
19085
19100
  const isDarkMode = themeClass.includes("uf-dark");
@@ -19092,7 +19107,8 @@ function TransferCryptoSingleInput({
19092
19107
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
19093
19108
  destination_token_address: destinationTokenAddress,
19094
19109
  destination_chain_id: destinationChainId,
19095
- destination_chain_type: destinationChainType
19110
+ destination_chain_type: destinationChainType,
19111
+ product_type: productType
19096
19112
  });
19097
19113
  const supportedTokens = tokensResponse?.data ?? [];
19098
19114
  const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
@@ -20127,6 +20143,54 @@ function TransferCryptoDoubleInput({
20127
20143
  }
20128
20144
  ) });
20129
20145
  }
20146
+ function useDepositQuote(params) {
20147
+ const {
20148
+ publishableKey,
20149
+ sourceChainType,
20150
+ sourceChainId,
20151
+ sourceTokenAddress,
20152
+ destinationAmount,
20153
+ destinationChainType,
20154
+ destinationChainId,
20155
+ destinationTokenAddress,
20156
+ adjustForSlippage,
20157
+ enabled = true
20158
+ } = params;
20159
+ const request = {
20160
+ source_chain_type: sourceChainType,
20161
+ source_chain_id: sourceChainId,
20162
+ source_token_address: sourceTokenAddress,
20163
+ destination_amount: destinationAmount,
20164
+ destination_chain_type: destinationChainType,
20165
+ destination_chain_id: destinationChainId,
20166
+ destination_token_address: destinationTokenAddress,
20167
+ ...adjustForSlippage ? { adjust_for_slippage: true } : {}
20168
+ };
20169
+ return (0, import_react_query11.useQuery)({
20170
+ queryKey: [
20171
+ "unifold",
20172
+ "depositQuote",
20173
+ sourceChainType,
20174
+ sourceChainId,
20175
+ sourceTokenAddress,
20176
+ destinationAmount,
20177
+ destinationChainType,
20178
+ destinationChainId,
20179
+ destinationTokenAddress,
20180
+ adjustForSlippage,
20181
+ publishableKey
20182
+ ],
20183
+ queryFn: () => getDepositQuote(request, publishableKey),
20184
+ enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
20185
+ staleTime: 3e4,
20186
+ gcTime: 5 * 6e4,
20187
+ refetchInterval: 3e4,
20188
+ refetchIntervalInBackground: false,
20189
+ refetchOnWindowFocus: true,
20190
+ retry: 2,
20191
+ retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
20192
+ });
20193
+ }
20130
20194
  var BROWSER_WALLET_STEP_MIN_HEIGHT_CLASS = "uf-min-h-[460px]";
20131
20195
  var WALLET_ICONS = {
20132
20196
  metamask: MetamaskIcon,
@@ -20602,7 +20666,7 @@ function EnterAmountView({
20602
20666
  }
20603
20667
  )
20604
20668
  ] }) }),
20605
- tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && inputUsdNum > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
20669
+ tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && tokenChainDetails.minimum_deposit_amount_usd > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
20606
20670
  "div",
20607
20671
  {
20608
20672
  className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
@@ -21204,7 +21268,11 @@ function BrowserWalletModal({
21204
21268
  checkoutReceivedUsd,
21205
21269
  onNewDeposit,
21206
21270
  onDone,
21207
- paymentIntentStatus
21271
+ paymentIntentStatus,
21272
+ checkoutQuote,
21273
+ checkoutDestination,
21274
+ checkoutRemainingBaseUnits,
21275
+ productType
21208
21276
  }) {
21209
21277
  const { colors: colors2, fonts, components } = useTheme();
21210
21278
  const [step, setStep] = React262.useState("select-token");
@@ -21226,7 +21294,49 @@ function BrowserWalletModal({
21226
21294
  const themeClass = theme === "dark" ? "uf-dark" : "";
21227
21295
  const chainType = depositWallet.chain_type;
21228
21296
  const recipientAddress = depositWallet.address;
21297
+ const isCheckoutMode = !!checkoutAmountUsd;
21229
21298
  const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
21299
+ const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
21300
+ const effectiveDestinationAmount = React262.useMemo(() => {
21301
+ if (!checkoutRemainingBaseUnits || checkoutRemainingBaseUnits === "0") return "0";
21302
+ if (!checkoutAmountUsd) return checkoutRemainingBaseUnits;
21303
+ const remaining = BigInt(checkoutRemainingBaseUnits);
21304
+ const minUsd = Math.max(tokenChainDetails?.minimum_deposit_amount_usd ?? 0, 3);
21305
+ const totalUsd = parseFloat(checkoutAmountUsd);
21306
+ if (totalUsd <= 0) return remaining > 0n ? remaining.toString() : "0";
21307
+ const receivedUsd = parseFloat(checkoutReceivedUsd ?? "0");
21308
+ const remainingUsd = totalUsd - receivedUsd;
21309
+ if (remainingUsd <= 0) return "0";
21310
+ const baseUnitsPerUsd = Number(remaining) / remainingUsd;
21311
+ const minBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
21312
+ const effective = remaining > minBaseUnits ? remaining : minBaseUnits;
21313
+ return effective > 0n ? effective.toString() : "0";
21314
+ }, [checkoutRemainingBaseUnits, checkoutAmountUsd, checkoutReceivedUsd, tokenChainDetails]);
21315
+ const { data: walletCheckoutQuote } = useDepositQuote({
21316
+ publishableKey,
21317
+ sourceChainType: selectedToken?.chain_type ?? "",
21318
+ sourceChainId: selectedToken?.chain_id ?? "",
21319
+ sourceTokenAddress: selectedToken?.token_address ?? "",
21320
+ destinationAmount: effectiveDestinationAmount,
21321
+ destinationChainType: checkoutDestination?.chainType ?? "",
21322
+ destinationChainId: checkoutDestination?.chainId ?? "",
21323
+ destinationTokenAddress: checkoutDestination?.tokenAddress ?? "",
21324
+ adjustForSlippage: true,
21325
+ enabled: open && isCheckoutMode && !!selectedToken && !!checkoutDestination && effectiveDestinationAmount !== "0"
21326
+ });
21327
+ const activeCheckoutQuote = React262.useMemo(() => {
21328
+ if (!isCheckoutMode) return null;
21329
+ if (walletCheckoutQuote) {
21330
+ return {
21331
+ sourceAmount: walletCheckoutQuote.source_amount,
21332
+ sourceTokenDecimals: walletCheckoutQuote.source_token_decimals,
21333
+ sourceTokenSymbol: walletCheckoutQuote.source_token_symbol,
21334
+ sourceAmountUsd: walletCheckoutQuote.source_amount_usd,
21335
+ slippageBufferPercent: walletCheckoutQuote.slippage_buffer_percent ?? null
21336
+ };
21337
+ }
21338
+ return checkoutQuote ?? null;
21339
+ }, [isCheckoutMode, walletCheckoutQuote, checkoutQuote]);
21230
21340
  const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
21231
21341
  userId,
21232
21342
  publishableKey,
@@ -21278,7 +21388,8 @@ function BrowserWalletModal({
21278
21388
  const options = {
21279
21389
  destination_token_address: depositWallet.destination_token_address,
21280
21390
  destination_chain_id: depositWallet.destination_chain_id,
21281
- destination_chain_type: depositWallet.destination_chain_type
21391
+ destination_chain_type: depositWallet.destination_chain_type,
21392
+ ...productType ? { product_type: productType } : {}
21282
21393
  };
21283
21394
  const response = await getSupportedDepositTokens(
21284
21395
  publishableKey,
@@ -21680,7 +21791,6 @@ function BrowserWalletModal({
21680
21791
  throw error2;
21681
21792
  }
21682
21793
  };
21683
- const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
21684
21794
  const usdToTokenRate = React262.useMemo(() => {
21685
21795
  if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken)
21686
21796
  return 0;
@@ -21690,15 +21800,24 @@ function BrowserWalletModal({
21690
21800
  return balanceAmount / balanceUsd;
21691
21801
  }, [selectedBalance, selectedToken]);
21692
21802
  const tokenAmount = React262.useMemo(() => {
21803
+ if (isCheckoutMode && activeCheckoutQuote && selectedToken) {
21804
+ return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
21805
+ }
21693
21806
  const usdNum = parseFloat(amountUsd) || 0;
21694
21807
  if (usdNum === 0 || usdToTokenRate === 0) return 0;
21695
21808
  return usdNum * usdToTokenRate;
21696
- }, [amountUsd, usdToTokenRate]);
21809
+ }, [amountUsd, usdToTokenRate, isCheckoutMode, activeCheckoutQuote, selectedToken]);
21810
+ React262.useEffect(() => {
21811
+ if (isCheckoutMode && activeCheckoutQuote?.sourceAmountUsd && step === "input-amount") {
21812
+ const quoteUsd = activeCheckoutQuote.sourceAmountUsd;
21813
+ setAmountUsd(quoteUsd);
21814
+ }
21815
+ }, [isCheckoutMode, activeCheckoutQuote, step]);
21697
21816
  const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
21698
21817
  const maxUsdAmount = selectedBalance?.amount_usd ? parseFloat(selectedBalance.amount_usd) : 0;
21699
21818
  const inputUsdNum = parseFloat(amountUsd) || 0;
21700
21819
  const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
21701
- const isValidAmount = inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
21820
+ const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
21702
21821
  const formattedTokenAmount = React262.useMemo(() => {
21703
21822
  if (tokenAmount === 0 || !selectedToken) return null;
21704
21823
  return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(
@@ -23138,7 +23257,7 @@ function usePaymentIntent(params) {
23138
23257
  enabled = true,
23139
23258
  pollingInterval = 3e3
23140
23259
  } = params;
23141
- return (0, import_react_query11.useQuery)({
23260
+ return (0, import_react_query12.useQuery)({
23142
23261
  queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
23143
23262
  queryFn: () => retrievePaymentIntent(clientSecret, publishableKey),
23144
23263
  enabled: enabled && !!clientSecret && !!publishableKey,
@@ -23154,49 +23273,6 @@ function usePaymentIntent(params) {
23154
23273
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
23155
23274
  });
23156
23275
  }
23157
- function useDepositQuote(params) {
23158
- const {
23159
- publishableKey,
23160
- sourceChainType,
23161
- sourceChainId,
23162
- sourceTokenAddress,
23163
- destinationAmount,
23164
- destinationChainType,
23165
- destinationChainId,
23166
- destinationTokenAddress,
23167
- enabled = true
23168
- } = params;
23169
- const request = {
23170
- source_chain_type: sourceChainType,
23171
- source_chain_id: sourceChainId,
23172
- source_token_address: sourceTokenAddress,
23173
- destination_amount: destinationAmount,
23174
- destination_chain_type: destinationChainType,
23175
- destination_chain_id: destinationChainId,
23176
- destination_token_address: destinationTokenAddress
23177
- };
23178
- return (0, import_react_query12.useQuery)({
23179
- queryKey: [
23180
- "unifold",
23181
- "depositQuote",
23182
- sourceChainType,
23183
- sourceChainId,
23184
- sourceTokenAddress,
23185
- destinationAmount,
23186
- destinationChainType,
23187
- destinationChainId,
23188
- destinationTokenAddress,
23189
- publishableKey
23190
- ],
23191
- queryFn: () => getDepositQuote(request, publishableKey),
23192
- enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
23193
- staleTime: 6e4,
23194
- gcTime: 5 * 6e4,
23195
- refetchOnWindowFocus: false,
23196
- retry: 2,
23197
- retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
23198
- });
23199
- }
23200
23276
  function mapDepositAddressesToWallets(depositAddresses, pi) {
23201
23277
  return depositAddresses.map((da, idx) => ({
23202
23278
  id: da.id,
@@ -23346,6 +23422,7 @@ function CheckoutModal({
23346
23422
  destinationChainType: paymentIntent?.destination_chain_type ?? "",
23347
23423
  destinationChainId: paymentIntent?.destination_chain_id ?? "",
23348
23424
  destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
23425
+ adjustForSlippage: true,
23349
23426
  enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
23350
23427
  });
23351
23428
  const handleBrowserWalletClick = (0, import_react26.useCallback)(
@@ -23737,6 +23814,7 @@ function CheckoutModal({
23737
23814
  depositConfirmationMode: "auto_ui",
23738
23815
  wallets,
23739
23816
  onSourceTokenChange: setSelectedSource,
23817
+ productType: "payment",
23740
23818
  checkoutQuote: sourceQuote ? {
23741
23819
  sourceAmount: sourceQuote.source_amount,
23742
23820
  sourceTokenDecimals: sourceQuote.source_token_decimals,
@@ -23776,6 +23854,16 @@ function CheckoutModal({
23776
23854
  prefillAmountUsd: remainingAmountUsd,
23777
23855
  checkoutAmountUsd: paymentIntent?.amount_usd,
23778
23856
  checkoutReceivedUsd: paymentIntent?.amount_received_usd,
23857
+ checkoutDestination: paymentIntent ? {
23858
+ chainType: paymentIntent.destination_chain_type,
23859
+ chainId: paymentIntent.destination_chain_id,
23860
+ tokenAddress: paymentIntent.destination_token_address
23861
+ } : void 0,
23862
+ productType: "payment",
23863
+ checkoutRemainingBaseUnits: paymentIntent ? (() => {
23864
+ const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
23865
+ return remaining > 0n ? remaining.toString() : "0";
23866
+ })() : void 0,
23779
23867
  onSuccess: (txHash) => {
23780
23868
  onCheckoutSuccess?.({
23781
23869
  paymentIntentId: paymentIntent?.id || "",
package/dist/index.mjs CHANGED
@@ -6244,13 +6244,18 @@ async function getSupportedDepositTokens(publishableKey, options) {
6244
6244
  const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
6245
6245
  validatePublishableKey(pk);
6246
6246
  let url = `${API_BASE_URL}/v1/public/tokens/supported_deposit_tokens`;
6247
+ const params = new URLSearchParams();
6247
6248
  if (options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type) {
6248
- const params = new URLSearchParams({
6249
- destination_token_address: options.destination_token_address,
6250
- destination_chain_id: options.destination_chain_id,
6251
- destination_chain_type: options.destination_chain_type
6252
- });
6253
- url = `${url}?${params.toString()}`;
6249
+ params.set("destination_token_address", options.destination_token_address);
6250
+ params.set("destination_chain_id", options.destination_chain_id);
6251
+ params.set("destination_chain_type", options.destination_chain_type);
6252
+ }
6253
+ if (options?.product_type) {
6254
+ params.set("product_type", options.product_type);
6255
+ }
6256
+ const qs = params.toString();
6257
+ if (qs) {
6258
+ url = `${url}?${qs}`;
6254
6259
  }
6255
6260
  const response = await fetch(url, {
6256
6261
  method: "GET",
@@ -11061,6 +11066,7 @@ var Separator = SelectSeparator;
11061
11066
  import { jsx as jsx422, jsxs as jsxs36 } from "react/jsx-runtime";
11062
11067
  import { jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
11063
11068
  import * as React262 from "react";
11069
+ import { useQuery as useQuery9 } from "@tanstack/react-query";
11064
11070
  import { jsx as jsx44 } from "react/jsx-runtime";
11065
11071
  import { jsx as jsx45, jsxs as jsxs38 } from "react/jsx-runtime";
11066
11072
  import { Fragment as Fragment52, jsx as jsx46, jsxs as jsxs39 } from "react/jsx-runtime";
@@ -11079,7 +11085,6 @@ import {
11079
11085
  useRef as useRef82,
11080
11086
  useMemo as useMemo102
11081
11087
  } from "react";
11082
- import { useQuery as useQuery9 } from "@tanstack/react-query";
11083
11088
  import { useQuery as useQuery10 } from "@tanstack/react-query";
11084
11089
  import { Fragment as Fragment10, jsx as jsx522, jsxs as jsxs45 } from "react/jsx-runtime";
11085
11090
  import {
@@ -13502,14 +13507,14 @@ function BuyWithCard({
13502
13507
  );
13503
13508
  if (matchingCurrency) {
13504
13509
  setCurrency(matchingCurrency.currency_code.toLowerCase());
13505
- if (!amount && !hasManualAmountEntry) {
13510
+ if (!amount && !hasManualAmountEntry && matchingCurrency.default_amount != null) {
13506
13511
  setAmount(matchingCurrency.default_amount.toString());
13507
13512
  }
13508
13513
  } else if (!amount && !hasManualAmountEntry) {
13509
13514
  const usdCurrency = fiatCurrencies.find(
13510
13515
  (c) => c.currency_code.toLowerCase() === "usd"
13511
13516
  );
13512
- if (usdCurrency) {
13517
+ if (usdCurrency?.default_amount != null) {
13513
13518
  setAmount(usdCurrency.default_amount.toString());
13514
13519
  }
13515
13520
  }
@@ -13527,7 +13532,7 @@ function BuyWithCard({
13527
13532
  const currentCurrency = fiatCurrencies.find(
13528
13533
  (c) => c.currency_code.toLowerCase() === currency.toLowerCase()
13529
13534
  );
13530
- if (currentCurrency) {
13535
+ if (currentCurrency?.default_amount != null) {
13531
13536
  setAmount(currentCurrency.default_amount.toString());
13532
13537
  }
13533
13538
  }
@@ -17852,11 +17857,16 @@ function useAddressValidation({
17852
17857
  };
17853
17858
  }
17854
17859
  function useSupportedDepositTokens(publishableKey, options) {
17855
- const filteredOptions = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type ? {
17856
- destination_token_address: options.destination_token_address,
17857
- destination_chain_id: options.destination_chain_id,
17858
- destination_chain_type: options.destination_chain_type
17859
- } : void 0;
17860
+ const hasDestination = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type;
17861
+ const filteredOptions = {
17862
+ ...hasDestination ? {
17863
+ destination_token_address: options.destination_token_address,
17864
+ destination_chain_id: options.destination_chain_id,
17865
+ destination_chain_type: options.destination_chain_type
17866
+ } : {},
17867
+ ...options?.product_type ? { product_type: options.product_type } : {}
17868
+ };
17869
+ const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
17860
17870
  return useQuery8({
17861
17871
  queryKey: [
17862
17872
  "unifold",
@@ -17864,9 +17874,13 @@ function useSupportedDepositTokens(publishableKey, options) {
17864
17874
  publishableKey,
17865
17875
  filteredOptions?.destination_token_address ?? null,
17866
17876
  filteredOptions?.destination_chain_id ?? null,
17867
- filteredOptions?.destination_chain_type ?? null
17877
+ filteredOptions?.destination_chain_type ?? null,
17878
+ filteredOptions?.product_type ?? null
17868
17879
  ],
17869
- queryFn: () => getSupportedDepositTokens(publishableKey, filteredOptions),
17880
+ queryFn: () => getSupportedDepositTokens(
17881
+ publishableKey,
17882
+ hasFilteredOptions ? filteredOptions : void 0
17883
+ ),
17870
17884
  staleTime: 1e3 * 60 * 5,
17871
17885
  // 5 minutes — token list rarely changes
17872
17886
  gcTime: 1e3 * 60 * 30,
@@ -19065,7 +19079,8 @@ function TransferCryptoSingleInput({
19065
19079
  onDepositError,
19066
19080
  wallets: externalWallets,
19067
19081
  onSourceTokenChange,
19068
- checkoutQuote
19082
+ checkoutQuote,
19083
+ productType
19069
19084
  }) {
19070
19085
  const { themeClass, colors: colors2, fonts, components } = useTheme();
19071
19086
  const isDarkMode = themeClass.includes("uf-dark");
@@ -19078,7 +19093,8 @@ function TransferCryptoSingleInput({
19078
19093
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
19079
19094
  destination_token_address: destinationTokenAddress,
19080
19095
  destination_chain_id: destinationChainId,
19081
- destination_chain_type: destinationChainType
19096
+ destination_chain_type: destinationChainType,
19097
+ product_type: productType
19082
19098
  });
19083
19099
  const supportedTokens = tokensResponse?.data ?? [];
19084
19100
  const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
@@ -20113,6 +20129,54 @@ function TransferCryptoDoubleInput({
20113
20129
  }
20114
20130
  ) });
20115
20131
  }
20132
+ function useDepositQuote(params) {
20133
+ const {
20134
+ publishableKey,
20135
+ sourceChainType,
20136
+ sourceChainId,
20137
+ sourceTokenAddress,
20138
+ destinationAmount,
20139
+ destinationChainType,
20140
+ destinationChainId,
20141
+ destinationTokenAddress,
20142
+ adjustForSlippage,
20143
+ enabled = true
20144
+ } = params;
20145
+ const request = {
20146
+ source_chain_type: sourceChainType,
20147
+ source_chain_id: sourceChainId,
20148
+ source_token_address: sourceTokenAddress,
20149
+ destination_amount: destinationAmount,
20150
+ destination_chain_type: destinationChainType,
20151
+ destination_chain_id: destinationChainId,
20152
+ destination_token_address: destinationTokenAddress,
20153
+ ...adjustForSlippage ? { adjust_for_slippage: true } : {}
20154
+ };
20155
+ return useQuery9({
20156
+ queryKey: [
20157
+ "unifold",
20158
+ "depositQuote",
20159
+ sourceChainType,
20160
+ sourceChainId,
20161
+ sourceTokenAddress,
20162
+ destinationAmount,
20163
+ destinationChainType,
20164
+ destinationChainId,
20165
+ destinationTokenAddress,
20166
+ adjustForSlippage,
20167
+ publishableKey
20168
+ ],
20169
+ queryFn: () => getDepositQuote(request, publishableKey),
20170
+ enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
20171
+ staleTime: 3e4,
20172
+ gcTime: 5 * 6e4,
20173
+ refetchInterval: 3e4,
20174
+ refetchIntervalInBackground: false,
20175
+ refetchOnWindowFocus: true,
20176
+ retry: 2,
20177
+ retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
20178
+ });
20179
+ }
20116
20180
  var BROWSER_WALLET_STEP_MIN_HEIGHT_CLASS = "uf-min-h-[460px]";
20117
20181
  var WALLET_ICONS = {
20118
20182
  metamask: MetamaskIcon,
@@ -20588,7 +20652,7 @@ function EnterAmountView({
20588
20652
  }
20589
20653
  )
20590
20654
  ] }) }),
20591
- tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && inputUsdNum > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ jsxs39(
20655
+ tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && tokenChainDetails.minimum_deposit_amount_usd > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ jsxs39(
20592
20656
  "div",
20593
20657
  {
20594
20658
  className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
@@ -21190,7 +21254,11 @@ function BrowserWalletModal({
21190
21254
  checkoutReceivedUsd,
21191
21255
  onNewDeposit,
21192
21256
  onDone,
21193
- paymentIntentStatus
21257
+ paymentIntentStatus,
21258
+ checkoutQuote,
21259
+ checkoutDestination,
21260
+ checkoutRemainingBaseUnits,
21261
+ productType
21194
21262
  }) {
21195
21263
  const { colors: colors2, fonts, components } = useTheme();
21196
21264
  const [step, setStep] = React262.useState("select-token");
@@ -21212,7 +21280,49 @@ function BrowserWalletModal({
21212
21280
  const themeClass = theme === "dark" ? "uf-dark" : "";
21213
21281
  const chainType = depositWallet.chain_type;
21214
21282
  const recipientAddress = depositWallet.address;
21283
+ const isCheckoutMode = !!checkoutAmountUsd;
21215
21284
  const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
21285
+ const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
21286
+ const effectiveDestinationAmount = React262.useMemo(() => {
21287
+ if (!checkoutRemainingBaseUnits || checkoutRemainingBaseUnits === "0") return "0";
21288
+ if (!checkoutAmountUsd) return checkoutRemainingBaseUnits;
21289
+ const remaining = BigInt(checkoutRemainingBaseUnits);
21290
+ const minUsd = Math.max(tokenChainDetails?.minimum_deposit_amount_usd ?? 0, 3);
21291
+ const totalUsd = parseFloat(checkoutAmountUsd);
21292
+ if (totalUsd <= 0) return remaining > 0n ? remaining.toString() : "0";
21293
+ const receivedUsd = parseFloat(checkoutReceivedUsd ?? "0");
21294
+ const remainingUsd = totalUsd - receivedUsd;
21295
+ if (remainingUsd <= 0) return "0";
21296
+ const baseUnitsPerUsd = Number(remaining) / remainingUsd;
21297
+ const minBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
21298
+ const effective = remaining > minBaseUnits ? remaining : minBaseUnits;
21299
+ return effective > 0n ? effective.toString() : "0";
21300
+ }, [checkoutRemainingBaseUnits, checkoutAmountUsd, checkoutReceivedUsd, tokenChainDetails]);
21301
+ const { data: walletCheckoutQuote } = useDepositQuote({
21302
+ publishableKey,
21303
+ sourceChainType: selectedToken?.chain_type ?? "",
21304
+ sourceChainId: selectedToken?.chain_id ?? "",
21305
+ sourceTokenAddress: selectedToken?.token_address ?? "",
21306
+ destinationAmount: effectiveDestinationAmount,
21307
+ destinationChainType: checkoutDestination?.chainType ?? "",
21308
+ destinationChainId: checkoutDestination?.chainId ?? "",
21309
+ destinationTokenAddress: checkoutDestination?.tokenAddress ?? "",
21310
+ adjustForSlippage: true,
21311
+ enabled: open && isCheckoutMode && !!selectedToken && !!checkoutDestination && effectiveDestinationAmount !== "0"
21312
+ });
21313
+ const activeCheckoutQuote = React262.useMemo(() => {
21314
+ if (!isCheckoutMode) return null;
21315
+ if (walletCheckoutQuote) {
21316
+ return {
21317
+ sourceAmount: walletCheckoutQuote.source_amount,
21318
+ sourceTokenDecimals: walletCheckoutQuote.source_token_decimals,
21319
+ sourceTokenSymbol: walletCheckoutQuote.source_token_symbol,
21320
+ sourceAmountUsd: walletCheckoutQuote.source_amount_usd,
21321
+ slippageBufferPercent: walletCheckoutQuote.slippage_buffer_percent ?? null
21322
+ };
21323
+ }
21324
+ return checkoutQuote ?? null;
21325
+ }, [isCheckoutMode, walletCheckoutQuote, checkoutQuote]);
21216
21326
  const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
21217
21327
  userId,
21218
21328
  publishableKey,
@@ -21264,7 +21374,8 @@ function BrowserWalletModal({
21264
21374
  const options = {
21265
21375
  destination_token_address: depositWallet.destination_token_address,
21266
21376
  destination_chain_id: depositWallet.destination_chain_id,
21267
- destination_chain_type: depositWallet.destination_chain_type
21377
+ destination_chain_type: depositWallet.destination_chain_type,
21378
+ ...productType ? { product_type: productType } : {}
21268
21379
  };
21269
21380
  const response = await getSupportedDepositTokens(
21270
21381
  publishableKey,
@@ -21666,7 +21777,6 @@ function BrowserWalletModal({
21666
21777
  throw error2;
21667
21778
  }
21668
21779
  };
21669
- const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
21670
21780
  const usdToTokenRate = React262.useMemo(() => {
21671
21781
  if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken)
21672
21782
  return 0;
@@ -21676,15 +21786,24 @@ function BrowserWalletModal({
21676
21786
  return balanceAmount / balanceUsd;
21677
21787
  }, [selectedBalance, selectedToken]);
21678
21788
  const tokenAmount = React262.useMemo(() => {
21789
+ if (isCheckoutMode && activeCheckoutQuote && selectedToken) {
21790
+ return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
21791
+ }
21679
21792
  const usdNum = parseFloat(amountUsd) || 0;
21680
21793
  if (usdNum === 0 || usdToTokenRate === 0) return 0;
21681
21794
  return usdNum * usdToTokenRate;
21682
- }, [amountUsd, usdToTokenRate]);
21795
+ }, [amountUsd, usdToTokenRate, isCheckoutMode, activeCheckoutQuote, selectedToken]);
21796
+ React262.useEffect(() => {
21797
+ if (isCheckoutMode && activeCheckoutQuote?.sourceAmountUsd && step === "input-amount") {
21798
+ const quoteUsd = activeCheckoutQuote.sourceAmountUsd;
21799
+ setAmountUsd(quoteUsd);
21800
+ }
21801
+ }, [isCheckoutMode, activeCheckoutQuote, step]);
21683
21802
  const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
21684
21803
  const maxUsdAmount = selectedBalance?.amount_usd ? parseFloat(selectedBalance.amount_usd) : 0;
21685
21804
  const inputUsdNum = parseFloat(amountUsd) || 0;
21686
21805
  const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
21687
- const isValidAmount = inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
21806
+ const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
21688
21807
  const formattedTokenAmount = React262.useMemo(() => {
21689
21808
  if (tokenAmount === 0 || !selectedToken) return null;
21690
21809
  return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(
@@ -23124,7 +23243,7 @@ function usePaymentIntent(params) {
23124
23243
  enabled = true,
23125
23244
  pollingInterval = 3e3
23126
23245
  } = params;
23127
- return useQuery9({
23246
+ return useQuery10({
23128
23247
  queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
23129
23248
  queryFn: () => retrievePaymentIntent(clientSecret, publishableKey),
23130
23249
  enabled: enabled && !!clientSecret && !!publishableKey,
@@ -23140,49 +23259,6 @@ function usePaymentIntent(params) {
23140
23259
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
23141
23260
  });
23142
23261
  }
23143
- function useDepositQuote(params) {
23144
- const {
23145
- publishableKey,
23146
- sourceChainType,
23147
- sourceChainId,
23148
- sourceTokenAddress,
23149
- destinationAmount,
23150
- destinationChainType,
23151
- destinationChainId,
23152
- destinationTokenAddress,
23153
- enabled = true
23154
- } = params;
23155
- const request = {
23156
- source_chain_type: sourceChainType,
23157
- source_chain_id: sourceChainId,
23158
- source_token_address: sourceTokenAddress,
23159
- destination_amount: destinationAmount,
23160
- destination_chain_type: destinationChainType,
23161
- destination_chain_id: destinationChainId,
23162
- destination_token_address: destinationTokenAddress
23163
- };
23164
- return useQuery10({
23165
- queryKey: [
23166
- "unifold",
23167
- "depositQuote",
23168
- sourceChainType,
23169
- sourceChainId,
23170
- sourceTokenAddress,
23171
- destinationAmount,
23172
- destinationChainType,
23173
- destinationChainId,
23174
- destinationTokenAddress,
23175
- publishableKey
23176
- ],
23177
- queryFn: () => getDepositQuote(request, publishableKey),
23178
- enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
23179
- staleTime: 6e4,
23180
- gcTime: 5 * 6e4,
23181
- refetchOnWindowFocus: false,
23182
- retry: 2,
23183
- retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
23184
- });
23185
- }
23186
23262
  function mapDepositAddressesToWallets(depositAddresses, pi) {
23187
23263
  return depositAddresses.map((da, idx) => ({
23188
23264
  id: da.id,
@@ -23332,6 +23408,7 @@ function CheckoutModal({
23332
23408
  destinationChainType: paymentIntent?.destination_chain_type ?? "",
23333
23409
  destinationChainId: paymentIntent?.destination_chain_id ?? "",
23334
23410
  destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
23411
+ adjustForSlippage: true,
23335
23412
  enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
23336
23413
  });
23337
23414
  const handleBrowserWalletClick = useCallback52(
@@ -23723,6 +23800,7 @@ function CheckoutModal({
23723
23800
  depositConfirmationMode: "auto_ui",
23724
23801
  wallets,
23725
23802
  onSourceTokenChange: setSelectedSource,
23803
+ productType: "payment",
23726
23804
  checkoutQuote: sourceQuote ? {
23727
23805
  sourceAmount: sourceQuote.source_amount,
23728
23806
  sourceTokenDecimals: sourceQuote.source_token_decimals,
@@ -23762,6 +23840,16 @@ function CheckoutModal({
23762
23840
  prefillAmountUsd: remainingAmountUsd,
23763
23841
  checkoutAmountUsd: paymentIntent?.amount_usd,
23764
23842
  checkoutReceivedUsd: paymentIntent?.amount_received_usd,
23843
+ checkoutDestination: paymentIntent ? {
23844
+ chainType: paymentIntent.destination_chain_type,
23845
+ chainId: paymentIntent.destination_chain_id,
23846
+ tokenAddress: paymentIntent.destination_token_address
23847
+ } : void 0,
23848
+ productType: "payment",
23849
+ checkoutRemainingBaseUnits: paymentIntent ? (() => {
23850
+ const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
23851
+ return remaining > 0n ? remaining.toString() : "0";
23852
+ })() : void 0,
23765
23853
  onSuccess: (txHash) => {
23766
23854
  onCheckoutSuccess?.({
23767
23855
  paymentIntentId: paymentIntent?.id || "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifold/connect-react",
3
- "version": "0.1.52",
3
+ "version": "0.1.53",
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.52",
30
- "@unifold/react-provider": "0.1.52",
31
- "@unifold/ui-react": "0.1.52"
29
+ "@unifold/core": "0.1.53",
30
+ "@unifold/ui-react": "0.1.53",
31
+ "@unifold/react-provider": "0.1.53"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/react": "^19.0.0",