@unifold/ui-react 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.
- package/dist/index.d.mts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +163 -77
- package/dist/index.mjs +157 -71
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -93,7 +93,8 @@ interface EthereumProvider {
|
|
|
93
93
|
params?: unknown[];
|
|
94
94
|
}): Promise<unknown>;
|
|
95
95
|
on(event: string, callback: (...args: unknown[]) => void): void;
|
|
96
|
-
|
|
96
|
+
off?(event: string, callback: (...args: unknown[]) => void): void;
|
|
97
|
+
removeListener?(event: string, callback: (...args: unknown[]) => void): void;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
/** Quick amount chips on the browser wallet "Enter amount" step */
|
|
@@ -126,7 +127,8 @@ interface EvmWalletProvider {
|
|
|
126
127
|
params?: unknown[];
|
|
127
128
|
}): Promise<unknown>;
|
|
128
129
|
on(event: string, callback: (...args: unknown[]) => void): void;
|
|
129
|
-
|
|
130
|
+
off?(event: string, callback: (...args: unknown[]) => void): void;
|
|
131
|
+
removeListener?(event: string, callback: (...args: unknown[]) => void): void;
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
type DepositModalInitialScreen = "main" | "transfer" | "card" | "tracker";
|
|
@@ -273,8 +275,10 @@ interface TransferCryptoSingleInputProps {
|
|
|
273
275
|
sourceTokenSymbol: string;
|
|
274
276
|
sourceAmountUsd: string | null;
|
|
275
277
|
} | null;
|
|
278
|
+
/** Product context sent to the API — "deposit" (default) or "payment". */
|
|
279
|
+
productType?: "deposit" | "payment";
|
|
276
280
|
}
|
|
277
|
-
declare function TransferCryptoSingleInput({ userId, publishableKey, clientSecret, recipientAddress, destinationChainType, destinationChainId, destinationTokenAddress, defaultSourceChainType, defaultSourceChainId, defaultSourceTokenAddress, defaultSourceSymbol, depositConfirmationMode, onExecutionsChange, onDepositSuccess, onDepositError, wallets: externalWallets, onSourceTokenChange, checkoutQuote, }: TransferCryptoSingleInputProps): react_jsx_runtime.JSX.Element;
|
|
281
|
+
declare function TransferCryptoSingleInput({ userId, publishableKey, clientSecret, recipientAddress, destinationChainType, destinationChainId, destinationTokenAddress, defaultSourceChainType, defaultSourceChainId, defaultSourceTokenAddress, defaultSourceSymbol, depositConfirmationMode, onExecutionsChange, onDepositSuccess, onDepositError, wallets: externalWallets, onSourceTokenChange, checkoutQuote, productType, }: TransferCryptoSingleInputProps): react_jsx_runtime.JSX.Element;
|
|
278
282
|
|
|
279
283
|
interface TransferCryptoDoubleInputProps {
|
|
280
284
|
userId: string;
|
|
@@ -838,6 +842,8 @@ interface UseDepositQuoteParams {
|
|
|
838
842
|
destinationChainType: string;
|
|
839
843
|
destinationChainId: string;
|
|
840
844
|
destinationTokenAddress: string;
|
|
845
|
+
/** When true, inflates source amount by expected slippage. Typically set by checkout flows. */
|
|
846
|
+
adjustForSlippage?: boolean;
|
|
841
847
|
enabled?: boolean;
|
|
842
848
|
}
|
|
843
849
|
/**
|
|
@@ -884,6 +890,7 @@ interface UseSupportedDepositTokensOptions {
|
|
|
884
890
|
destination_token_address?: string;
|
|
885
891
|
destination_chain_id?: string;
|
|
886
892
|
destination_chain_type?: string;
|
|
893
|
+
product_type?: "deposit" | "payment";
|
|
887
894
|
}
|
|
888
895
|
/**
|
|
889
896
|
* Hook to fetch supported deposit tokens with caching and deduplication via react-query.
|
package/dist/index.d.ts
CHANGED
|
@@ -93,7 +93,8 @@ interface EthereumProvider {
|
|
|
93
93
|
params?: unknown[];
|
|
94
94
|
}): Promise<unknown>;
|
|
95
95
|
on(event: string, callback: (...args: unknown[]) => void): void;
|
|
96
|
-
|
|
96
|
+
off?(event: string, callback: (...args: unknown[]) => void): void;
|
|
97
|
+
removeListener?(event: string, callback: (...args: unknown[]) => void): void;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
/** Quick amount chips on the browser wallet "Enter amount" step */
|
|
@@ -126,7 +127,8 @@ interface EvmWalletProvider {
|
|
|
126
127
|
params?: unknown[];
|
|
127
128
|
}): Promise<unknown>;
|
|
128
129
|
on(event: string, callback: (...args: unknown[]) => void): void;
|
|
129
|
-
|
|
130
|
+
off?(event: string, callback: (...args: unknown[]) => void): void;
|
|
131
|
+
removeListener?(event: string, callback: (...args: unknown[]) => void): void;
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
type DepositModalInitialScreen = "main" | "transfer" | "card" | "tracker";
|
|
@@ -273,8 +275,10 @@ interface TransferCryptoSingleInputProps {
|
|
|
273
275
|
sourceTokenSymbol: string;
|
|
274
276
|
sourceAmountUsd: string | null;
|
|
275
277
|
} | null;
|
|
278
|
+
/** Product context sent to the API — "deposit" (default) or "payment". */
|
|
279
|
+
productType?: "deposit" | "payment";
|
|
276
280
|
}
|
|
277
|
-
declare function TransferCryptoSingleInput({ userId, publishableKey, clientSecret, recipientAddress, destinationChainType, destinationChainId, destinationTokenAddress, defaultSourceChainType, defaultSourceChainId, defaultSourceTokenAddress, defaultSourceSymbol, depositConfirmationMode, onExecutionsChange, onDepositSuccess, onDepositError, wallets: externalWallets, onSourceTokenChange, checkoutQuote, }: TransferCryptoSingleInputProps): react_jsx_runtime.JSX.Element;
|
|
281
|
+
declare function TransferCryptoSingleInput({ userId, publishableKey, clientSecret, recipientAddress, destinationChainType, destinationChainId, destinationTokenAddress, defaultSourceChainType, defaultSourceChainId, defaultSourceTokenAddress, defaultSourceSymbol, depositConfirmationMode, onExecutionsChange, onDepositSuccess, onDepositError, wallets: externalWallets, onSourceTokenChange, checkoutQuote, productType, }: TransferCryptoSingleInputProps): react_jsx_runtime.JSX.Element;
|
|
278
282
|
|
|
279
283
|
interface TransferCryptoDoubleInputProps {
|
|
280
284
|
userId: string;
|
|
@@ -838,6 +842,8 @@ interface UseDepositQuoteParams {
|
|
|
838
842
|
destinationChainType: string;
|
|
839
843
|
destinationChainId: string;
|
|
840
844
|
destinationTokenAddress: string;
|
|
845
|
+
/** When true, inflates source amount by expected slippage. Typically set by checkout flows. */
|
|
846
|
+
adjustForSlippage?: boolean;
|
|
841
847
|
enabled?: boolean;
|
|
842
848
|
}
|
|
843
849
|
/**
|
|
@@ -884,6 +890,7 @@ interface UseSupportedDepositTokensOptions {
|
|
|
884
890
|
destination_token_address?: string;
|
|
885
891
|
destination_chain_id?: string;
|
|
886
892
|
destination_chain_type?: string;
|
|
893
|
+
product_type?: "deposit" | "payment";
|
|
887
894
|
}
|
|
888
895
|
/**
|
|
889
896
|
* Hook to fetch supported deposit tokens with caching and deduplication via react-query.
|
package/dist/index.js
CHANGED
|
@@ -2608,14 +2608,14 @@ function BuyWithCard({
|
|
|
2608
2608
|
);
|
|
2609
2609
|
if (matchingCurrency) {
|
|
2610
2610
|
setCurrency(matchingCurrency.currency_code.toLowerCase());
|
|
2611
|
-
if (!amount && !hasManualAmountEntry) {
|
|
2611
|
+
if (!amount && !hasManualAmountEntry && matchingCurrency.default_amount != null) {
|
|
2612
2612
|
setAmount(matchingCurrency.default_amount.toString());
|
|
2613
2613
|
}
|
|
2614
2614
|
} else if (!amount && !hasManualAmountEntry) {
|
|
2615
2615
|
const usdCurrency = fiatCurrencies.find(
|
|
2616
2616
|
(c) => c.currency_code.toLowerCase() === "usd"
|
|
2617
2617
|
);
|
|
2618
|
-
if (usdCurrency) {
|
|
2618
|
+
if (usdCurrency?.default_amount != null) {
|
|
2619
2619
|
setAmount(usdCurrency.default_amount.toString());
|
|
2620
2620
|
}
|
|
2621
2621
|
}
|
|
@@ -2633,7 +2633,7 @@ function BuyWithCard({
|
|
|
2633
2633
|
const currentCurrency = fiatCurrencies.find(
|
|
2634
2634
|
(c) => c.currency_code.toLowerCase() === currency.toLowerCase()
|
|
2635
2635
|
);
|
|
2636
|
-
if (currentCurrency) {
|
|
2636
|
+
if (currentCurrency?.default_amount != null) {
|
|
2637
2637
|
setAmount(currentCurrency.default_amount.toString());
|
|
2638
2638
|
}
|
|
2639
2639
|
}
|
|
@@ -6658,8 +6658,11 @@ function BrowserWalletButton({
|
|
|
6658
6658
|
solanaProvider.off("accountChanged", handleAccountsChanged);
|
|
6659
6659
|
}
|
|
6660
6660
|
for (const provider of ethProviders) {
|
|
6661
|
-
provider.removeListener(
|
|
6662
|
-
|
|
6661
|
+
const off = provider.off?.bind(provider) ?? provider.removeListener?.bind(provider);
|
|
6662
|
+
if (off) {
|
|
6663
|
+
off("accountsChanged", handleEthAccountsChanged);
|
|
6664
|
+
off("chainChanged", handleAccountsChanged);
|
|
6665
|
+
}
|
|
6663
6666
|
}
|
|
6664
6667
|
};
|
|
6665
6668
|
}, [chainType, eip6963ProviderCount]);
|
|
@@ -6954,7 +6957,7 @@ function useProjectConfig({
|
|
|
6954
6957
|
}
|
|
6955
6958
|
|
|
6956
6959
|
// src/components/deposits/DepositModal.tsx
|
|
6957
|
-
var
|
|
6960
|
+
var import_core24 = require("@unifold/core");
|
|
6958
6961
|
|
|
6959
6962
|
// src/hooks/use-allowed-country.ts
|
|
6960
6963
|
var import_react_query6 = require("@tanstack/react-query");
|
|
@@ -7083,11 +7086,16 @@ function useAddressValidation({
|
|
|
7083
7086
|
var import_react_query8 = require("@tanstack/react-query");
|
|
7084
7087
|
var import_core18 = require("@unifold/core");
|
|
7085
7088
|
function useSupportedDepositTokens(publishableKey, options) {
|
|
7086
|
-
const
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7089
|
+
const hasDestination = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type;
|
|
7090
|
+
const filteredOptions = {
|
|
7091
|
+
...hasDestination ? {
|
|
7092
|
+
destination_token_address: options.destination_token_address,
|
|
7093
|
+
destination_chain_id: options.destination_chain_id,
|
|
7094
|
+
destination_chain_type: options.destination_chain_type
|
|
7095
|
+
} : {},
|
|
7096
|
+
...options?.product_type ? { product_type: options.product_type } : {}
|
|
7097
|
+
};
|
|
7098
|
+
const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
|
|
7091
7099
|
return (0, import_react_query8.useQuery)({
|
|
7092
7100
|
queryKey: [
|
|
7093
7101
|
"unifold",
|
|
@@ -7095,9 +7103,13 @@ function useSupportedDepositTokens(publishableKey, options) {
|
|
|
7095
7103
|
publishableKey,
|
|
7096
7104
|
filteredOptions?.destination_token_address ?? null,
|
|
7097
7105
|
filteredOptions?.destination_chain_id ?? null,
|
|
7098
|
-
filteredOptions?.destination_chain_type ?? null
|
|
7106
|
+
filteredOptions?.destination_chain_type ?? null,
|
|
7107
|
+
filteredOptions?.product_type ?? null
|
|
7099
7108
|
],
|
|
7100
|
-
queryFn: () => (0, import_core18.getSupportedDepositTokens)(
|
|
7109
|
+
queryFn: () => (0, import_core18.getSupportedDepositTokens)(
|
|
7110
|
+
publishableKey,
|
|
7111
|
+
hasFilteredOptions ? filteredOptions : void 0
|
|
7112
|
+
),
|
|
7101
7113
|
staleTime: 1e3 * 60 * 5,
|
|
7102
7114
|
// 5 minutes — token list rarely changes
|
|
7103
7115
|
gcTime: 1e3 * 60 * 30,
|
|
@@ -8375,7 +8387,8 @@ function TransferCryptoSingleInput({
|
|
|
8375
8387
|
onDepositError,
|
|
8376
8388
|
wallets: externalWallets,
|
|
8377
8389
|
onSourceTokenChange,
|
|
8378
|
-
checkoutQuote
|
|
8390
|
+
checkoutQuote,
|
|
8391
|
+
productType
|
|
8379
8392
|
}) {
|
|
8380
8393
|
const { themeClass, colors: colors2, fonts, components } = useTheme();
|
|
8381
8394
|
const isDarkMode = themeClass.includes("uf-dark");
|
|
@@ -8388,7 +8401,8 @@ function TransferCryptoSingleInput({
|
|
|
8388
8401
|
const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
|
|
8389
8402
|
destination_token_address: destinationTokenAddress,
|
|
8390
8403
|
destination_chain_id: destinationChainId,
|
|
8391
|
-
destination_chain_type: destinationChainType
|
|
8404
|
+
destination_chain_type: destinationChainType,
|
|
8405
|
+
product_type: productType
|
|
8392
8406
|
});
|
|
8393
8407
|
const supportedTokens = tokensResponse?.data ?? [];
|
|
8394
8408
|
const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
|
|
@@ -9441,7 +9455,59 @@ function TransferCryptoDoubleInput({
|
|
|
9441
9455
|
|
|
9442
9456
|
// src/components/deposits/BrowserWalletModal.tsx
|
|
9443
9457
|
var React26 = __toESM(require("react"));
|
|
9458
|
+
var import_core23 = require("@unifold/core");
|
|
9459
|
+
|
|
9460
|
+
// src/hooks/use-deposit-quote.ts
|
|
9461
|
+
var import_react_query9 = require("@tanstack/react-query");
|
|
9444
9462
|
var import_core22 = require("@unifold/core");
|
|
9463
|
+
function useDepositQuote(params) {
|
|
9464
|
+
const {
|
|
9465
|
+
publishableKey,
|
|
9466
|
+
sourceChainType,
|
|
9467
|
+
sourceChainId,
|
|
9468
|
+
sourceTokenAddress,
|
|
9469
|
+
destinationAmount,
|
|
9470
|
+
destinationChainType,
|
|
9471
|
+
destinationChainId,
|
|
9472
|
+
destinationTokenAddress,
|
|
9473
|
+
adjustForSlippage,
|
|
9474
|
+
enabled = true
|
|
9475
|
+
} = params;
|
|
9476
|
+
const request = {
|
|
9477
|
+
source_chain_type: sourceChainType,
|
|
9478
|
+
source_chain_id: sourceChainId,
|
|
9479
|
+
source_token_address: sourceTokenAddress,
|
|
9480
|
+
destination_amount: destinationAmount,
|
|
9481
|
+
destination_chain_type: destinationChainType,
|
|
9482
|
+
destination_chain_id: destinationChainId,
|
|
9483
|
+
destination_token_address: destinationTokenAddress,
|
|
9484
|
+
...adjustForSlippage ? { adjust_for_slippage: true } : {}
|
|
9485
|
+
};
|
|
9486
|
+
return (0, import_react_query9.useQuery)({
|
|
9487
|
+
queryKey: [
|
|
9488
|
+
"unifold",
|
|
9489
|
+
"depositQuote",
|
|
9490
|
+
sourceChainType,
|
|
9491
|
+
sourceChainId,
|
|
9492
|
+
sourceTokenAddress,
|
|
9493
|
+
destinationAmount,
|
|
9494
|
+
destinationChainType,
|
|
9495
|
+
destinationChainId,
|
|
9496
|
+
destinationTokenAddress,
|
|
9497
|
+
adjustForSlippage,
|
|
9498
|
+
publishableKey
|
|
9499
|
+
],
|
|
9500
|
+
queryFn: () => (0, import_core22.getDepositQuote)(request, publishableKey),
|
|
9501
|
+
enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
|
|
9502
|
+
staleTime: 3e4,
|
|
9503
|
+
gcTime: 5 * 6e4,
|
|
9504
|
+
refetchInterval: 3e4,
|
|
9505
|
+
refetchIntervalInBackground: false,
|
|
9506
|
+
refetchOnWindowFocus: true,
|
|
9507
|
+
retry: 2,
|
|
9508
|
+
retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
|
|
9509
|
+
});
|
|
9510
|
+
}
|
|
9445
9511
|
|
|
9446
9512
|
// src/components/deposits/browser-wallets/types.ts
|
|
9447
9513
|
var BROWSER_WALLET_STEP_MIN_HEIGHT_CLASS = "uf-min-h-[460px]";
|
|
@@ -9931,7 +9997,7 @@ function EnterAmountView({
|
|
|
9931
9997
|
}
|
|
9932
9998
|
)
|
|
9933
9999
|
] }) }),
|
|
9934
|
-
tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd &&
|
|
10000
|
+
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_runtime46.jsxs)(
|
|
9935
10001
|
"div",
|
|
9936
10002
|
{
|
|
9937
10003
|
className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
|
|
@@ -10545,7 +10611,11 @@ function BrowserWalletModal({
|
|
|
10545
10611
|
checkoutReceivedUsd,
|
|
10546
10612
|
onNewDeposit,
|
|
10547
10613
|
onDone,
|
|
10548
|
-
paymentIntentStatus
|
|
10614
|
+
paymentIntentStatus,
|
|
10615
|
+
checkoutQuote,
|
|
10616
|
+
checkoutDestination,
|
|
10617
|
+
checkoutRemainingBaseUnits,
|
|
10618
|
+
productType
|
|
10549
10619
|
}) {
|
|
10550
10620
|
const { colors: colors2, fonts, components } = useTheme();
|
|
10551
10621
|
const [step, setStep] = React26.useState("select-token");
|
|
@@ -10567,7 +10637,49 @@ function BrowserWalletModal({
|
|
|
10567
10637
|
const themeClass = theme === "dark" ? "uf-dark" : "";
|
|
10568
10638
|
const chainType = depositWallet.chain_type;
|
|
10569
10639
|
const recipientAddress = depositWallet.address;
|
|
10640
|
+
const isCheckoutMode = !!checkoutAmountUsd;
|
|
10570
10641
|
const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
|
|
10642
|
+
const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
|
|
10643
|
+
const effectiveDestinationAmount = React26.useMemo(() => {
|
|
10644
|
+
if (!checkoutRemainingBaseUnits || checkoutRemainingBaseUnits === "0") return "0";
|
|
10645
|
+
if (!checkoutAmountUsd) return checkoutRemainingBaseUnits;
|
|
10646
|
+
const remaining = BigInt(checkoutRemainingBaseUnits);
|
|
10647
|
+
const minUsd = Math.max(tokenChainDetails?.minimum_deposit_amount_usd ?? 0, 3);
|
|
10648
|
+
const totalUsd = parseFloat(checkoutAmountUsd);
|
|
10649
|
+
if (totalUsd <= 0) return remaining > 0n ? remaining.toString() : "0";
|
|
10650
|
+
const receivedUsd = parseFloat(checkoutReceivedUsd ?? "0");
|
|
10651
|
+
const remainingUsd = totalUsd - receivedUsd;
|
|
10652
|
+
if (remainingUsd <= 0) return "0";
|
|
10653
|
+
const baseUnitsPerUsd = Number(remaining) / remainingUsd;
|
|
10654
|
+
const minBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
|
|
10655
|
+
const effective = remaining > minBaseUnits ? remaining : minBaseUnits;
|
|
10656
|
+
return effective > 0n ? effective.toString() : "0";
|
|
10657
|
+
}, [checkoutRemainingBaseUnits, checkoutAmountUsd, checkoutReceivedUsd, tokenChainDetails]);
|
|
10658
|
+
const { data: walletCheckoutQuote } = useDepositQuote({
|
|
10659
|
+
publishableKey,
|
|
10660
|
+
sourceChainType: selectedToken?.chain_type ?? "",
|
|
10661
|
+
sourceChainId: selectedToken?.chain_id ?? "",
|
|
10662
|
+
sourceTokenAddress: selectedToken?.token_address ?? "",
|
|
10663
|
+
destinationAmount: effectiveDestinationAmount,
|
|
10664
|
+
destinationChainType: checkoutDestination?.chainType ?? "",
|
|
10665
|
+
destinationChainId: checkoutDestination?.chainId ?? "",
|
|
10666
|
+
destinationTokenAddress: checkoutDestination?.tokenAddress ?? "",
|
|
10667
|
+
adjustForSlippage: true,
|
|
10668
|
+
enabled: open && isCheckoutMode && !!selectedToken && !!checkoutDestination && effectiveDestinationAmount !== "0"
|
|
10669
|
+
});
|
|
10670
|
+
const activeCheckoutQuote = React26.useMemo(() => {
|
|
10671
|
+
if (!isCheckoutMode) return null;
|
|
10672
|
+
if (walletCheckoutQuote) {
|
|
10673
|
+
return {
|
|
10674
|
+
sourceAmount: walletCheckoutQuote.source_amount,
|
|
10675
|
+
sourceTokenDecimals: walletCheckoutQuote.source_token_decimals,
|
|
10676
|
+
sourceTokenSymbol: walletCheckoutQuote.source_token_symbol,
|
|
10677
|
+
sourceAmountUsd: walletCheckoutQuote.source_amount_usd,
|
|
10678
|
+
slippageBufferPercent: walletCheckoutQuote.slippage_buffer_percent ?? null
|
|
10679
|
+
};
|
|
10680
|
+
}
|
|
10681
|
+
return checkoutQuote ?? null;
|
|
10682
|
+
}, [isCheckoutMode, walletCheckoutQuote, checkoutQuote]);
|
|
10571
10683
|
const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
|
|
10572
10684
|
userId,
|
|
10573
10685
|
publishableKey,
|
|
@@ -10619,9 +10731,10 @@ function BrowserWalletModal({
|
|
|
10619
10731
|
const options = {
|
|
10620
10732
|
destination_token_address: depositWallet.destination_token_address,
|
|
10621
10733
|
destination_chain_id: depositWallet.destination_chain_id,
|
|
10622
|
-
destination_chain_type: depositWallet.destination_chain_type
|
|
10734
|
+
destination_chain_type: depositWallet.destination_chain_type,
|
|
10735
|
+
...productType ? { product_type: productType } : {}
|
|
10623
10736
|
};
|
|
10624
|
-
const response = await (0,
|
|
10737
|
+
const response = await (0, import_core23.getSupportedDepositTokens)(
|
|
10625
10738
|
publishableKey,
|
|
10626
10739
|
options
|
|
10627
10740
|
);
|
|
@@ -10658,7 +10771,7 @@ function BrowserWalletModal({
|
|
|
10658
10771
|
let cancelled = false;
|
|
10659
10772
|
setIsLoading(true);
|
|
10660
10773
|
setError(null);
|
|
10661
|
-
(0,
|
|
10774
|
+
(0, import_core23.getAddressBalances)(walletInfo.address, supportedChainType, publishableKey).then((response) => {
|
|
10662
10775
|
if (cancelled) return;
|
|
10663
10776
|
const nonZeroBalances = response.balances.filter(
|
|
10664
10777
|
(b) => b.amount !== "0"
|
|
@@ -10982,7 +11095,7 @@ function BrowserWalletModal({
|
|
|
10982
11095
|
amountInSmallestUnit = decimalToSmallestUnit(amountStr, token.decimals);
|
|
10983
11096
|
}
|
|
10984
11097
|
try {
|
|
10985
|
-
const buildResponse = await (0,
|
|
11098
|
+
const buildResponse = await (0, import_core23.buildSolanaTransaction)(
|
|
10986
11099
|
{
|
|
10987
11100
|
chain_id: "mainnet",
|
|
10988
11101
|
token_address: token.token_address === "" ? "native" : token.token_address,
|
|
@@ -11009,7 +11122,7 @@ function BrowserWalletModal({
|
|
|
11009
11122
|
binaryStr += String.fromCharCode(serialized[i]);
|
|
11010
11123
|
}
|
|
11011
11124
|
const signedTransactionBase64 = btoa(binaryStr);
|
|
11012
|
-
const sendResponse = await (0,
|
|
11125
|
+
const sendResponse = await (0, import_core23.sendSolanaTransaction)(
|
|
11013
11126
|
{
|
|
11014
11127
|
chain_id: "mainnet",
|
|
11015
11128
|
signed_transaction: signedTransactionBase64
|
|
@@ -11021,7 +11134,6 @@ function BrowserWalletModal({
|
|
|
11021
11134
|
throw error2;
|
|
11022
11135
|
}
|
|
11023
11136
|
};
|
|
11024
|
-
const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
|
|
11025
11137
|
const usdToTokenRate = React26.useMemo(() => {
|
|
11026
11138
|
if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken)
|
|
11027
11139
|
return 0;
|
|
@@ -11031,15 +11143,24 @@ function BrowserWalletModal({
|
|
|
11031
11143
|
return balanceAmount / balanceUsd;
|
|
11032
11144
|
}, [selectedBalance, selectedToken]);
|
|
11033
11145
|
const tokenAmount = React26.useMemo(() => {
|
|
11146
|
+
if (isCheckoutMode && activeCheckoutQuote && selectedToken) {
|
|
11147
|
+
return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
|
|
11148
|
+
}
|
|
11034
11149
|
const usdNum = parseFloat(amountUsd) || 0;
|
|
11035
11150
|
if (usdNum === 0 || usdToTokenRate === 0) return 0;
|
|
11036
11151
|
return usdNum * usdToTokenRate;
|
|
11037
|
-
}, [amountUsd, usdToTokenRate]);
|
|
11152
|
+
}, [amountUsd, usdToTokenRate, isCheckoutMode, activeCheckoutQuote, selectedToken]);
|
|
11153
|
+
React26.useEffect(() => {
|
|
11154
|
+
if (isCheckoutMode && activeCheckoutQuote?.sourceAmountUsd && step === "input-amount") {
|
|
11155
|
+
const quoteUsd = activeCheckoutQuote.sourceAmountUsd;
|
|
11156
|
+
setAmountUsd(quoteUsd);
|
|
11157
|
+
}
|
|
11158
|
+
}, [isCheckoutMode, activeCheckoutQuote, step]);
|
|
11038
11159
|
const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
|
|
11039
11160
|
const maxUsdAmount = selectedBalance?.amount_usd ? parseFloat(selectedBalance.amount_usd) : 0;
|
|
11040
11161
|
const inputUsdNum = parseFloat(amountUsd) || 0;
|
|
11041
11162
|
const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
|
|
11042
|
-
const isValidAmount = inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
|
|
11163
|
+
const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
|
|
11043
11164
|
const formattedTokenAmount = React26.useMemo(() => {
|
|
11044
11165
|
if (tokenAmount === 0 || !selectedToken) return null;
|
|
11045
11166
|
return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(
|
|
@@ -11954,7 +12075,7 @@ function DepositModal({
|
|
|
11954
12075
|
if (view !== "tracker" || !userId) return;
|
|
11955
12076
|
const fetchExecutions = async () => {
|
|
11956
12077
|
try {
|
|
11957
|
-
const response = await (0,
|
|
12078
|
+
const response = await (0, import_core24.queryExecutions)(userId, publishableKey, import_core24.ActionType.Deposit);
|
|
11958
12079
|
const sorted = [...response.data].sort((a, b) => {
|
|
11959
12080
|
const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
11960
12081
|
const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
|
|
@@ -12480,8 +12601,8 @@ var import_react19 = require("react");
|
|
|
12480
12601
|
var import_lucide_react24 = require("lucide-react");
|
|
12481
12602
|
|
|
12482
12603
|
// src/hooks/use-payment-intent.ts
|
|
12483
|
-
var
|
|
12484
|
-
var
|
|
12604
|
+
var import_react_query10 = require("@tanstack/react-query");
|
|
12605
|
+
var import_core25 = require("@unifold/core");
|
|
12485
12606
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
12486
12607
|
"succeeded",
|
|
12487
12608
|
"expired",
|
|
@@ -12495,9 +12616,9 @@ function usePaymentIntent(params) {
|
|
|
12495
12616
|
enabled = true,
|
|
12496
12617
|
pollingInterval = 3e3
|
|
12497
12618
|
} = params;
|
|
12498
|
-
return (0,
|
|
12619
|
+
return (0, import_react_query10.useQuery)({
|
|
12499
12620
|
queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
|
|
12500
|
-
queryFn: () => (0,
|
|
12621
|
+
queryFn: () => (0, import_core25.retrievePaymentIntent)(clientSecret, publishableKey),
|
|
12501
12622
|
enabled: enabled && !!clientSecret && !!publishableKey,
|
|
12502
12623
|
staleTime: 0,
|
|
12503
12624
|
refetchInterval: (query) => {
|
|
@@ -12512,53 +12633,6 @@ function usePaymentIntent(params) {
|
|
|
12512
12633
|
});
|
|
12513
12634
|
}
|
|
12514
12635
|
|
|
12515
|
-
// src/hooks/use-deposit-quote.ts
|
|
12516
|
-
var import_react_query10 = require("@tanstack/react-query");
|
|
12517
|
-
var import_core25 = require("@unifold/core");
|
|
12518
|
-
function useDepositQuote(params) {
|
|
12519
|
-
const {
|
|
12520
|
-
publishableKey,
|
|
12521
|
-
sourceChainType,
|
|
12522
|
-
sourceChainId,
|
|
12523
|
-
sourceTokenAddress,
|
|
12524
|
-
destinationAmount,
|
|
12525
|
-
destinationChainType,
|
|
12526
|
-
destinationChainId,
|
|
12527
|
-
destinationTokenAddress,
|
|
12528
|
-
enabled = true
|
|
12529
|
-
} = params;
|
|
12530
|
-
const request = {
|
|
12531
|
-
source_chain_type: sourceChainType,
|
|
12532
|
-
source_chain_id: sourceChainId,
|
|
12533
|
-
source_token_address: sourceTokenAddress,
|
|
12534
|
-
destination_amount: destinationAmount,
|
|
12535
|
-
destination_chain_type: destinationChainType,
|
|
12536
|
-
destination_chain_id: destinationChainId,
|
|
12537
|
-
destination_token_address: destinationTokenAddress
|
|
12538
|
-
};
|
|
12539
|
-
return (0, import_react_query10.useQuery)({
|
|
12540
|
-
queryKey: [
|
|
12541
|
-
"unifold",
|
|
12542
|
-
"depositQuote",
|
|
12543
|
-
sourceChainType,
|
|
12544
|
-
sourceChainId,
|
|
12545
|
-
sourceTokenAddress,
|
|
12546
|
-
destinationAmount,
|
|
12547
|
-
destinationChainType,
|
|
12548
|
-
destinationChainId,
|
|
12549
|
-
destinationTokenAddress,
|
|
12550
|
-
publishableKey
|
|
12551
|
-
],
|
|
12552
|
-
queryFn: () => (0, import_core25.getDepositQuote)(request, publishableKey),
|
|
12553
|
-
enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
|
|
12554
|
-
staleTime: 6e4,
|
|
12555
|
-
gcTime: 5 * 6e4,
|
|
12556
|
-
refetchOnWindowFocus: false,
|
|
12557
|
-
retry: 2,
|
|
12558
|
-
retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
|
|
12559
|
-
});
|
|
12560
|
-
}
|
|
12561
|
-
|
|
12562
12636
|
// src/components/checkout/CheckoutModal.tsx
|
|
12563
12637
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
12564
12638
|
function mapDepositAddressesToWallets(depositAddresses, pi) {
|
|
@@ -12710,6 +12784,7 @@ function CheckoutModal({
|
|
|
12710
12784
|
destinationChainType: paymentIntent?.destination_chain_type ?? "",
|
|
12711
12785
|
destinationChainId: paymentIntent?.destination_chain_id ?? "",
|
|
12712
12786
|
destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
|
|
12787
|
+
adjustForSlippage: true,
|
|
12713
12788
|
enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
|
|
12714
12789
|
});
|
|
12715
12790
|
const handleBrowserWalletClick = (0, import_react19.useCallback)(
|
|
@@ -13101,6 +13176,7 @@ function CheckoutModal({
|
|
|
13101
13176
|
depositConfirmationMode: "auto_ui",
|
|
13102
13177
|
wallets,
|
|
13103
13178
|
onSourceTokenChange: setSelectedSource,
|
|
13179
|
+
productType: "payment",
|
|
13104
13180
|
checkoutQuote: sourceQuote ? {
|
|
13105
13181
|
sourceAmount: sourceQuote.source_amount,
|
|
13106
13182
|
sourceTokenDecimals: sourceQuote.source_token_decimals,
|
|
@@ -13140,6 +13216,16 @@ function CheckoutModal({
|
|
|
13140
13216
|
prefillAmountUsd: remainingAmountUsd,
|
|
13141
13217
|
checkoutAmountUsd: paymentIntent?.amount_usd,
|
|
13142
13218
|
checkoutReceivedUsd: paymentIntent?.amount_received_usd,
|
|
13219
|
+
checkoutDestination: paymentIntent ? {
|
|
13220
|
+
chainType: paymentIntent.destination_chain_type,
|
|
13221
|
+
chainId: paymentIntent.destination_chain_id,
|
|
13222
|
+
tokenAddress: paymentIntent.destination_token_address
|
|
13223
|
+
} : void 0,
|
|
13224
|
+
productType: "payment",
|
|
13225
|
+
checkoutRemainingBaseUnits: paymentIntent ? (() => {
|
|
13226
|
+
const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
|
|
13227
|
+
return remaining > 0n ? remaining.toString() : "0";
|
|
13228
|
+
})() : void 0,
|
|
13143
13229
|
onSuccess: (txHash) => {
|
|
13144
13230
|
onCheckoutSuccess?.({
|
|
13145
13231
|
paymentIntentId: paymentIntent?.id || "",
|
package/dist/index.mjs
CHANGED
|
@@ -2531,14 +2531,14 @@ function BuyWithCard({
|
|
|
2531
2531
|
);
|
|
2532
2532
|
if (matchingCurrency) {
|
|
2533
2533
|
setCurrency(matchingCurrency.currency_code.toLowerCase());
|
|
2534
|
-
if (!amount && !hasManualAmountEntry) {
|
|
2534
|
+
if (!amount && !hasManualAmountEntry && matchingCurrency.default_amount != null) {
|
|
2535
2535
|
setAmount(matchingCurrency.default_amount.toString());
|
|
2536
2536
|
}
|
|
2537
2537
|
} else if (!amount && !hasManualAmountEntry) {
|
|
2538
2538
|
const usdCurrency = fiatCurrencies.find(
|
|
2539
2539
|
(c) => c.currency_code.toLowerCase() === "usd"
|
|
2540
2540
|
);
|
|
2541
|
-
if (usdCurrency) {
|
|
2541
|
+
if (usdCurrency?.default_amount != null) {
|
|
2542
2542
|
setAmount(usdCurrency.default_amount.toString());
|
|
2543
2543
|
}
|
|
2544
2544
|
}
|
|
@@ -2556,7 +2556,7 @@ function BuyWithCard({
|
|
|
2556
2556
|
const currentCurrency = fiatCurrencies.find(
|
|
2557
2557
|
(c) => c.currency_code.toLowerCase() === currency.toLowerCase()
|
|
2558
2558
|
);
|
|
2559
|
-
if (currentCurrency) {
|
|
2559
|
+
if (currentCurrency?.default_amount != null) {
|
|
2560
2560
|
setAmount(currentCurrency.default_amount.toString());
|
|
2561
2561
|
}
|
|
2562
2562
|
}
|
|
@@ -6586,8 +6586,11 @@ function BrowserWalletButton({
|
|
|
6586
6586
|
solanaProvider.off("accountChanged", handleAccountsChanged);
|
|
6587
6587
|
}
|
|
6588
6588
|
for (const provider of ethProviders) {
|
|
6589
|
-
provider.removeListener(
|
|
6590
|
-
|
|
6589
|
+
const off = provider.off?.bind(provider) ?? provider.removeListener?.bind(provider);
|
|
6590
|
+
if (off) {
|
|
6591
|
+
off("accountsChanged", handleEthAccountsChanged);
|
|
6592
|
+
off("chainChanged", handleAccountsChanged);
|
|
6593
|
+
}
|
|
6591
6594
|
}
|
|
6592
6595
|
};
|
|
6593
6596
|
}, [chainType, eip6963ProviderCount]);
|
|
@@ -7023,11 +7026,16 @@ import {
|
|
|
7023
7026
|
getSupportedDepositTokens
|
|
7024
7027
|
} from "@unifold/core";
|
|
7025
7028
|
function useSupportedDepositTokens(publishableKey, options) {
|
|
7026
|
-
const
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7029
|
+
const hasDestination = options?.destination_token_address && options?.destination_chain_id && options?.destination_chain_type;
|
|
7030
|
+
const filteredOptions = {
|
|
7031
|
+
...hasDestination ? {
|
|
7032
|
+
destination_token_address: options.destination_token_address,
|
|
7033
|
+
destination_chain_id: options.destination_chain_id,
|
|
7034
|
+
destination_chain_type: options.destination_chain_type
|
|
7035
|
+
} : {},
|
|
7036
|
+
...options?.product_type ? { product_type: options.product_type } : {}
|
|
7037
|
+
};
|
|
7038
|
+
const hasFilteredOptions = Object.keys(filteredOptions).length > 0;
|
|
7031
7039
|
return useQuery8({
|
|
7032
7040
|
queryKey: [
|
|
7033
7041
|
"unifold",
|
|
@@ -7035,9 +7043,13 @@ function useSupportedDepositTokens(publishableKey, options) {
|
|
|
7035
7043
|
publishableKey,
|
|
7036
7044
|
filteredOptions?.destination_token_address ?? null,
|
|
7037
7045
|
filteredOptions?.destination_chain_id ?? null,
|
|
7038
|
-
filteredOptions?.destination_chain_type ?? null
|
|
7046
|
+
filteredOptions?.destination_chain_type ?? null,
|
|
7047
|
+
filteredOptions?.product_type ?? null
|
|
7039
7048
|
],
|
|
7040
|
-
queryFn: () => getSupportedDepositTokens(
|
|
7049
|
+
queryFn: () => getSupportedDepositTokens(
|
|
7050
|
+
publishableKey,
|
|
7051
|
+
hasFilteredOptions ? filteredOptions : void 0
|
|
7052
|
+
),
|
|
7041
7053
|
staleTime: 1e3 * 60 * 5,
|
|
7042
7054
|
// 5 minutes — token list rarely changes
|
|
7043
7055
|
gcTime: 1e3 * 60 * 30,
|
|
@@ -8328,7 +8340,8 @@ function TransferCryptoSingleInput({
|
|
|
8328
8340
|
onDepositError,
|
|
8329
8341
|
wallets: externalWallets,
|
|
8330
8342
|
onSourceTokenChange,
|
|
8331
|
-
checkoutQuote
|
|
8343
|
+
checkoutQuote,
|
|
8344
|
+
productType
|
|
8332
8345
|
}) {
|
|
8333
8346
|
const { themeClass, colors: colors2, fonts, components } = useTheme();
|
|
8334
8347
|
const isDarkMode = themeClass.includes("uf-dark");
|
|
@@ -8341,7 +8354,8 @@ function TransferCryptoSingleInput({
|
|
|
8341
8354
|
const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
|
|
8342
8355
|
destination_token_address: destinationTokenAddress,
|
|
8343
8356
|
destination_chain_id: destinationChainId,
|
|
8344
|
-
destination_chain_type: destinationChainType
|
|
8357
|
+
destination_chain_type: destinationChainType,
|
|
8358
|
+
product_type: productType
|
|
8345
8359
|
});
|
|
8346
8360
|
const supportedTokens = tokensResponse?.data ?? [];
|
|
8347
8361
|
const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
|
|
@@ -9414,6 +9428,60 @@ import {
|
|
|
9414
9428
|
sendSolanaTransaction as sendSolanaTransactionToBackend
|
|
9415
9429
|
} from "@unifold/core";
|
|
9416
9430
|
|
|
9431
|
+
// src/hooks/use-deposit-quote.ts
|
|
9432
|
+
import { useQuery as useQuery9 } from "@tanstack/react-query";
|
|
9433
|
+
import {
|
|
9434
|
+
getDepositQuote
|
|
9435
|
+
} from "@unifold/core";
|
|
9436
|
+
function useDepositQuote(params) {
|
|
9437
|
+
const {
|
|
9438
|
+
publishableKey,
|
|
9439
|
+
sourceChainType,
|
|
9440
|
+
sourceChainId,
|
|
9441
|
+
sourceTokenAddress,
|
|
9442
|
+
destinationAmount,
|
|
9443
|
+
destinationChainType,
|
|
9444
|
+
destinationChainId,
|
|
9445
|
+
destinationTokenAddress,
|
|
9446
|
+
adjustForSlippage,
|
|
9447
|
+
enabled = true
|
|
9448
|
+
} = params;
|
|
9449
|
+
const request = {
|
|
9450
|
+
source_chain_type: sourceChainType,
|
|
9451
|
+
source_chain_id: sourceChainId,
|
|
9452
|
+
source_token_address: sourceTokenAddress,
|
|
9453
|
+
destination_amount: destinationAmount,
|
|
9454
|
+
destination_chain_type: destinationChainType,
|
|
9455
|
+
destination_chain_id: destinationChainId,
|
|
9456
|
+
destination_token_address: destinationTokenAddress,
|
|
9457
|
+
...adjustForSlippage ? { adjust_for_slippage: true } : {}
|
|
9458
|
+
};
|
|
9459
|
+
return useQuery9({
|
|
9460
|
+
queryKey: [
|
|
9461
|
+
"unifold",
|
|
9462
|
+
"depositQuote",
|
|
9463
|
+
sourceChainType,
|
|
9464
|
+
sourceChainId,
|
|
9465
|
+
sourceTokenAddress,
|
|
9466
|
+
destinationAmount,
|
|
9467
|
+
destinationChainType,
|
|
9468
|
+
destinationChainId,
|
|
9469
|
+
destinationTokenAddress,
|
|
9470
|
+
adjustForSlippage,
|
|
9471
|
+
publishableKey
|
|
9472
|
+
],
|
|
9473
|
+
queryFn: () => getDepositQuote(request, publishableKey),
|
|
9474
|
+
enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
|
|
9475
|
+
staleTime: 3e4,
|
|
9476
|
+
gcTime: 5 * 6e4,
|
|
9477
|
+
refetchInterval: 3e4,
|
|
9478
|
+
refetchIntervalInBackground: false,
|
|
9479
|
+
refetchOnWindowFocus: true,
|
|
9480
|
+
retry: 2,
|
|
9481
|
+
retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
|
|
9482
|
+
});
|
|
9483
|
+
}
|
|
9484
|
+
|
|
9417
9485
|
// src/components/deposits/browser-wallets/types.ts
|
|
9418
9486
|
var BROWSER_WALLET_STEP_MIN_HEIGHT_CLASS = "uf-min-h-[460px]";
|
|
9419
9487
|
|
|
@@ -9902,7 +9970,7 @@ function EnterAmountView({
|
|
|
9902
9970
|
}
|
|
9903
9971
|
)
|
|
9904
9972
|
] }) }),
|
|
9905
|
-
tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd &&
|
|
9973
|
+
tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && tokenChainDetails.minimum_deposit_amount_usd > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ jsxs39(
|
|
9906
9974
|
"div",
|
|
9907
9975
|
{
|
|
9908
9976
|
className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
|
|
@@ -10516,7 +10584,11 @@ function BrowserWalletModal({
|
|
|
10516
10584
|
checkoutReceivedUsd,
|
|
10517
10585
|
onNewDeposit,
|
|
10518
10586
|
onDone,
|
|
10519
|
-
paymentIntentStatus
|
|
10587
|
+
paymentIntentStatus,
|
|
10588
|
+
checkoutQuote,
|
|
10589
|
+
checkoutDestination,
|
|
10590
|
+
checkoutRemainingBaseUnits,
|
|
10591
|
+
productType
|
|
10520
10592
|
}) {
|
|
10521
10593
|
const { colors: colors2, fonts, components } = useTheme();
|
|
10522
10594
|
const [step, setStep] = React26.useState("select-token");
|
|
@@ -10538,7 +10610,49 @@ function BrowserWalletModal({
|
|
|
10538
10610
|
const themeClass = theme === "dark" ? "uf-dark" : "";
|
|
10539
10611
|
const chainType = depositWallet.chain_type;
|
|
10540
10612
|
const recipientAddress = depositWallet.address;
|
|
10613
|
+
const isCheckoutMode = !!checkoutAmountUsd;
|
|
10541
10614
|
const supportedChainType = chainType === "algorand" || chainType === "xrpl" ? "ethereum" : chainType;
|
|
10615
|
+
const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
|
|
10616
|
+
const effectiveDestinationAmount = React26.useMemo(() => {
|
|
10617
|
+
if (!checkoutRemainingBaseUnits || checkoutRemainingBaseUnits === "0") return "0";
|
|
10618
|
+
if (!checkoutAmountUsd) return checkoutRemainingBaseUnits;
|
|
10619
|
+
const remaining = BigInt(checkoutRemainingBaseUnits);
|
|
10620
|
+
const minUsd = Math.max(tokenChainDetails?.minimum_deposit_amount_usd ?? 0, 3);
|
|
10621
|
+
const totalUsd = parseFloat(checkoutAmountUsd);
|
|
10622
|
+
if (totalUsd <= 0) return remaining > 0n ? remaining.toString() : "0";
|
|
10623
|
+
const receivedUsd = parseFloat(checkoutReceivedUsd ?? "0");
|
|
10624
|
+
const remainingUsd = totalUsd - receivedUsd;
|
|
10625
|
+
if (remainingUsd <= 0) return "0";
|
|
10626
|
+
const baseUnitsPerUsd = Number(remaining) / remainingUsd;
|
|
10627
|
+
const minBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
|
|
10628
|
+
const effective = remaining > minBaseUnits ? remaining : minBaseUnits;
|
|
10629
|
+
return effective > 0n ? effective.toString() : "0";
|
|
10630
|
+
}, [checkoutRemainingBaseUnits, checkoutAmountUsd, checkoutReceivedUsd, tokenChainDetails]);
|
|
10631
|
+
const { data: walletCheckoutQuote } = useDepositQuote({
|
|
10632
|
+
publishableKey,
|
|
10633
|
+
sourceChainType: selectedToken?.chain_type ?? "",
|
|
10634
|
+
sourceChainId: selectedToken?.chain_id ?? "",
|
|
10635
|
+
sourceTokenAddress: selectedToken?.token_address ?? "",
|
|
10636
|
+
destinationAmount: effectiveDestinationAmount,
|
|
10637
|
+
destinationChainType: checkoutDestination?.chainType ?? "",
|
|
10638
|
+
destinationChainId: checkoutDestination?.chainId ?? "",
|
|
10639
|
+
destinationTokenAddress: checkoutDestination?.tokenAddress ?? "",
|
|
10640
|
+
adjustForSlippage: true,
|
|
10641
|
+
enabled: open && isCheckoutMode && !!selectedToken && !!checkoutDestination && effectiveDestinationAmount !== "0"
|
|
10642
|
+
});
|
|
10643
|
+
const activeCheckoutQuote = React26.useMemo(() => {
|
|
10644
|
+
if (!isCheckoutMode) return null;
|
|
10645
|
+
if (walletCheckoutQuote) {
|
|
10646
|
+
return {
|
|
10647
|
+
sourceAmount: walletCheckoutQuote.source_amount,
|
|
10648
|
+
sourceTokenDecimals: walletCheckoutQuote.source_token_decimals,
|
|
10649
|
+
sourceTokenSymbol: walletCheckoutQuote.source_token_symbol,
|
|
10650
|
+
sourceAmountUsd: walletCheckoutQuote.source_amount_usd,
|
|
10651
|
+
slippageBufferPercent: walletCheckoutQuote.slippage_buffer_percent ?? null
|
|
10652
|
+
};
|
|
10653
|
+
}
|
|
10654
|
+
return checkoutQuote ?? null;
|
|
10655
|
+
}, [isCheckoutMode, walletCheckoutQuote, checkoutQuote]);
|
|
10542
10656
|
const { executions: depositExecutions, isPolling, handleIveDeposited } = useDepositPolling({
|
|
10543
10657
|
userId,
|
|
10544
10658
|
publishableKey,
|
|
@@ -10590,7 +10704,8 @@ function BrowserWalletModal({
|
|
|
10590
10704
|
const options = {
|
|
10591
10705
|
destination_token_address: depositWallet.destination_token_address,
|
|
10592
10706
|
destination_chain_id: depositWallet.destination_chain_id,
|
|
10593
|
-
destination_chain_type: depositWallet.destination_chain_type
|
|
10707
|
+
destination_chain_type: depositWallet.destination_chain_type,
|
|
10708
|
+
...productType ? { product_type: productType } : {}
|
|
10594
10709
|
};
|
|
10595
10710
|
const response = await getSupportedDepositTokens2(
|
|
10596
10711
|
publishableKey,
|
|
@@ -10992,7 +11107,6 @@ function BrowserWalletModal({
|
|
|
10992
11107
|
throw error2;
|
|
10993
11108
|
}
|
|
10994
11109
|
};
|
|
10995
|
-
const selectedToken = selectedBalance ? getTokenFromBalance(selectedBalance) : null;
|
|
10996
11110
|
const usdToTokenRate = React26.useMemo(() => {
|
|
10997
11111
|
if (!selectedBalance || !selectedBalance.amount_usd || !selectedToken)
|
|
10998
11112
|
return 0;
|
|
@@ -11002,15 +11116,24 @@ function BrowserWalletModal({
|
|
|
11002
11116
|
return balanceAmount / balanceUsd;
|
|
11003
11117
|
}, [selectedBalance, selectedToken]);
|
|
11004
11118
|
const tokenAmount = React26.useMemo(() => {
|
|
11119
|
+
if (isCheckoutMode && activeCheckoutQuote && selectedToken) {
|
|
11120
|
+
return Number(activeCheckoutQuote.sourceAmount) / 10 ** activeCheckoutQuote.sourceTokenDecimals;
|
|
11121
|
+
}
|
|
11005
11122
|
const usdNum = parseFloat(amountUsd) || 0;
|
|
11006
11123
|
if (usdNum === 0 || usdToTokenRate === 0) return 0;
|
|
11007
11124
|
return usdNum * usdToTokenRate;
|
|
11008
|
-
}, [amountUsd, usdToTokenRate]);
|
|
11125
|
+
}, [amountUsd, usdToTokenRate, isCheckoutMode, activeCheckoutQuote, selectedToken]);
|
|
11126
|
+
React26.useEffect(() => {
|
|
11127
|
+
if (isCheckoutMode && activeCheckoutQuote?.sourceAmountUsd && step === "input-amount") {
|
|
11128
|
+
const quoteUsd = activeCheckoutQuote.sourceAmountUsd;
|
|
11129
|
+
setAmountUsd(quoteUsd);
|
|
11130
|
+
}
|
|
11131
|
+
}, [isCheckoutMode, activeCheckoutQuote, step]);
|
|
11009
11132
|
const maxTokenAmount = selectedBalance && selectedToken ? Number(selectedBalance.amount) / 10 ** selectedToken.decimals : 0;
|
|
11010
11133
|
const maxUsdAmount = selectedBalance?.amount_usd ? parseFloat(selectedBalance.amount_usd) : 0;
|
|
11011
11134
|
const inputUsdNum = parseFloat(amountUsd) || 0;
|
|
11012
11135
|
const minDepositUsd = tokenChainDetails?.minimum_deposit_amount_usd || 0;
|
|
11013
|
-
const isValidAmount = inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
|
|
11136
|
+
const isValidAmount = isCheckoutMode && activeCheckoutQuote ? tokenAmount > 0 && tokenAmount <= maxTokenAmount : inputUsdNum > 0 && inputUsdNum <= maxUsdAmount && inputUsdNum >= minDepositUsd;
|
|
11014
11137
|
const formattedTokenAmount = React26.useMemo(() => {
|
|
11015
11138
|
if (tokenAmount === 0 || !selectedToken) return null;
|
|
11016
11139
|
return `${tokenAmount.toFixed(6)} ${selectedToken.symbol}`.replace(
|
|
@@ -12458,7 +12581,7 @@ import {
|
|
|
12458
12581
|
import { AlertTriangle as AlertTriangle2, ChevronRight as ChevronRight12 } from "lucide-react";
|
|
12459
12582
|
|
|
12460
12583
|
// src/hooks/use-payment-intent.ts
|
|
12461
|
-
import { useQuery as
|
|
12584
|
+
import { useQuery as useQuery10 } from "@tanstack/react-query";
|
|
12462
12585
|
import { retrievePaymentIntent } from "@unifold/core";
|
|
12463
12586
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
12464
12587
|
"succeeded",
|
|
@@ -12473,7 +12596,7 @@ function usePaymentIntent(params) {
|
|
|
12473
12596
|
enabled = true,
|
|
12474
12597
|
pollingInterval = 3e3
|
|
12475
12598
|
} = params;
|
|
12476
|
-
return
|
|
12599
|
+
return useQuery10({
|
|
12477
12600
|
queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
|
|
12478
12601
|
queryFn: () => retrievePaymentIntent(clientSecret, publishableKey),
|
|
12479
12602
|
enabled: enabled && !!clientSecret && !!publishableKey,
|
|
@@ -12490,55 +12613,6 @@ function usePaymentIntent(params) {
|
|
|
12490
12613
|
});
|
|
12491
12614
|
}
|
|
12492
12615
|
|
|
12493
|
-
// src/hooks/use-deposit-quote.ts
|
|
12494
|
-
import { useQuery as useQuery10 } from "@tanstack/react-query";
|
|
12495
|
-
import {
|
|
12496
|
-
getDepositQuote
|
|
12497
|
-
} from "@unifold/core";
|
|
12498
|
-
function useDepositQuote(params) {
|
|
12499
|
-
const {
|
|
12500
|
-
publishableKey,
|
|
12501
|
-
sourceChainType,
|
|
12502
|
-
sourceChainId,
|
|
12503
|
-
sourceTokenAddress,
|
|
12504
|
-
destinationAmount,
|
|
12505
|
-
destinationChainType,
|
|
12506
|
-
destinationChainId,
|
|
12507
|
-
destinationTokenAddress,
|
|
12508
|
-
enabled = true
|
|
12509
|
-
} = params;
|
|
12510
|
-
const request = {
|
|
12511
|
-
source_chain_type: sourceChainType,
|
|
12512
|
-
source_chain_id: sourceChainId,
|
|
12513
|
-
source_token_address: sourceTokenAddress,
|
|
12514
|
-
destination_amount: destinationAmount,
|
|
12515
|
-
destination_chain_type: destinationChainType,
|
|
12516
|
-
destination_chain_id: destinationChainId,
|
|
12517
|
-
destination_token_address: destinationTokenAddress
|
|
12518
|
-
};
|
|
12519
|
-
return useQuery10({
|
|
12520
|
-
queryKey: [
|
|
12521
|
-
"unifold",
|
|
12522
|
-
"depositQuote",
|
|
12523
|
-
sourceChainType,
|
|
12524
|
-
sourceChainId,
|
|
12525
|
-
sourceTokenAddress,
|
|
12526
|
-
destinationAmount,
|
|
12527
|
-
destinationChainType,
|
|
12528
|
-
destinationChainId,
|
|
12529
|
-
destinationTokenAddress,
|
|
12530
|
-
publishableKey
|
|
12531
|
-
],
|
|
12532
|
-
queryFn: () => getDepositQuote(request, publishableKey),
|
|
12533
|
-
enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
|
|
12534
|
-
staleTime: 6e4,
|
|
12535
|
-
gcTime: 5 * 6e4,
|
|
12536
|
-
refetchOnWindowFocus: false,
|
|
12537
|
-
retry: 2,
|
|
12538
|
-
retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
|
|
12539
|
-
});
|
|
12540
|
-
}
|
|
12541
|
-
|
|
12542
12616
|
// src/components/checkout/CheckoutModal.tsx
|
|
12543
12617
|
import { Fragment as Fragment10, jsx as jsx52, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
12544
12618
|
function mapDepositAddressesToWallets(depositAddresses, pi) {
|
|
@@ -12690,6 +12764,7 @@ function CheckoutModal({
|
|
|
12690
12764
|
destinationChainType: paymentIntent?.destination_chain_type ?? "",
|
|
12691
12765
|
destinationChainId: paymentIntent?.destination_chain_id ?? "",
|
|
12692
12766
|
destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
|
|
12767
|
+
adjustForSlippage: true,
|
|
12693
12768
|
enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
|
|
12694
12769
|
});
|
|
12695
12770
|
const handleBrowserWalletClick = useCallback5(
|
|
@@ -13081,6 +13156,7 @@ function CheckoutModal({
|
|
|
13081
13156
|
depositConfirmationMode: "auto_ui",
|
|
13082
13157
|
wallets,
|
|
13083
13158
|
onSourceTokenChange: setSelectedSource,
|
|
13159
|
+
productType: "payment",
|
|
13084
13160
|
checkoutQuote: sourceQuote ? {
|
|
13085
13161
|
sourceAmount: sourceQuote.source_amount,
|
|
13086
13162
|
sourceTokenDecimals: sourceQuote.source_token_decimals,
|
|
@@ -13120,6 +13196,16 @@ function CheckoutModal({
|
|
|
13120
13196
|
prefillAmountUsd: remainingAmountUsd,
|
|
13121
13197
|
checkoutAmountUsd: paymentIntent?.amount_usd,
|
|
13122
13198
|
checkoutReceivedUsd: paymentIntent?.amount_received_usd,
|
|
13199
|
+
checkoutDestination: paymentIntent ? {
|
|
13200
|
+
chainType: paymentIntent.destination_chain_type,
|
|
13201
|
+
chainId: paymentIntent.destination_chain_id,
|
|
13202
|
+
tokenAddress: paymentIntent.destination_token_address
|
|
13203
|
+
} : void 0,
|
|
13204
|
+
productType: "payment",
|
|
13205
|
+
checkoutRemainingBaseUnits: paymentIntent ? (() => {
|
|
13206
|
+
const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
|
|
13207
|
+
return remaining > 0n ? remaining.toString() : "0";
|
|
13208
|
+
})() : void 0,
|
|
13123
13209
|
onSuccess: (txHash) => {
|
|
13124
13210
|
onCheckoutSuccess?.({
|
|
13125
13211
|
paymentIntentId: paymentIntent?.id || "",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unifold/ui-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
4
4
|
"description": "Unifold UI React - Deposit and onramp components for React applications",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"lucide-react": "^0.454.0",
|
|
35
35
|
"qr-code-styling": "^1.6.0-rc.1",
|
|
36
36
|
"tailwind-merge": "^2.0.0",
|
|
37
|
-
"@unifold/core": "0.1.
|
|
37
|
+
"@unifold/core": "0.1.53"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@solana/web3.js": "^1.87.0",
|