@unifold/ui-web 0.1.51 → 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 +160 -69
  2. package/dist/index.mjs +160 -69
  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
  }
@@ -54108,8 +54113,11 @@ function BrowserWalletButton({
54108
54113
  solanaProvider.off("accountChanged", handleAccountsChanged);
54109
54114
  }
54110
54115
  for (const provider of ethProviders) {
54111
- provider.removeListener("accountsChanged", handleEthAccountsChanged);
54112
- provider.removeListener("chainChanged", handleAccountsChanged);
54116
+ const off = provider.off?.bind(provider) ?? provider.removeListener?.bind(provider);
54117
+ if (off) {
54118
+ off("accountsChanged", handleEthAccountsChanged);
54119
+ off("chainChanged", handleAccountsChanged);
54120
+ }
54113
54121
  }
54114
54122
  };
54115
54123
  }, [chainType, eip6963ProviderCount]);
@@ -54503,11 +54511,16 @@ function useAddressValidation({
54503
54511
  };
54504
54512
  }
54505
54513
  function useSupportedDepositTokens(publishableKey, options2) {
54506
- const filteredOptions = options2?.destination_token_address && options2?.destination_chain_id && options2?.destination_chain_type ? {
54507
- destination_token_address: options2.destination_token_address,
54508
- destination_chain_id: options2.destination_chain_id,
54509
- destination_chain_type: options2.destination_chain_type
54510
- } : 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;
54511
54524
  return useQuery({
54512
54525
  queryKey: [
54513
54526
  "unifold",
@@ -54515,9 +54528,13 @@ function useSupportedDepositTokens(publishableKey, options2) {
54515
54528
  publishableKey,
54516
54529
  filteredOptions?.destination_token_address ?? null,
54517
54530
  filteredOptions?.destination_chain_id ?? null,
54518
- filteredOptions?.destination_chain_type ?? null
54531
+ filteredOptions?.destination_chain_type ?? null,
54532
+ filteredOptions?.product_type ?? null
54519
54533
  ],
54520
- queryFn: () => getSupportedDepositTokens(publishableKey, filteredOptions),
54534
+ queryFn: () => getSupportedDepositTokens(
54535
+ publishableKey,
54536
+ hasFilteredOptions ? filteredOptions : void 0
54537
+ ),
54521
54538
  staleTime: 1e3 * 60 * 5,
54522
54539
  // 5 minutes — token list rarely changes
54523
54540
  gcTime: 1e3 * 60 * 30,
@@ -55716,7 +55733,8 @@ function TransferCryptoSingleInput({
55716
55733
  onDepositError,
55717
55734
  wallets: externalWallets,
55718
55735
  onSourceTokenChange,
55719
- checkoutQuote
55736
+ checkoutQuote,
55737
+ productType
55720
55738
  }) {
55721
55739
  const { themeClass, colors: colors2, fonts, components } = useTheme();
55722
55740
  const isDarkMode = themeClass.includes("uf-dark");
@@ -55729,7 +55747,8 @@ function TransferCryptoSingleInput({
55729
55747
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
55730
55748
  destination_token_address: destinationTokenAddress,
55731
55749
  destination_chain_id: destinationChainId,
55732
- destination_chain_type: destinationChainType
55750
+ destination_chain_type: destinationChainType,
55751
+ product_type: productType
55733
55752
  });
55734
55753
  const supportedTokens = tokensResponse?.data ?? [];
55735
55754
  const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
@@ -56764,6 +56783,54 @@ function TransferCryptoDoubleInput({
56764
56783
  }
56765
56784
  ) });
56766
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
+ }
56767
56834
  var BROWSER_WALLET_STEP_MIN_HEIGHT_CLASS = "uf-min-h-[460px]";
56768
56835
  var WALLET_ICONS = {
56769
56836
  metamask: MetamaskIcon,
@@ -57239,7 +57306,7 @@ function EnterAmountView({
57239
57306
  }
57240
57307
  )
57241
57308
  ] }) }),
