@unifold/ui-web 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 +155 -67
  2. package/dist/index.mjs +155 -67
  3. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -43245,13 +43245,18 @@ async function getSupportedDepositTokens(publishableKey, options2) {
43245
43245
  const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
43246
43246
  validatePublishableKey(pk);
43247
43247
  let url = `${API_BASE_URL}/v1/public/tokens/supported_deposit_tokens`;
43248
+ const params = new URLSearchParams();
43248
43249
  if (options2?.destination_token_address && options2?.destination_chain_id && options2?.destination_chain_type) {
43249
- const params = new URLSearchParams({
43250
- destination_token_address: options2.destination_token_address,
43251
- destination_chain_id: options2.destination_chain_id,
43252
- destination_chain_type: options2.destination_chain_type
43253
- });
43254
- url = `${url}?${params.toString()}`;
43250
+ params.set("destination_token_address", options2.destination_token_address);
43251
+ params.set("destination_chain_id", options2.destination_chain_id);
43252
+ params.set("destination_chain_type", options2.destination_chain_type);
43253
+ }
43254
+ if (options2?.product_type) {
43255
+ params.set("product_type", options2.product_type);
43256
+ }
43257
+ const qs = params.toString();
43258
+ if (qs) {
43259
+ url = `${url}?${qs}`;
43255
43260
  }
43256
43261
  const response = await fetch(url, {
43257
43262
  method: "GET",
@@ -50156,14 +50161,14 @@ function BuyWithCard({
50156
50161
  );
50157
50162
  if (matchingCurrency) {
50158
50163
  setCurrency(matchingCurrency.currency_code.toLowerCase());
50159
- if (!amount && !hasManualAmountEntry) {
50164
+ if (!amount && !hasManualAmountEntry && matchingCurrency.default_amount != null) {
50160
50165
  setAmount(matchingCurrency.default_amount.toString());
50161
50166
  }
50162
50167
  } else if (!amount && !hasManualAmountEntry) {
50163
50168
  const usdCurrency = fiatCurrencies.find(
50164
50169
  (c) => c.currency_code.toLowerCase() === "usd"
50165
50170
  );
50166
- if (usdCurrency) {
50171
+ if (usdCurrency?.default_amount != null) {
50167
50172
  setAmount(usdCurrency.default_amount.toString());
50168
50173
  }
50169
50174
  }
@@ -50181,7 +50186,7 @@ function BuyWithCard({
50181
50186
  const currentCurrency = fiatCurrencies.find(
50182
50187
  (c) => c.currency_code.toLowerCase() === currency.toLowerCase()
50183
50188
  );
50184
- if (currentCurrency) {
50189
+ if (currentCurrency?.default_amount != null) {
50185
50190
  setAmount(currentCurrency.default_amount.toString());
50186
50191
  }
50187
50192
  }
@@ -54506,11 +54511,16 @@ function useAddressValidation({
54506
54511
  };
54507
54512
  }
54508
54513
  function useSupportedDepositTokens(publishableKey, options2) {
54509
- const filteredOptions = options2?.destination_token_address && options2?.destination_chain_id && options2?.destination_chain_type ? {
54510
- destination_token_address: options2.destination_token_address,
54511
- destination_chain_id: options2.destination_chain_id,
54512
- destination_chain_type: options2.destination_chain_type
54513
- } : void 0;
54514
+ const hasDestination = options2?.destination_token_address && options2?.destination_chain_id && options2?.destination_chain_type;
54515
+ const filteredOptions = {
54516
+ ...hasDestination ? {
54517
+ destination_token_address: options2.destination_token_address,
54518
+ destination_chain_id: options2.destination_chain_id,
54519
+ destination_chain_type: options2.destination_chain_type
54520
+ } : {},
54521
+ ...options2?.product_type ? { product_type: options2.product_type } : {}
54522
+ };
54523
+ const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
54514
54524
  return useQuery({
54515
54525
  queryKey: [
54516
54526
  "unifold",
@@ -54518,9 +54528,13 @@ function useSupportedDepositTokens(publishableKey, options2) {
54518
54528
  publishableKey,
54519
54529
  filteredOptions?.destination_token_address ?? null,
54520
54530
  filteredOptions?.destination_chain_id ?? null,
54521
- filteredOptions?.destination_chain_type ?? null
54531
+ filteredOptions?.destination_chain_type ?? null,
54532
+ filteredOptions?.product_type ?? null
54522
54533
  ],
54523
- queryFn: () => getSupportedDepositTokens(publishableKey, filteredOptions),
54534
+ queryFn: () => getSupportedDepositTokens(
54535
+ publishableKey,
54536
+ hasFilteredOptions ? filteredOptions : void 0
54537
+ ),
54524
54538
  staleTime: 1e3 * 60 * 5,
54525
54539
  // 5 minutes — token list rarely changes
54526
54540
  gcTime: 1e3 * 60 * 30,
@@ -55719,7 +55733,8 @@ function TransferCryptoSingleInput({
55719
55733
  onDepositError,
55720
55734
  wallets: externalWallets,
55721
55735
  onSourceTokenChange,
55722
- checkoutQuote
55736
+ checkoutQuote,
55737
+ productType
55723
55738
  }) {
55724
55739
  const { themeClass, colors: colors2, fonts, components } = useTheme();
55725
55740
  const isDarkMode = themeClass.includes("uf-dark");
@@ -55732,7 +55747,8 @@ function TransferCryptoSingleInput({
55732
55747
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
55733
55748
  destination_token_address: destinationTokenAddress,
55734
55749
  destination_chain_id: destinationChainId,
55735
- destination_chain_type: destinationChainType
55750
+ destination_chain_type: destinationChainType,
55751
+ product_type: productType
55736
55752
  });
55737
55753
  const supportedTokens = tokensResponse?.data ?? [];
55738
55754
  const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
@@ -56767,6 +56783,54 @@ function TransferCryptoDoubleInput({
56767
56783
  }
56768
56784
  ) });
56769
56785
  }
56786
+ function useDepositQuote(params) {
56787
+ const {
56788
+ publishableKey,
56789
+ sourceChainType,
56790
+ sourceChainId,
56791
+ sourceTokenAddress,
56792
+ destinationAmount,
56793
+ destinationChainType,
56794
+ destinationChainId,
56795
+ destinationTokenAddress,
56796
+ adjustForSlippage,
56797
+ enabled = true
56798
+ } = params;
56799
+ const request = {
56800
+ source_chain_type: sourceChainType,
56801
+ source_chain_id: sourceChainId,
56802
+ source_token_address: sourceTokenAddress,
56803
+ destination_amount: destinationAmount,
56804
+ destination_chain_type: destinationChainType,
56805
+ destination_chain_id: destinationChainId,
56806
+ destination_token_address: destinationTokenAddress,
56807
+ ...adjustForSlippage ? { adjust_for_slippage: true } : {}
56808
+ };
56809
+ return useQuery({
56810
+ queryKey: [
56811
+ "unifold",
56812
+ "depositQuote",
56813
+ sourceChainType,
56814
+ sourceChainId,
56815
+ sourceTokenAddress,
56816
+ destinationAmount,
56817
+ destinationChainType,
56818
+ destinationChainId,
56819
+ destinationTokenAddress,
56820
+ adjustForSlippage,
56821
+ publishableKey
56822
+ ],
56823
+ queryFn: () => getDepositQuote(request, publishableKey),
56824
+ enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
56825
+ staleTime: 3e4,
56826
+ gcTime: 5 * 6e4,
56827
+ refetchInterval: 3e4,
56828
+ refetchIntervalInBackground: false,
56829
+ refetchOnWindowFocus: true,
56830
+ retry: 2,
56831
+ retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
56832
+ });
56833
+ }
56770
56834
  var BROWSER_WALLET_STEP_MIN_HEIGHT_CLASS = "uf-min-h-[460px]";
56771
56835
  var WALLET_ICONS = {
56772
56836
  metamask: MetamaskIcon,
@@ -57242,7 +57306,7 @@ function EnterAmountView({
57242
57306
  }
57243
57307
  )
57244
57308
  ] }) }),
57245
- tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && inputUsdNum > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
57309
+ 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_runtime65.jsxs)(
57246
57310
  "div",
57247
57311
  {
57248
57312
  className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
@@ -57844,7 +57908,11 @@ function BrowserWalletModal({
57844
57908
  checkoutReceivedUsd,
57845
57909
  onNewDeposit,
57846
57910
  onDone,
57847
- paymentIntentStatus
57911
+ paymentIntentStatus,
57912
+ checkoutQuote,
57913
+ checkoutDestination,
57914
+ checkoutRemainingBaseUnits,
57915
+ productType
57848
57916
  }) {
57849
57917
  const { colors: colors2, fonts, components } = useTheme();
57850
57918
  const [step, setStep] = React262.useState("select-token");
@@ -57866,7 +57934,49 @@ function BrowserWalletModal({
57866
57934
  const themeClass = theme === "dark" ? "uf-dark" : "";
57867
57935
  const chainType = depositWallet.chain_type;
57868
57936
  const recipientAddress = depositWallet.address;
57937
+ const isCheckoutMode = !!checkoutAmountUsd;
57869
57938
  const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
57939
+ const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
57940
+ const effectiveDestinationAmount = React262.useMemo(() => {
57941
+ if (!checkoutRemainingBaseUnits || checkoutRemainingBaseUnits === "0") return "0";
57942
+ if (!checkoutAmountUsd) return checkoutRemainingBaseUnits;
57943
+ const remaining = BigInt(checkoutRemainingBaseUnits);
57944
+ const minUsd = Math.max(tokenChainDetails?.minimum_deposit_amount_usd ?? 0, 3);
57945
+ const totalUsd = parseFloat(checkoutAmountUsd);
57946
+ if (totalUsd <= 0) return remaining > 0n ? remaining.toString() : "0";
57947
+ const receivedUsd = parseFloat(checkoutReceivedUsd ?? "0");
57948
+ const remainingUsd = totalUsd - receivedUsd;
57949
+ if (remainingUsd <= 0) return "0";
57950
+ const baseUnitsPerUsd = Number(remaining) / remainingUsd;
57951
+ const minBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
57952
+ const effective = remaining > minBaseUnits ? remaining : minBaseUnits;
57953
+ return effective > 0n ? effective.toString() : "0";
57954
+ }, [checkoutRemainingBaseUnits, checkoutAmountUsd, checkoutReceivedUsd, tokenChainDetails]);
57955
+ const { data: walletCheckoutQuote } = useDepositQuote({
57956
+ publishableKey,
57957
+ sourceChainType: selectedToken?.chain_type ?? "",
57958
+ sourceChainId: selectedToken?.chain_id ?? "",
57959
+ sourceTokenAddress: selectedToken?.token_address ?? "",
57960
+ destinationAmount: effectiveDestinationAmount,
57961
+ destinationChainType: checkoutDestination?.chainType ?? "",
57962
+ destinationChainId: checkoutDestination?.chainId ?? "",
57963
+ destinationTokenAddress: checkoutDestination?.tokenAddress ?? "",
57964
+ adjustForSlippage: true,
57965
+ enabled: open && isCheckoutMode && !!selectedToken && !!checkoutDestination && effectiveDestinationAmount !== "0"
57966
+ });
57967
+ const activeCheckoutQuote = React262.useMemo(() => {
57968
+ if (!isCheckoutMode) return null;
57969
+ if (walletCheckoutQuote) {
57970
+ return {
57971
+ sourceAmount: walletCheckoutQuote.source_amount,
57972
+ sourceTokenDecimals: walletCheckoutQuote.source_token_decimals,
57973
+ sourceTokenSymbol: walletCheckoutQuote.source_token_symbol,
57974
+ sourceAmountUsd: walletCheckoutQuote.source_amount_usd,
57975
+ slippageBufferPercent: walletCheckoutQuote.slippage_buffer_percent ?? null
57976
+ };
57977
+ }
57978
+ return checkoutQuote ?? null;
57979
+ }, [isCheckoutMode, walletCheckoutQuote, checkoutQuote]);
57870
57980
  const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
57871
57981
  userId,
57872
57982
  publishableKey,
@@ -57918,7 +58028,8 @@ function BrowserWalletModal({
57918
58028
  const options2 = {
57919
58029
  destination_token_address: depositWallet.destination_token_address,
57920
58030
  destination_chain_id: depositWallet.destination_chain_id,
57921
- destination_chain_type: depositWallet.destination_chain_type
58031
+ destination_chain_type: depositWallet.destination_chain_type,
58032
+ ...productType ? { product_type: productType } : {}
57922
58033
  };
57923
58034
  const response = await getSupportedDepositTokens(
57924
58035
  publishableKey,
@@ -58320,7 +58431,6 @@ function BrowserWalletModal({
58320
58431
  throw error2;
58321
58432
  }
58322
58433
  };
58323
- const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
58324
58434
  const usdToTokenRate = React262.useMemo(() => {
58325
58435
  if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken)
58326
58436
  return 0;
@@ -58330,15 +58440,24 @@ function BrowserWalletModal({
58330
58440
  return balanceAmount / balanceUsd;
58331
58441
  }, [selectedBalance, selectedToken]);
58332
58442
  const tokenAmount = React262.useMemo(() => {
58443
+ if (isCheckoutMode && activeCheckoutQuote && selectedToken) {
58444
+ return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
58445
+ }
58333
58446
  const usdNum = parseFloat(amountUsd) || 0;
58334
58447
  if (usdNum === 0 || usdToTokenRate === 0) return 0;
58335
58448
  return usdNum * usdToTokenRate;
58336
- }, [amountUsd, usdToTokenRate]);
58449
+ }, [amountUsd, usdToTokenRate, isCheckoutMode, activeCheckoutQuote, selectedToken]);
58450
+ React262.useEffect(() => {
58451
+ if (isCheckoutMode && activeCheckoutQuote?.sourceAmountUsd && step === "input-amount") {
58452
+ const quoteUsd = activeCheckoutQuote.sourceAmountUsd;
58453
+ setAmountUsd(quoteUsd);
58454
+ }
58455
+ }, [isCheckoutMode, activeCheckoutQuote, step]);
58337
58456
  const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
58338
58457
  const maxUsdAmount = selectedBalance?.amount_usd ? parseFloat(selectedBalance.amount_usd) : 0;
58339
58458
  const inputUsdNum = parseFloat(amountUsd) || 0;
58340
58459
  const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
58341
- const isValidAmount = inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
58460
+ const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
58342
58461
  const formattedTokenAmount = React262.useMemo(() => {
58343
58462
  if (tokenAmount === 0 || !selectedToken) return null;
58344
58463
  return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(
@@ -59794,49 +59913,6 @@ function usePaymentIntent(params) {
59794
59913
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
59795
59914
  });
59796
59915
  }
59797
- function useDepositQuote(params) {
59798
- const {
59799
- publishableKey,
59800
- sourceChainType,
59801
- sourceChainId,
59802
- sourceTokenAddress,
59803
- destinationAmount,
59804
- destinationChainType,
59805
- destinationChainId,
59806
- destinationTokenAddress,
59807
- enabled = true
59808
- } = params;
59809
- const request = {
59810
- source_chain_type: sourceChainType,
59811
- source_chain_id: sourceChainId,
59812
- source_token_address: sourceTokenAddress,
59813
- destination_amount: destinationAmount,
59814
- destination_chain_type: destinationChainType,
59815
- destination_chain_id: destinationChainId,
59816
- destination_token_address: destinationTokenAddress
59817
- };
59818
- return useQuery({
59819
- queryKey: [
59820
- "unifold",
59821
- "depositQuote",
59822
- sourceChainType,
59823
- sourceChainId,
59824
- sourceTokenAddress,
59825
- destinationAmount,
59826
- destinationChainType,
59827
- destinationChainId,
59828
- destinationTokenAddress,
59829
- publishableKey
59830
- ],
59831
- queryFn: () => getDepositQuote(request, publishableKey),
59832
- enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
59833
- staleTime: 6e4,
59834
- gcTime: 5 * 6e4,
59835
- refetchOnWindowFocus: false,
59836
- retry: 2,
59837
- retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
59838
- });
59839
- }
59840
59916
  function mapDepositAddressesToWallets(depositAddresses, pi) {
59841
59917
  return depositAddresses.map((da, idx) => ({
59842
59918
  id: da.id,
@@ -59986,6 +60062,7 @@ function CheckoutModal({
59986
60062
  destinationChainType: paymentIntent?.destination_chain_type ?? "",
59987
60063
  destinationChainId: paymentIntent?.destination_chain_id ?? "",
59988
60064
  destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
60065
+ adjustForSlippage: true,
59989
60066
  enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
59990
60067
  });
59991
60068
  const handleBrowserWalletClick = (0, import_react27.useCallback)(
@@ -60377,6 +60454,7 @@ function CheckoutModal({
60377
60454
  depositConfirmationMode: "auto_ui",
60378
60455
  wallets,
60379
60456
  onSourceTokenChange: setSelectedSource,
60457
+ productType: "payment",
60380
60458
  checkoutQuote: sourceQuote ? {
60381
60459
  sourceAmount: sourceQuote.source_amount,
60382
60460
  sourceTokenDecimals: sourceQuote.source_token_decimals,
@@ -60416,6 +60494,16 @@ function CheckoutModal({
60416
60494
  prefillAmountUsd: remainingAmountUsd,
60417
60495
  checkoutAmountUsd: paymentIntent?.amount_usd,
60418
60496
  checkoutReceivedUsd: paymentIntent?.amount_received_usd,
60497
+ checkoutDestination: paymentIntent ? {
60498
+ chainType: paymentIntent.destination_chain_type,
60499
+ chainId: paymentIntent.destination_chain_id,
60500
+ tokenAddress: paymentIntent.destination_token_address
60501
+ } : void 0,
60502
+ productType: "payment",
60503
+ checkoutRemainingBaseUnits: paymentIntent ? (() => {
60504
+ const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
60505
+ return remaining > 0n ? remaining.toString() : "0";
60506
+ })() : void 0,
60419
60507
  onSuccess: (txHash) => {
60420
60508
  onCheckoutSuccess?.({
60421
60509
  paymentIntentId: paymentIntent?.id || "",
package/dist/index.mjs CHANGED
@@ -43232,13 +43232,18 @@ async function getSupportedDepositTokens(publishableKey, options2) {
43232
43232
  const pk = publishableKey || DEFAULT_PUBLISHABLE_KEY;
43233
43233
  validatePublishableKey(pk);
43234
43234
  let url = `${API_BASE_URL}/v1/public/tokens/supported_deposit_tokens`;
43235
+ const params = new URLSearchParams();
43235
43236
  if (options2?.destination_token_address && options2?.destination_chain_id && options2?.destination_chain_type) {
43236
- const params = new URLSearchParams({
43237
- destination_token_address: options2.destination_token_address,
43238
- destination_chain_id: options2.destination_chain_id,
43239
- destination_chain_type: options2.destination_chain_type
43240
- });
43241
- url = `${url}?${params.toString()}`;
43237
+ params.set("destination_token_address", options2.destination_token_address);
43238
+ params.set("destination_chain_id", options2.destination_chain_id);
43239
+ params.set("destination_chain_type", options2.destination_chain_type);
43240
+ }
43241
+ if (options2?.product_type) {
43242
+ params.set("product_type", options2.product_type);
43243
+ }
43244
+ const qs = params.toString();
43245
+ if (qs) {
43246
+ url = `${url}?${qs}`;
43242
43247
  }
43243
43248
  const response = await fetch(url, {
43244
43249
  method: "GET",
@@ -50143,14 +50148,14 @@ function BuyWithCard({
50143
50148
  );
50144
50149
  if (matchingCurrency) {
50145
50150
  setCurrency(matchingCurrency.currency_code.toLowerCase());
50146
- if (!amount && !hasManualAmountEntry) {
50151
+ if (!amount && !hasManualAmountEntry && matchingCurrency.default_amount != null) {
50147
50152
  setAmount(matchingCurrency.default_amount.toString());
50148
50153
  }
50149
50154
  } else if (!amount && !hasManualAmountEntry) {
50150
50155
  const usdCurrency = fiatCurrencies.find(
50151
50156
  (c) => c.currency_code.toLowerCase() === "usd"
50152
50157
  );
50153
- if (usdCurrency) {
50158
+ if (usdCurrency?.default_amount != null) {
50154
50159
  setAmount(usdCurrency.default_amount.toString());
50155
50160
  }
50156
50161
  }
@@ -50168,7 +50173,7 @@ function BuyWithCard({
50168
50173
  const currentCurrency = fiatCurrencies.find(
50169
50174
  (c) => c.currency_code.toLowerCase() === currency.toLowerCase()
50170
50175
  );
50171
- if (currentCurrency) {
50176
+ if (currentCurrency?.default_amount != null) {
50172
50177
  setAmount(currentCurrency.default_amount.toString());
50173
50178
  }
50174
50179
  }
@@ -54493,11 +54498,16 @@ function useAddressValidation({
54493
54498
  };
54494
54499
  }
54495
54500
  function useSupportedDepositTokens(publishableKey, options2) {
54496
- const filteredOptions = options2?.destination_token_address && options2?.destination_chain_id && options2?.destination_chain_type ? {
54497
- destination_token_address: options2.destination_token_address,
54498
- destination_chain_id: options2.destination_chain_id,
54499
- destination_chain_type: options2.destination_chain_type
54500
- } : void 0;
54501
+ const hasDestination = options2?.destination_token_address && options2?.destination_chain_id && options2?.destination_chain_type;
54502
+ const filteredOptions = {
54503
+ ...hasDestination ? {
54504
+ destination_token_address: options2.destination_token_address,
54505
+ destination_chain_id: options2.destination_chain_id,
54506
+ destination_chain_type: options2.destination_chain_type
54507
+ } : {},
54508
+ ...options2?.product_type ? { product_type: options2.product_type } : {}
54509
+ };
54510
+ const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
54501
54511
  return useQuery({
54502
54512
  queryKey: [
54503
54513
  "unifold",
@@ -54505,9 +54515,13 @@ function useSupportedDepositTokens(publishableKey, options2) {
54505
54515
  publishableKey,
54506
54516
  filteredOptions?.destination_token_address ?? null,
54507
54517
  filteredOptions?.destination_chain_id ?? null,
54508
- filteredOptions?.destination_chain_type ?? null
54518
+ filteredOptions?.destination_chain_type ?? null,
54519
+ filteredOptions?.product_type ?? null
54509
54520
  ],
54510
- queryFn: () => getSupportedDepositTokens(publishableKey, filteredOptions),
54521
+ queryFn: () => getSupportedDepositTokens(
54522
+ publishableKey,
54523
+ hasFilteredOptions ? filteredOptions : void 0
54524
+ ),
54511
54525
  staleTime: 1e3 * 60 * 5,
54512
54526
  // 5 minutes — token list rarely changes
54513
54527
  gcTime: 1e3 * 60 * 30,
@@ -55706,7 +55720,8 @@ function TransferCryptoSingleInput({
55706
55720
  onDepositError,
55707
55721
  wallets: externalWallets,
55708
55722
  onSourceTokenChange,
55709
- checkoutQuote
55723
+ checkoutQuote,
55724
+ productType
55710
55725
  }) {
55711
55726
  const { themeClass, colors: colors2, fonts, components } = useTheme();
55712
55727
  const isDarkMode = themeClass.includes("uf-dark");
@@ -55719,7 +55734,8 @@ function TransferCryptoSingleInput({
55719
55734
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
55720
55735
  destination_token_address: destinationTokenAddress,
55721
55736
  destination_chain_id: destinationChainId,
55722
- destination_chain_type: destinationChainType
55737
+ destination_chain_type: destinationChainType,
55738
+ product_type: productType
55723
55739
  });
55724
55740
  const supportedTokens = tokensResponse?.data ?? [];
55725
55741
  const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
@@ -56754,6 +56770,54 @@ function TransferCryptoDoubleInput({
56754
56770
  }
56755
56771
  ) });
56756
56772
  }
56773
+ function useDepositQuote(params) {
56774
+ const {
56775
+ publishableKey,
56776
+ sourceChainType,
56777
+ sourceChainId,
56778
+ sourceTokenAddress,
56779
+ destinationAmount,
56780
+ destinationChainType,
56781
+ destinationChainId,
56782
+ destinationTokenAddress,
56783
+ adjustForSlippage,
56784
+ enabled = true
56785
+ } = params;
56786
+ const request = {
56787
+ source_chain_type: sourceChainType,
56788
+ source_chain_id: sourceChainId,
56789
+ source_token_address: sourceTokenAddress,
56790
+ destination_amount: destinationAmount,
56791
+ destination_chain_type: destinationChainType,
56792
+ destination_chain_id: destinationChainId,
56793
+ destination_token_address: destinationTokenAddress,
56794
+ ...adjustForSlippage ? { adjust_for_slippage: true } : {}
56795
+ };
56796
+ return useQuery({
56797
+ queryKey: [
56798
+ "unifold",
56799
+ "depositQuote",
56800
+ sourceChainType,
56801
+ sourceChainId,
56802
+ sourceTokenAddress,
56803
+ destinationAmount,
56804
+ destinationChainType,
56805
+ destinationChainId,
56806
+ destinationTokenAddress,
56807
+ adjustForSlippage,
56808
+ publishableKey
56809
+ ],
56810
+ queryFn: () => getDepositQuote(request, publishableKey),
56811
+ enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
56812
+ staleTime: 3e4,
56813
+ gcTime: 5 * 6e4,
56814
+ refetchInterval: 3e4,
56815
+ refetchIntervalInBackground: false,
56816
+ refetchOnWindowFocus: true,
56817
+ retry: 2,
56818
+ retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
56819
+ });
56820
+ }
56757
56821
  var BROWSER_WALLET_STEP_MIN_HEIGHT_CLASS = "uf-min-h-[460px]";
56758
56822
  var WALLET_ICONS = {
56759
56823
  metamask: MetamaskIcon,
@@ -57229,7 +57293,7 @@ function EnterAmountView({
57229
57293
  }
57230
57294
  )
57231
57295
  ] }) }),
57232
- tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && inputUsdNum > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
57296
+ 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_runtime65.jsxs)(
57233
57297
  "div",
57234
57298
  {
57235
57299
  className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
@@ -57831,7 +57895,11 @@ function BrowserWalletModal({
57831
57895
  checkoutReceivedUsd,
57832
57896
  onNewDeposit,
57833
57897
  onDone,
57834
- paymentIntentStatus
57898
+ paymentIntentStatus,
57899
+ checkoutQuote,
57900
+ checkoutDestination,
57901
+ checkoutRemainingBaseUnits,
57902
+ productType
57835
57903
  }) {
57836
57904
  const { colors: colors2, fonts, components } = useTheme();
57837
57905
  const [step, setStep] = React262.useState("select-token");
@@ -57853,7 +57921,49 @@ function BrowserWalletModal({
57853
57921
  const themeClass = theme === "dark" ? "uf-dark" : "";
57854
57922
  const chainType = depositWallet.chain_type;
57855
57923
  const recipientAddress = depositWallet.address;
57924
+ const isCheckoutMode = !!checkoutAmountUsd;
57856
57925
  const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
57926
+ const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
57927
+ const effectiveDestinationAmount = React262.useMemo(() => {
57928
+ if (!checkoutRemainingBaseUnits || checkoutRemainingBaseUnits === "0") return "0";
57929
+ if (!checkoutAmountUsd) return checkoutRemainingBaseUnits;
57930
+ const remaining = BigInt(checkoutRemainingBaseUnits);
57931
+ const minUsd = Math.max(tokenChainDetails?.minimum_deposit_amount_usd ?? 0, 3);
57932
+ const totalUsd = parseFloat(checkoutAmountUsd);
57933
+ if (totalUsd <= 0) return remaining > 0n ? remaining.toString() : "0";
57934
+ const receivedUsd = parseFloat(checkoutReceivedUsd ?? "0");
57935
+ const remainingUsd = totalUsd - receivedUsd;
57936
+ if (remainingUsd <= 0) return "0";
57937
+ const baseUnitsPerUsd = Number(remaining) / remainingUsd;
57938
+ const minBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
57939
+ const effective = remaining > minBaseUnits ? remaining : minBaseUnits;
57940
+ return effective > 0n ? effective.toString() : "0";
57941
+ }, [checkoutRemainingBaseUnits, checkoutAmountUsd, checkoutReceivedUsd, tokenChainDetails]);
57942
+ const { data: walletCheckoutQuote } = useDepositQuote({
57943
+ publishableKey,
57944
+ sourceChainType: selectedToken?.chain_type ?? "",
57945
+ sourceChainId: selectedToken?.chain_id ?? "",
57946
+ sourceTokenAddress: selectedToken?.token_address ?? "",
57947
+ destinationAmount: effectiveDestinationAmount,
57948
+ destinationChainType: checkoutDestination?.chainType ?? "",
57949
+ destinationChainId: checkoutDestination?.chainId ?? "",
57950
+ destinationTokenAddress: checkoutDestination?.tokenAddress ?? "",
57951
+ adjustForSlippage: true,
57952
+ enabled: open && isCheckoutMode && !!selectedToken && !!checkoutDestination && effectiveDestinationAmount !== "0"
57953
+ });
57954
+ const activeCheckoutQuote = React262.useMemo(() => {
57955
+ if (!isCheckoutMode) return null;
57956
+ if (walletCheckoutQuote) {
57957
+ return {
57958
+ sourceAmount: walletCheckoutQuote.source_amount,
57959
+ sourceTokenDecimals: walletCheckoutQuote.source_token_decimals,
57960
+ sourceTokenSymbol: walletCheckoutQuote.source_token_symbol,
57961
+ sourceAmountUsd: walletCheckoutQuote.source_amount_usd,
57962
+ slippageBufferPercent: walletCheckoutQuote.slippage_buffer_percent ?? null
57963
+ };
57964
+ }
57965
+ return checkoutQuote ?? null;
57966
+ }, [isCheckoutMode, walletCheckoutQuote, checkoutQuote]);
57857
57967
  const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
57858
57968
  userId,
57859
57969
  publishableKey,
@@ -57905,7 +58015,8 @@ function BrowserWalletModal({
57905
58015
  const options2 = {
57906
58016
  destination_token_address: depositWallet.destination_token_address,
57907
58017
  destination_chain_id: depositWallet.destination_chain_id,
57908
- destination_chain_type: depositWallet.destination_chain_type
58018
+ destination_chain_type: depositWallet.destination_chain_type,
58019
+ ...productType ? { product_type: productType } : {}
57909
58020
  };
57910
58021
  const response = await getSupportedDepositTokens(
57911
58022
  publishableKey,
@@ -58307,7 +58418,6 @@ function BrowserWalletModal({
58307
58418
  throw error2;
58308
58419
  }
58309
58420
  };
58310
- const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
58311
58421
  const usdToTokenRate = React262.useMemo(() => {
58312
58422
  if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken)
58313
58423
  return 0;
@@ -58317,15 +58427,24 @@ function BrowserWalletModal({
58317
58427
  return balanceAmount / balanceUsd;
58318
58428
  }, [selectedBalance, selectedToken]);
58319
58429
  const tokenAmount = React262.useMemo(() => {
58430
+ if (isCheckoutMode && activeCheckoutQuote && selectedToken) {
58431
+ return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
58432
+ }
58320
58433
  const usdNum = parseFloat(amountUsd) || 0;
58321
58434
  if (usdNum === 0 || usdToTokenRate === 0) return 0;
58322
58435
  return usdNum * usdToTokenRate;
58323
- }, [amountUsd, usdToTokenRate]);
58436
+ }, [amountUsd, usdToTokenRate, isCheckoutMode, activeCheckoutQuote, selectedToken]);
58437
+ React262.useEffect(() => {
58438
+ if (isCheckoutMode && activeCheckoutQuote?.sourceAmountUsd && step === "input-amount") {
58439
+ const quoteUsd = activeCheckoutQuote.sourceAmountUsd;
58440
+ setAmountUsd(quoteUsd);
58441
+ }
58442
+ }, [isCheckoutMode, activeCheckoutQuote, step]);
58324
58443
  const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
58325
58444
  const maxUsdAmount = selectedBalance?.amount_usd ? parseFloat(selectedBalance.amount_usd) : 0;
58326
58445
  const inputUsdNum = parseFloat(amountUsd) || 0;
58327
58446
  const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
58328
- const isValidAmount = inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
58447
+ const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
58329
58448
  const formattedTokenAmount = React262.useMemo(() => {
58330
58449
  if (tokenAmount === 0 || !selectedToken) return null;
58331
58450
  return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(
@@ -59781,49 +59900,6 @@ function usePaymentIntent(params) {
59781
59900
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
59782
59901
  });
59783
59902
  }
59784
- function useDepositQuote(params) {
59785
- const {
59786
- publishableKey,
59787
- sourceChainType,
59788
- sourceChainId,
59789
- sourceTokenAddress,
59790
- destinationAmount,
59791
- destinationChainType,
59792
- destinationChainId,
59793
- destinationTokenAddress,
59794
- enabled = true
59795
- } = params;
59796
- const request = {
59797
- source_chain_type: sourceChainType,
59798
- source_chain_id: sourceChainId,
59799
- source_token_address: sourceTokenAddress,
59800
- destination_amount: destinationAmount,
59801
- destination_chain_type: destinationChainType,
59802
- destination_chain_id: destinationChainId,
59803
- destination_token_address: destinationTokenAddress
59804
- };
59805
- return useQuery({
59806
- queryKey: [
59807
- "unifold",
59808
- "depositQuote",
59809
- sourceChainType,
59810
- sourceChainId,
59811
- sourceTokenAddress,
59812
- destinationAmount,
59813
- destinationChainType,
59814
- destinationChainId,
59815
- destinationTokenAddress,
59816
- publishableKey
59817
- ],
59818
- queryFn: () => getDepositQuote(request, publishableKey),
59819
- enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
59820
- staleTime: 6e4,
59821
- gcTime: 5 * 6e4,
59822
- refetchOnWindowFocus: false,
59823
- retry: 2,
59824
- retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
59825
- });
59826
- }
59827
59903
  function mapDepositAddressesToWallets(depositAddresses, pi) {
59828
59904
  return depositAddresses.map((da, idx) => ({
59829
59905
  id: da.id,
@@ -59973,6 +60049,7 @@ function CheckoutModal({
59973
60049
  destinationChainType: paymentIntent?.destination_chain_type ?? "",
59974
60050
  destinationChainId: paymentIntent?.destination_chain_id ?? "",
59975
60051
  destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
60052
+ adjustForSlippage: true,
59976
60053
  enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
59977
60054
  });
59978
60055
  const handleBrowserWalletClick = (0, import_react27.useCallback)(
@@ -60364,6 +60441,7 @@ function CheckoutModal({
60364
60441
  depositConfirmationMode: "auto_ui",
60365
60442
  wallets,
60366
60443
  onSourceTokenChange: setSelectedSource,
60444
+ productType: "payment",
60367
60445
  checkoutQuote: sourceQuote ? {
60368
60446
  sourceAmount: sourceQuote.source_amount,
60369
60447
  sourceTokenDecimals: sourceQuote.source_token_decimals,
@@ -60403,6 +60481,16 @@ function CheckoutModal({
60403
60481
  prefillAmountUsd: remainingAmountUsd,
60404
60482
  checkoutAmountUsd: paymentIntent?.amount_usd,
60405
60483
  checkoutReceivedUsd: paymentIntent?.amount_received_usd,
60484
+ checkoutDestination: paymentIntent ? {
60485
+ chainType: paymentIntent.destination_chain_type,
60486
+ chainId: paymentIntent.destination_chain_id,
60487
+ tokenAddress: paymentIntent.destination_token_address
60488
+ } : void 0,
60489
+ productType: "payment",
60490
+ checkoutRemainingBaseUnits: paymentIntent ? (() => {
60491
+ const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
60492
+ return remaining > 0n ? remaining.toString() : "0";
60493
+ })() : void 0,
60406
60494
  onSuccess: (txHash) => {
60407
60495
  onCheckoutSuccess?.({
60408
60496
  paymentIntentId: paymentIntent?.id || "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifold/ui-web",
3
- "version": "0.1.52",
3
+ "version": "0.1.53",
4
4
  "description": "Unifold UI Web - Framework-agnostic deposit widget",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -30,10 +30,10 @@
30
30
  "@types/react-dom": "^19.0.0",
31
31
  "tsup": "^8.0.0",
32
32
  "typescript": "^5.0.0",
33
- "@unifold/connect-react": "0.1.52",
34
- "@unifold/core": "0.1.52",
35
- "@unifold/ui-react": "0.1.52",
36
- "@unifold/react-provider": "0.1.52"
33
+ "@unifold/connect-react": "0.1.53",
34
+ "@unifold/ui-react": "0.1.53",
35
+ "@unifold/core": "0.1.53",
36
+ "@unifold/react-provider": "0.1.53"
37
37
  },
38
38
  "keywords": [
39
39
  "unifold",