57242
- 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)(
57243
57310
  "div",
57244
57311
  {
57245
57312
  className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
@@ -57841,7 +57908,11 @@ function BrowserWalletModal({
57841
57908
  checkoutReceivedUsd,
57842
57909
  onNewDeposit,
57843
57910
  onDone,
57844
- paymentIntentStatus
57911
+ paymentIntentStatus,
57912
+ checkoutQuote,
57913
+ checkoutDestination,
57914
+ checkoutRemainingBaseUnits,
57915
+ productType
57845
57916
  }) {
57846
57917
  const { colors: colors2, fonts, components } = useTheme();
57847
57918
  const [step, setStep] = React262.useState("select-token");
@@ -57863,7 +57934,49 @@ function BrowserWalletModal({
57863
57934
  const themeClass = theme === "dark" ? "uf-dark" : "";
57864
57935
  const chainType = depositWallet.chain_type;
57865
57936
  const recipientAddress = depositWallet.address;
57937
+ const isCheckoutMode = !!checkoutAmountUsd;
57866
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]);
57867
57980
  const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
57868
57981
  userId,
57869
57982
  publishableKey,
@@ -57915,7 +58028,8 @@ function BrowserWalletModal({
57915
58028
  const options2 = {
57916
58029
  destination_token_address: depositWallet.destination_token_address,
57917
58030
  destination_chain_id: depositWallet.destination_chain_id,
57918
- destination_chain_type: depositWallet.destination_chain_type
58031
+ destination_chain_type: depositWallet.destination_chain_type,
58032
+ ...productType ? { product_type: productType } : {}
57919
58033
  };
57920
58034
  const response = await getSupportedDepositTokens(
57921
58035
  publishableKey,
@@ -58317,7 +58431,6 @@ function BrowserWalletModal({
58317
58431
  throw error2;
58318
58432
  }
58319
58433
  };
58320
- const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
58321
58434
  const usdToTokenRate = React262.useMemo(() => {
58322
58435
  if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken)
58323
58436
  return 0;
@@ -58327,15 +58440,24 @@ function BrowserWalletModal({
58327
58440
  return balanceAmount / balanceUsd;
58328
58441
  }, [selectedBalance, selectedToken]);
58329
58442
  const tokenAmount = React262.useMemo(() => {
58443
+ if (isCheckoutMode && activeCheckoutQuote && selectedToken) {
58444
+ return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
58445
+ }
58330
58446
  const usdNum = parseFloat(amountUsd) || 0;
58331
58447
  if (usdNum === 0 || usdToTokenRate === 0) return 0;
58332
58448
  return usdNum * usdToTokenRate;
58333
- }, [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]);
58334
58456
  const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
58335
58457
  const maxUsdAmount = selectedBalance?.amount_usd ? parseFloat(selectedBalance.amount_usd) : 0;
58336
58458
  const inputUsdNum = parseFloat(amountUsd) || 0;
58337
58459
  const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
58338
- const isValidAmount = inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
58460
+ const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
58339
58461
  const formattedTokenAmount = React262.useMemo(() => {
58340
58462
  if (tokenAmount === 0 || !selectedToken) return null;
58341
58463
  return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(
@@ -59791,49 +59913,6 @@ function usePaymentIntent(params) {
59791
59913
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
59792
59914
  });
59793
59915
  }
59794
- function useDepositQuote(params) {
59795
- const {
59796
- publishableKey,
59797
- sourceChainType,
59798
- sourceChainId,
59799
- sourceTokenAddress,
59800
- destinationAmount,
59801
- destinationChainType,
59802
- destinationChainId,
59803
- destinationTokenAddress,
59804
- enabled = true
59805
- } = params;
59806
- const request = {
59807
- source_chain_type: sourceChainType,
59808
- source_chain_id: sourceChainId,
59809
- source_token_address: sourceTokenAddress,
59810
- destination_amount: destinationAmount,
59811
- destination_chain_type: destinationChainType,
59812
- destination_chain_id: destinationChainId,
59813
- destination_token_address: destinationTokenAddress
59814
- };
59815
- return useQuery({
59816
- queryKey: [
59817
- "unifold",
59818
- "depositQuote",
59819
- sourceChainType,
59820
- sourceChainId,
59821
- sourceTokenAddress,
59822
- destinationAmount,
59823
- destinationChainType,
59824
- destinationChainId,
59825
- destinationTokenAddress,
59826
- publishableKey
59827
- ],
59828
- queryFn: () => getDepositQuote(request, publishableKey),
59829
- enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
59830
- staleTime: 6e4,
59831
- gcTime: 5 * 6e4,
59832
- refetchOnWindowFocus: false,
59833
- retry: 2,
59834
- retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
59835
- });
59836
- }
59837
59916
  function mapDepositAddressesToWallets(depositAddresses, pi) {
59838
59917
  return depositAddresses.map((da, idx) => ({
59839
59918
  id: da.id,
@@ -59983,6 +60062,7 @@ function CheckoutModal({
59983
60062
  destinationChainType: paymentIntent?.destination_chain_type ?? "",
59984
60063
  destinationChainId: paymentIntent?.destination_chain_id ?? "",
59985
60064
  destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
60065
+ adjustForSlippage: true,
59986
60066
  enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
59987
60067
  });
59988
60068
  const handleBrowserWalletClick = (0, import_react27.useCallback)(
@@ -60374,6 +60454,7 @@ function CheckoutModal({
60374
60454
  depositConfirmationMode: "auto_ui",
60375
60455
  wallets,
60376
60456
  onSourceTokenChange: setSelectedSource,
60457
+ productType: "payment",
60377
60458
  checkoutQuote: sourceQuote ? {
60378
60459
  sourceAmount: sourceQuote.source_amount,
60379
60460
  sourceTokenDecimals: sourceQuote.source_token_decimals,
@@ -60413,6 +60494,16 @@ function CheckoutModal({
60413
60494
  prefillAmountUsd: remainingAmountUsd,
60414
60495
  checkoutAmountUsd: paymentIntent?.amount_usd,
60415
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,
60416
60507
  onSuccess: (txHash) => {
60417
60508
  onCheckoutSuccess?.({
60418
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
  }
@@ -54095,8 +54100,11 @@ function BrowserWalletButton({
54095
54100
  solanaProvider.off("accountChanged", handleAccountsChanged);
54096
54101
  }
54097
54102
  for (const provider of ethProviders) {
54098
- provider.removeListener("accountsChanged", handleEthAccountsChanged);
54099
- provider.removeListener("chainChanged", handleAccountsChanged);
54103
+ const off = provider.off?.bind(provider) ?? provider.removeListener?.bind(provider);
54104
+ if (off) {
54105
+ off("accountsChanged", handleEthAccountsChanged);
54106
+ off("chainChanged", handleAccountsChanged);
54107
+ }
54100
54108
  }
54101
54109
  };
54102
54110
  }, [chainType, eip6963ProviderCount]);
@@ -54490,11 +54498,16 @@ function useAddressValidation({
54490
54498
  };
54491
54499
  }
54492
54500
  function useSupportedDepositTokens(publishableKey, options2) {
54493
- const filteredOptions = options2?.destination_token_address && options2?.destination_chain_id && options2?.destination_chain_type ? {
54494
- destination_token_address: options2.destination_token_address,
54495
- destination_chain_id: options2.destination_chain_id,
54496
- destination_chain_type: options2.destination_chain_type
54497
- } : 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;
54498
54511
  return useQuery({
54499
54512
  queryKey: [
54500
54513
  "unifold",
@@ -54502,9 +54515,13 @@ function useSupportedDepositTokens(publishableKey, options2) {
54502
54515
  publishableKey,
54503
54516
  filteredOptions?.destination_token_address ?? null,
54504
54517
  filteredOptions?.destination_chain_id ?? null,
54505
- filteredOptions?.destination_chain_type ?? null
54518
+ filteredOptions?.destination_chain_type ?? null,
54519
+ filteredOptions?.product_type ?? null
54506
54520
  ],
54507
- queryFn: () => getSupportedDepositTokens(publishableKey, filteredOptions),
54521
+ queryFn: () => getSupportedDepositTokens(
54522
+ publishableKey,
54523
+ hasFilteredOptions ? filteredOptions : void 0
54524
+ ),
54508
54525
  staleTime: 1e3 * 60 * 5,
54509
54526
  // 5 minutes — token list rarely changes
54510
54527
  gcTime: 1e3 * 60 * 30,
@@ -55703,7 +55720,8 @@ function TransferCryptoSingleInput({
55703
55720
  onDepositError,
55704
55721
  wallets: externalWallets,
55705
55722
  onSourceTokenChange,
55706
- checkoutQuote
55723
+ checkoutQuote,
55724
+ productType
55707
55725
  }) {
55708
55726
  const { themeClass, colors: colors2, fonts, components } = useTheme();
55709
55727
  const isDarkMode = themeClass.includes("uf-dark");
@@ -55716,7 +55734,8 @@ function TransferCryptoSingleInput({
55716
55734
  const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
55717
55735
  destination_token_address: destinationTokenAddress,
55718
55736
  destination_chain_id: destinationChainId,
55719
- destination_chain_type: destinationChainType
55737
+ destination_chain_type: destinationChainType,
55738
+ product_type: productType
55720
55739
  });
55721
55740
  const supportedTokens = tokensResponse?.data ?? [];
55722
55741
  const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
@@ -56751,6 +56770,54 @@ function TransferCryptoDoubleInput({
56751
56770
  }
56752
56771
  ) });
56753
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
+ }
56754
56821
  var BROWSER_WALLET_STEP_MIN_HEIGHT_CLASS = "uf-min-h-[460px]";
56755
56822
  var WALLET_ICONS = {
56756
56823
  metamask: MetamaskIcon,
@@ -57226,7 +57293,7 @@ function EnterAmountView({
57226
57293
  }
57227
57294
  )
57228
57295
  ] }) }),
57229
- 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)(
57230
57297
  "div",
57231
57298
  {
57232
57299
  className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
@@ -57828,7 +57895,11 @@ function BrowserWalletModal({
57828
57895
  checkoutReceivedUsd,
57829
57896
  onNewDeposit,
57830
57897
  onDone,
57831
- paymentIntentStatus
57898
+ paymentIntentStatus,
57899
+ checkoutQuote,
57900
+ checkoutDestination,
57901
+ checkoutRemainingBaseUnits,
57902
+ productType
57832
57903
  }) {
57833
57904
  const { colors: colors2, fonts, components } = useTheme();
57834
57905
  const [step, setStep] = React262.useState("select-token");
@@ -57850,7 +57921,49 @@ function BrowserWalletModal({
57850
57921
  const themeClass = theme === "dark" ? "uf-dark" : "";
57851
57922
  const chainType = depositWallet.chain_type;
57852
57923
  const recipientAddress = depositWallet.address;
57924
+ const isCheckoutMode = !!checkoutAmountUsd;
57853
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]);
57854
57967
  const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
57855
57968
  userId,
57856
57969
  publishableKey,
@@ -57902,7 +58015,8 @@ function BrowserWalletModal({
57902
58015
  const options2 = {
57903
58016
  destination_token_address: depositWallet.destination_token_address,
57904
58017
  destination_chain_id: depositWallet.destination_chain_id,
57905
- destination_chain_type: depositWallet.destination_chain_type
58018
+ destination_chain_type: depositWallet.destination_chain_type,
58019
+ ...productType ? { product_type: productType } : {}
57906
58020
  };
57907
58021
  const response = await getSupportedDepositTokens(
57908
58022
  publishableKey,
@@ -58304,7 +58418,6 @@ function BrowserWalletModal({
58304
58418
  throw error2;
58305
58419
  }
58306
58420
  };
58307
- const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
58308
58421
  const usdToTokenRate = React262.useMemo(() => {
58309
58422
  if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken)
58310
58423
  return 0;
@@ -58314,15 +58427,24 @@ function BrowserWalletModal({
58314
58427
  return balanceAmount / balanceUsd;
58315
58428
  }, [selectedBalance, selectedToken]);
58316
58429
  const tokenAmount = React262.useMemo(() => {
58430
+ if (isCheckoutMode && activeCheckoutQuote && selectedToken) {
58431
+ return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
58432
+ }
58317
58433
  const usdNum = parseFloat(amountUsd) || 0;
58318
58434
  if (usdNum === 0 || usdToTokenRate === 0) return 0;
58319
58435
  return usdNum * usdToTokenRate;
58320
- }, [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]);
58321
58443
  const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
58322
58444
  const maxUsdAmount = selectedBalance?.amount_usd ? parseFloat(selectedBalance.amount_usd) : 0;
58323
58445
  const inputUsdNum = parseFloat(amountUsd) || 0;
58324
58446
  const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
58325
- const isValidAmount = inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
58447
+ const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
58326
58448
  const formattedTokenAmount = React262.useMemo(() => {
58327
58449
  if (tokenAmount === 0 || !selectedToken) return null;
58328
58450
  return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(
@@ -59778,49 +59900,6 @@ function usePaymentIntent(params) {
59778
59900
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
59779
59901
  });
59780
59902
  }
59781
- function useDepositQuote(params) {
59782
- const {
59783
- publishableKey,
59784
- sourceChainType,
59785
- sourceChainId,
59786
- sourceTokenAddress,
59787
- destinationAmount,
59788
- destinationChainType,
59789
- destinationChainId,
59790
- destinationTokenAddress,
59791
- enabled = true
59792
- } = params;
59793
- const request = {
59794
- source_chain_type: sourceChainType,
59795
- source_chain_id: sourceChainId,
59796
- source_token_address: sourceTokenAddress,
59797
- destination_amount: destinationAmount,
59798
- destination_chain_type: destinationChainType,
59799
- destination_chain_id: destinationChainId,
59800
- destination_token_address: destinationTokenAddress
59801
- };
59802
- return useQuery({
59803
- queryKey: [
59804
- "unifold",
59805
- "depositQuote",
59806
- sourceChainType,
59807
- sourceChainId,
59808
- sourceTokenAddress,
59809
- destinationAmount,
59810
- destinationChainType,
59811
- destinationChainId,
59812
- destinationTokenAddress,
59813
- publishableKey
59814
- ],
59815
- queryFn: () => getDepositQuote(request, publishableKey),
59816
- enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
59817
- staleTime: 6e4,
59818
- gcTime: 5 * 6e4,
59819
- refetchOnWindowFocus: false,
59820
- retry: 2,
59821
- retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
59822
- });
59823
- }
59824
59903
  function mapDepositAddressesToWallets(depositAddresses, pi) {
59825
59904
  return depositAddresses.map((da, idx) => ({
59826
59905
  id: da.id,
@@ -59970,6 +60049,7 @@ function CheckoutModal({
59970
60049
  destinationChainType: paymentIntent?.destination_chain_type ?? "",
59971
60050
  destinationChainId: paymentIntent?.destination_chain_id ?? "",
59972
60051
  destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
60052
+ adjustForSlippage: true,
59973
60053
  enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
59974
60054
  });
59975
60055
  const handleBrowserWalletClick = (0, import_react27.useCallback)(
@@ -60361,6 +60441,7 @@ function CheckoutModal({
60361
60441
  depositConfirmationMode: "auto_ui",
60362
60442
  wallets,
60363
60443
  onSourceTokenChange: setSelectedSource,
60444
+ productType: "payment",
60364
60445
  checkoutQuote: sourceQuote ? {
60365
60446
  sourceAmount: sourceQuote.source_amount,
60366
60447
  sourceTokenDecimals: sourceQuote.source_token_decimals,
@@ -60400,6 +60481,16 @@ function CheckoutModal({
60400
60481
  prefillAmountUsd: remainingAmountUsd,
60401
60482
  checkoutAmountUsd: paymentIntent?.amount_usd,
60402
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,
60403
60494
  onSuccess: (txHash) => {
60404
60495
  onCheckoutSuccess?.({
60405
60496
  paymentIntentId: paymentIntent?.id || "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifold/ui-web",
3
- "version": "0.1.51",
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.51",
34
- "@unifold/core": "0.1.51",
35
- "@unifold/ui-react": "0.1.51",
36
- "@unifold/react-provider": "0.1.51"
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",