@b3dotfun/sdk 0.1.63-alpha.6 → 0.1.63
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/cjs/anyspend/react/components/AnySpend.d.ts +0 -2
- package/dist/cjs/anyspend/react/components/AnySpend.js +7 -24
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +4 -3
- package/dist/cjs/anyspend/react/components/AnySpendDeposit.js +1 -1
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +0 -19
- package/dist/cjs/anyspend/react/components/common/PaymentStripeWeb2.js +2 -2
- package/dist/esm/anyspend/react/components/AnySpend.d.ts +0 -2
- package/dist/esm/anyspend/react/components/AnySpend.js +8 -25
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +4 -3
- package/dist/esm/anyspend/react/components/AnySpendDeposit.js +1 -1
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +0 -19
- package/dist/esm/anyspend/react/components/common/PaymentStripeWeb2.js +2 -2
- package/dist/types/anyspend/react/components/AnySpend.d.ts +0 -2
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpend.tsx +6 -29
- package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +4 -3
- package/src/anyspend/react/components/AnySpendDeposit.tsx +0 -1
- package/src/anyspend/react/components/common/OrderDetails.tsx +0 -19
- package/src/anyspend/react/components/common/PaymentStripeWeb2.tsx +2 -2
|
@@ -51,6 +51,4 @@ export declare function AnySpend(props: {
|
|
|
51
51
|
classes?: AnySpendClasses;
|
|
52
52
|
/** When true, allows direct transfer without swap if source and destination token/chain are the same */
|
|
53
53
|
allowDirectTransfer?: boolean;
|
|
54
|
-
/** Fixed destination token amount (in wei/smallest unit). When provided, user cannot change the amount. */
|
|
55
|
-
destinationTokenAmount?: string;
|
|
56
54
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -61,7 +61,7 @@ function AnySpend(props) {
|
|
|
61
61
|
console.log("[mitch] AnySpend rendered with fingerprintConfig:", props, fingerprintConfig);
|
|
62
62
|
return ((0, jsx_runtime_1.jsx)(AnySpendFingerprintWrapper_1.AnySpendFingerprintWrapper, { fingerprint: fingerprintConfig, children: (0, jsx_runtime_1.jsx)(AnySpendInner, { ...props }) }));
|
|
63
63
|
}
|
|
64
|
-
function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationTokenChainId, mode = "modal", defaultActiveTab = "crypto", loadOrder, hideTransactionHistoryButton, recipientAddress: recipientAddressFromProps, onTokenSelect, onSuccess, customUsdInputValues, hideHeader, hideBottomNavigation = false, disableUrlParamManagement = false, returnToHomeUrl, customRecipientLabel, returnHomeLabel, classes, allowDirectTransfer = false,
|
|
64
|
+
function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationTokenChainId, mode = "modal", defaultActiveTab = "crypto", loadOrder, hideTransactionHistoryButton, recipientAddress: recipientAddressFromProps, onTokenSelect, onSuccess, customUsdInputValues, hideHeader, hideBottomNavigation = false, disableUrlParamManagement = false, returnToHomeUrl, customRecipientLabel, returnHomeLabel, classes, allowDirectTransfer = false, }) {
|
|
65
65
|
const searchParams = (0, react_2.useSearchParamsSSR)();
|
|
66
66
|
const router = (0, react_2.useRouter)();
|
|
67
67
|
const { partnerId } = (0, react_2.useB3Config)();
|
|
@@ -197,17 +197,6 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
197
197
|
(0, react_4.useEffect)(() => {
|
|
198
198
|
appliedDstMetadataRef.current = false;
|
|
199
199
|
}, [selectedDstToken.address, selectedDstToken.chainId]);
|
|
200
|
-
// Prefill destination amount if provided (for fixed amount mode)
|
|
201
|
-
const appliedDestinationAmount = (0, react_4.useRef)(false);
|
|
202
|
-
(0, react_4.useEffect)(() => {
|
|
203
|
-
// Only apply when we have real metadata (not default decimals)
|
|
204
|
-
if (destinationTokenAmount && dstTokenMetadata?.decimals && !appliedDestinationAmount.current) {
|
|
205
|
-
appliedDestinationAmount.current = true;
|
|
206
|
-
const formattedAmount = (0, viem_1.formatUnits)(BigInt(destinationTokenAmount), dstTokenMetadata.decimals);
|
|
207
|
-
setDstAmount(formattedAmount);
|
|
208
|
-
setIsSrcInputDirty(false); // Switch to EXACT_OUTPUT mode
|
|
209
|
-
}
|
|
210
|
-
}, [destinationTokenAmount, dstTokenMetadata]);
|
|
211
200
|
// Load swap configuration from URL on initial render
|
|
212
201
|
(0, react_4.useEffect)(() => {
|
|
213
202
|
// Skip if we've already processed the URL, if we have an order to load, or if URL param management is disabled
|
|
@@ -468,12 +457,9 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
468
457
|
anyspendQuote.data.currencyOut?.amount &&
|
|
469
458
|
anyspendQuote.data.currencyOut?.currency?.decimals) {
|
|
470
459
|
if (isSrcInputDirty) {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
475
|
-
setDstAmount((0, number_1.formatTokenAmount)(BigInt(amount), decimals, 6, false));
|
|
476
|
-
}
|
|
460
|
+
const amount = anyspendQuote.data.currencyOut.amount;
|
|
461
|
+
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
462
|
+
setDstAmount((0, number_1.formatTokenAmount)(BigInt(amount), decimals, 6, false));
|
|
477
463
|
}
|
|
478
464
|
else {
|
|
479
465
|
const amount = anyspendQuote.data.currencyIn.amount;
|
|
@@ -483,16 +469,13 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
483
469
|
}
|
|
484
470
|
else {
|
|
485
471
|
if (isSrcInputDirty) {
|
|
486
|
-
|
|
487
|
-
if (!destinationTokenAmount) {
|
|
488
|
-
setDstAmount("");
|
|
489
|
-
}
|
|
472
|
+
setDstAmount("");
|
|
490
473
|
}
|
|
491
474
|
else {
|
|
492
475
|
setSrcAmount("");
|
|
493
476
|
}
|
|
494
477
|
}
|
|
495
|
-
}, [anyspendQuote, isSrcInputDirty
|
|
478
|
+
}, [anyspendQuote, isSrcInputDirty]);
|
|
496
479
|
(0, react_4.useEffect)(() => {
|
|
497
480
|
if (oat?.data?.order.status === "executed" && !onSuccessCalled.current) {
|
|
498
481
|
console.log("Calling onSuccess");
|
|
@@ -921,7 +904,7 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
921
904
|
}, children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) })), activeTab === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: isBuyMode, effectiveRecipientAddress: effectiveRecipientAddress, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward"), dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
|
|
922
905
|
setIsSrcInputDirty(false);
|
|
923
906
|
setDstAmount(value);
|
|
924
|
-
},
|
|
907
|
+
}, anyspendQuote: isDirectTransfer ? undefined : anyspendQuote, onShowPointsDetail: isDirectTransfer ? undefined : () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: isDirectTransfer ? undefined : () => navigateToPanel(PanelView.FEE_DETAIL, "forward") }))] }), gasPriceData && !isLoadingGas && activeTab === "crypto" && !isDirectTransfer && ((0, jsx_runtime_1.jsx)(GasIndicator_1.GasIndicator, { gasPrice: gasPriceData, className: classes?.gasIndicator || "mt-2 w-full" })), (0, jsx_runtime_1.jsxs)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: [(0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (btnInfo.error && classes?.mainButtonError) ||
|
|
925
908
|
(btnInfo.disable && classes?.mainButtonDisabled) ||
|
|
926
909
|
classes?.mainButton ||
|
|
927
910
|
(0, cn_1.cn)("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: (0, cn_1.cn)(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }), !hideTransactionHistoryButton && (globalAddress || effectiveRecipientAddress) ? ((0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "link", onClick: onClickHistory, className: classes?.historyButton ||
|
|
@@ -83,13 +83,14 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
83
83
|
// Prefill destination amount if provided (for EXACT_OUTPUT mode)
|
|
84
84
|
const appliedDestinationAmount = (0, react_4.useRef)(false);
|
|
85
85
|
(0, react_4.useEffect)(() => {
|
|
86
|
-
if (destinationTokenAmount &&
|
|
86
|
+
if (destinationTokenAmount && !appliedDestinationAmount.current) {
|
|
87
87
|
appliedDestinationAmount.current = true;
|
|
88
|
+
// Convert wei to human-readable format
|
|
88
89
|
const formattedAmount = (0, number_1.formatUnits)(destinationTokenAmount, destinationToken.decimals);
|
|
89
90
|
setDstAmountInput(formattedAmount);
|
|
90
91
|
setIsSrcInputDirty(false); // Switch to EXACT_OUTPUT mode
|
|
91
92
|
}
|
|
92
|
-
}, [destinationTokenAmount, destinationToken, setDstAmountInput, setIsSrcInputDirty]);
|
|
93
|
+
}, [destinationTokenAmount, destinationToken.decimals, setDstAmountInput, setIsSrcInputDirty]);
|
|
93
94
|
const selectedRecipientOrDefault = selectedRecipientAddress ?? recipientAddress;
|
|
94
95
|
const expectedDstAmountRaw = anyspendQuote?.data?.currencyOut?.amount ?? "0";
|
|
95
96
|
const buildCustomPayload = (_recipient) => {
|
|
@@ -229,7 +230,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
229
230
|
const headerContent = header ? (header({ anyspendPrice: anyspendQuote, isLoadingAnyspendPrice: isLoadingAnyspendQuote })) : ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-as-primary text-xl font-bold", children: actionLabel }), (0, jsx_runtime_1.jsx)("p", { className: "text-as-secondary text-sm", children: "Pay from any token to execute a custom exact-in transaction." })] }) }));
|
|
230
231
|
const mainView = ((0, jsx_runtime_1.jsxs)("div", { className: classes?.container ||
|
|
231
232
|
"anyspend-custom-exact-in-container mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [headerContent, (0, jsx_runtime_1.jsx)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [paymentType === "crypto" ? ((0, jsx_runtime_1.jsx)(CryptoPaySection_1.CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(useAnyspendFlow_1.PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : ((0, jsx_runtime_1.jsx)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: (0, jsx_runtime_1.jsx)(PanelOnramp_1.PanelOnramp, { srcAmountOnRamp: srcAmount, setSrcAmountOnRamp: setSrcAmount, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: selectedRecipientOrDefault, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, hideDstToken: true, destinationAmount: dstAmount, onDestinationTokenChange: () => { }, onDestinationChainChange: () => { }, fiatPaymentMethodIndex: useAnyspendFlow_1.PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(useAnyspendFlow_1.PanelView.FEE_DETAIL), customUsdInputValues: customUsdInputValues, customRecipientLabel: customRecipientLabel }) })), (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: (0, jsx_runtime_1.jsx)(react_2.Button, { variant: "ghost", className: classes?.swapDirectionButton ||
|
|
232
|
-
"swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: false, effectiveRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => setActivePanel(useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION), dstAmount: isSrcInputDirty
|
|
233
|
+
"swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: false, effectiveRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => setActivePanel(useAnyspendFlow_1.PanelView.RECIPIENT_SELECTION), dstAmount: isSrcInputDirty ? dstAmount : dstAmountInput, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
|
|
233
234
|
setIsSrcInputDirty(false);
|
|
234
235
|
setDstAmountInput(value);
|
|
235
236
|
}, disableAmountInput: !!destinationTokenAmount, anyspendQuote: isDirectTransfer ? undefined : anyspendQuote, onShowPointsDetail: isDirectTransfer ? undefined : () => setActivePanel(useAnyspendFlow_1.PanelView.POINTS_DETAIL), onShowFeeDetail: isDirectTransfer ? undefined : () => setActivePanel(useAnyspendFlow_1.PanelView.FEE_DETAIL) }))] }) }), (0, jsx_runtime_1.jsx)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: (0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (btnInfo.error && classes?.mainButtonError) ||
|
|
@@ -209,5 +209,5 @@ function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, paymentT
|
|
|
209
209
|
// Deposit view
|
|
210
210
|
return ((0, jsx_runtime_1.jsxs)("div", { className: depositClasses?.form || "anyspend-deposit anyspend-deposit-form relative", children: [shouldShowChainSelection && ((0, jsx_runtime_1.jsxs)("button", { onClick: handleBack, className: depositClasses?.backButton ||
|
|
211
211
|
"anyspend-deposit-back-button text-as-secondary hover:text-as-primary absolute left-4 top-4 z-10 flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("svg", { className: depositClasses?.backIcon || "anyspend-deposit-back-icon h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }), (0, jsx_runtime_1.jsx)("span", { className: depositClasses?.backText || "anyspend-deposit-back-text text-sm", children: "Back" })] })), onClose && ((0, jsx_runtime_1.jsx)("button", { onClick: onClose, className: depositClasses?.closeButton ||
|
|
212
|
-
"anyspend-deposit-close-button text-as-secondary hover:text-as-primary absolute right-4 top-4 z-10", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })), (0, jsx_runtime_1.jsx)("div", { className: depositClasses?.formContent || (0, cn_1.cn)("anyspend-deposit-form-content", shouldShowChainSelection && "pt-8"), children: isCustomDeposit ? ((0, jsx_runtime_1.jsx)(AnySpendCustomExactIn_1.AnySpendCustomExactIn, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, paymentType: paymentType, sourceTokenAddress: sourceTokenAddress, sourceTokenChainId: selectedChainId, destinationToken: destinationToken, destinationChainId: destinationTokenChainId, orderType: effectiveOrderType, minDestinationAmount: minDestinationAmount, header: header ?? defaultHeader, onSuccess: onSuccess, onOpenCustomModal: onOpenCustomModal, mainFooter: mainFooter, onTokenSelect: onTokenSelect, customUsdInputValues: customUsdInputValues, preferEoa: preferEoa, customExactInConfig: depositContractConfig, returnToHomeUrl: returnToHomeUrl, customRecipientLabel: customRecipientLabel, returnHomeLabel: returnHomeLabel, classes: classes?.customExactIn, allowDirectTransfer: allowDirectTransfer, destinationTokenAmount: destinationTokenAmount }, selectedChainId)) : ((0, jsx_runtime_1.jsx)(AnySpend_1.AnySpend, { loadOrder: loadOrder, mode: mode, defaultActiveTab: paymentType, recipientAddress: recipientAddress, sourceChainId: selectedChainId, destinationTokenAddress: destinationTokenAddress, destinationTokenChainId: destinationTokenChainId, onSuccess: txHash => onSuccess?.(txHash ?? ""), onTokenSelect: onTokenSelect, customUsdInputValues: customUsdInputValues, hideHeader: true, hideBottomNavigation: true, disableUrlParamManagement: true, returnToHomeUrl: returnToHomeUrl, customRecipientLabel: customRecipientLabel, returnHomeLabel: returnHomeLabel, classes: classes?.anySpend, allowDirectTransfer: allowDirectTransfer
|
|
212
|
+
"anyspend-deposit-close-button text-as-secondary hover:text-as-primary absolute right-4 top-4 z-10", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })), (0, jsx_runtime_1.jsx)("div", { className: depositClasses?.formContent || (0, cn_1.cn)("anyspend-deposit-form-content", shouldShowChainSelection && "pt-8"), children: isCustomDeposit ? ((0, jsx_runtime_1.jsx)(AnySpendCustomExactIn_1.AnySpendCustomExactIn, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, paymentType: paymentType, sourceTokenAddress: sourceTokenAddress, sourceTokenChainId: selectedChainId, destinationToken: destinationToken, destinationChainId: destinationTokenChainId, orderType: effectiveOrderType, minDestinationAmount: minDestinationAmount, header: header ?? defaultHeader, onSuccess: onSuccess, onOpenCustomModal: onOpenCustomModal, mainFooter: mainFooter, onTokenSelect: onTokenSelect, customUsdInputValues: customUsdInputValues, preferEoa: preferEoa, customExactInConfig: depositContractConfig, returnToHomeUrl: returnToHomeUrl, customRecipientLabel: customRecipientLabel, returnHomeLabel: returnHomeLabel, classes: classes?.customExactIn, allowDirectTransfer: allowDirectTransfer, destinationTokenAmount: destinationTokenAmount }, selectedChainId)) : ((0, jsx_runtime_1.jsx)(AnySpend_1.AnySpend, { loadOrder: loadOrder, mode: mode, defaultActiveTab: paymentType, recipientAddress: recipientAddress, sourceChainId: selectedChainId, destinationTokenAddress: destinationTokenAddress, destinationTokenChainId: destinationTokenChainId, onSuccess: txHash => onSuccess?.(txHash ?? ""), onTokenSelect: onTokenSelect, customUsdInputValues: customUsdInputValues, hideHeader: true, hideBottomNavigation: true, disableUrlParamManagement: true, returnToHomeUrl: returnToHomeUrl, customRecipientLabel: customRecipientLabel, returnHomeLabel: returnHomeLabel, classes: classes?.anySpend, allowDirectTransfer: allowDirectTransfer }, selectedChainId)) }), (0, jsx_runtime_1.jsx)(WarningText_1.ChainWarningText, { chainId: destinationTokenChainId, classes: classes?.chainWarningText || { root: "px-4 pb-4" } })] }));
|
|
213
213
|
}
|
|
@@ -351,25 +351,6 @@ exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal",
|
|
|
351
351
|
handlePayment();
|
|
352
352
|
}
|
|
353
353
|
}, [isPayableState, isComponentReady, handlePayment]);
|
|
354
|
-
// Auto-redirect to redirectUrl when order is executed (for onramp orders)
|
|
355
|
-
(0, react_5.useEffect)(() => {
|
|
356
|
-
if (order.status === "executed" && order.onrampMetadata?.redirectUrl) {
|
|
357
|
-
const baseUrl = order.onrampMetadata.redirectUrl;
|
|
358
|
-
try {
|
|
359
|
-
const url = new URL(baseUrl);
|
|
360
|
-
// Prevent Open Redirect vulnerabilities by ensuring the protocol is http or https
|
|
361
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
362
|
-
console.error(`Attempted redirect to a URL with an invalid protocol: ${url.protocol}`);
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
const redirectUrl = `${baseUrl.replace(/\/$/, "")}/${order.id}`;
|
|
366
|
-
window.location.href = redirectUrl;
|
|
367
|
-
}
|
|
368
|
-
catch (error) {
|
|
369
|
-
console.error("Invalid redirect URL provided:", baseUrl, error);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}, [order.status, order.onrampMetadata?.redirectUrl, order.id]);
|
|
373
354
|
if (!srcToken || !dstToken) {
|
|
374
355
|
return (0, jsx_runtime_1.jsx)("div", { children: "Loading..." });
|
|
375
356
|
}
|
|
@@ -95,9 +95,9 @@ function StripePaymentForm({ order, clientSecret, onPaymentSuccess, }) {
|
|
|
95
95
|
}
|
|
96
96
|
// At this point TypeScript knows result.paymentIntent exists and error is undefined
|
|
97
97
|
console.log("@@stripe-web2-payment:success:", JSON.stringify({ orderId: order.id, paymentIntentId: result.paymentIntent.id }, null, 2));
|
|
98
|
-
// Payment succeeded
|
|
98
|
+
// Payment succeeded without redirect - handle success in the modal
|
|
99
99
|
setMessage(null);
|
|
100
|
-
//
|
|
100
|
+
// Add waitingForDeposit=true to query params
|
|
101
101
|
const currentUrl = new URL(window.location.href);
|
|
102
102
|
currentUrl.searchParams.set("waitingForDeposit", "true");
|
|
103
103
|
window.history.replaceState(null, "", currentUrl.toString());
|
|
@@ -51,6 +51,4 @@ export declare function AnySpend(props: {
|
|
|
51
51
|
classes?: AnySpendClasses;
|
|
52
52
|
/** When true, allows direct transfer without swap if source and destination token/chain are the same */
|
|
53
53
|
allowDirectTransfer?: boolean;
|
|
54
|
-
/** Fixed destination token amount (in wei/smallest unit). When provided, user cannot change the amount. */
|
|
55
|
-
destinationTokenAmount?: string;
|
|
56
54
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -12,7 +12,7 @@ import invariant from "invariant";
|
|
|
12
12
|
import { ArrowDown, CheckCircle, HistoryIcon, Loader2 } from "lucide-react";
|
|
13
13
|
import { motion } from "motion/react";
|
|
14
14
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
15
|
-
import {
|
|
15
|
+
import { parseUnits } from "viem";
|
|
16
16
|
import { base, mainnet } from "viem/chains";
|
|
17
17
|
import { useAutoSelectCryptoPaymentMethod } from "../hooks/useAutoSelectCryptoPaymentMethod.js";
|
|
18
18
|
import { useConnectedWalletDisplay } from "../hooks/useConnectedWalletDisplay.js";
|
|
@@ -54,7 +54,7 @@ export function AnySpend(props) {
|
|
|
54
54
|
console.log("[mitch] AnySpend rendered with fingerprintConfig:", props, fingerprintConfig);
|
|
55
55
|
return (_jsx(AnySpendFingerprintWrapper, { fingerprint: fingerprintConfig, children: _jsx(AnySpendInner, { ...props }) }));
|
|
56
56
|
}
|
|
57
|
-
function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationTokenChainId, mode = "modal", defaultActiveTab = "crypto", loadOrder, hideTransactionHistoryButton, recipientAddress: recipientAddressFromProps, onTokenSelect, onSuccess, customUsdInputValues, hideHeader, hideBottomNavigation = false, disableUrlParamManagement = false, returnToHomeUrl, customRecipientLabel, returnHomeLabel, classes, allowDirectTransfer = false,
|
|
57
|
+
function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationTokenChainId, mode = "modal", defaultActiveTab = "crypto", loadOrder, hideTransactionHistoryButton, recipientAddress: recipientAddressFromProps, onTokenSelect, onSuccess, customUsdInputValues, hideHeader, hideBottomNavigation = false, disableUrlParamManagement = false, returnToHomeUrl, customRecipientLabel, returnHomeLabel, classes, allowDirectTransfer = false, }) {
|
|
58
58
|
const searchParams = useSearchParamsSSR();
|
|
59
59
|
const router = useRouter();
|
|
60
60
|
const { partnerId } = useB3Config();
|
|
@@ -190,17 +190,6 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
190
190
|
useEffect(() => {
|
|
191
191
|
appliedDstMetadataRef.current = false;
|
|
192
192
|
}, [selectedDstToken.address, selectedDstToken.chainId]);
|
|
193
|
-
// Prefill destination amount if provided (for fixed amount mode)
|
|
194
|
-
const appliedDestinationAmount = useRef(false);
|
|
195
|
-
useEffect(() => {
|
|
196
|
-
// Only apply when we have real metadata (not default decimals)
|
|
197
|
-
if (destinationTokenAmount && dstTokenMetadata?.decimals && !appliedDestinationAmount.current) {
|
|
198
|
-
appliedDestinationAmount.current = true;
|
|
199
|
-
const formattedAmount = formatUnits(BigInt(destinationTokenAmount), dstTokenMetadata.decimals);
|
|
200
|
-
setDstAmount(formattedAmount);
|
|
201
|
-
setIsSrcInputDirty(false); // Switch to EXACT_OUTPUT mode
|
|
202
|
-
}
|
|
203
|
-
}, [destinationTokenAmount, dstTokenMetadata]);
|
|
204
193
|
// Load swap configuration from URL on initial render
|
|
205
194
|
useEffect(() => {
|
|
206
195
|
// Skip if we've already processed the URL, if we have an order to load, or if URL param management is disabled
|
|
@@ -461,12 +450,9 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
461
450
|
anyspendQuote.data.currencyOut?.amount &&
|
|
462
451
|
anyspendQuote.data.currencyOut?.currency?.decimals) {
|
|
463
452
|
if (isSrcInputDirty) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
468
|
-
setDstAmount(formatTokenAmount(BigInt(amount), decimals, 6, false));
|
|
469
|
-
}
|
|
453
|
+
const amount = anyspendQuote.data.currencyOut.amount;
|
|
454
|
+
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
455
|
+
setDstAmount(formatTokenAmount(BigInt(amount), decimals, 6, false));
|
|
470
456
|
}
|
|
471
457
|
else {
|
|
472
458
|
const amount = anyspendQuote.data.currencyIn.amount;
|
|
@@ -476,16 +462,13 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
476
462
|
}
|
|
477
463
|
else {
|
|
478
464
|
if (isSrcInputDirty) {
|
|
479
|
-
|
|
480
|
-
if (!destinationTokenAmount) {
|
|
481
|
-
setDstAmount("");
|
|
482
|
-
}
|
|
465
|
+
setDstAmount("");
|
|
483
466
|
}
|
|
484
467
|
else {
|
|
485
468
|
setSrcAmount("");
|
|
486
469
|
}
|
|
487
470
|
}
|
|
488
|
-
}, [anyspendQuote, isSrcInputDirty
|
|
471
|
+
}, [anyspendQuote, isSrcInputDirty]);
|
|
489
472
|
useEffect(() => {
|
|
490
473
|
if (oat?.data?.order.status === "executed" && !onSuccessCalled.current) {
|
|
491
474
|
console.log("Calling onSuccess");
|
|
@@ -914,7 +897,7 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
|
|
|
914
897
|
}, children: _jsx("div", { className: "relative flex items-center justify-center transition-opacity", children: _jsx(ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) })), activeTab === "crypto" && (_jsx(CryptoReceiveSection, { isDepositMode: false, isBuyMode: isBuyMode, effectiveRecipientAddress: effectiveRecipientAddress, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward"), dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
|
|
915
898
|
setIsSrcInputDirty(false);
|
|
916
899
|
setDstAmount(value);
|
|
917
|
-
},
|
|
900
|
+
}, anyspendQuote: isDirectTransfer ? undefined : anyspendQuote, onShowPointsDetail: isDirectTransfer ? undefined : () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), onShowFeeDetail: isDirectTransfer ? undefined : () => navigateToPanel(PanelView.FEE_DETAIL, "forward") }))] }), gasPriceData && !isLoadingGas && activeTab === "crypto" && !isDirectTransfer && (_jsx(GasIndicator, { gasPrice: gasPriceData, className: classes?.gasIndicator || "mt-2 w-full" })), _jsxs(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: cn("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: [_jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (btnInfo.error && classes?.mainButtonError) ||
|
|
918
901
|
(btnInfo.disable && classes?.mainButtonDisabled) ||
|
|
919
902
|
classes?.mainButton ||
|
|
920
903
|
cn("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: cn(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: _jsxs("div", { className: "flex items-center justify-center gap-2", children: [btnInfo.loading && _jsx(Loader2, { className: "h-4 w-4 animate-spin" }), btnInfo.text] }) }), !hideTransactionHistoryButton && (globalAddress || effectiveRecipientAddress) ? (_jsxs(Button, { variant: "link", onClick: onClickHistory, className: classes?.historyButton ||
|
|
@@ -77,13 +77,14 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
77
77
|
// Prefill destination amount if provided (for EXACT_OUTPUT mode)
|
|
78
78
|
const appliedDestinationAmount = useRef(false);
|
|
79
79
|
useEffect(() => {
|
|
80
|
-
if (destinationTokenAmount &&
|
|
80
|
+
if (destinationTokenAmount && !appliedDestinationAmount.current) {
|
|
81
81
|
appliedDestinationAmount.current = true;
|
|
82
|
+
// Convert wei to human-readable format
|
|
82
83
|
const formattedAmount = formatUnits(destinationTokenAmount, destinationToken.decimals);
|
|
83
84
|
setDstAmountInput(formattedAmount);
|
|
84
85
|
setIsSrcInputDirty(false); // Switch to EXACT_OUTPUT mode
|
|
85
86
|
}
|
|
86
|
-
}, [destinationTokenAmount, destinationToken, setDstAmountInput, setIsSrcInputDirty]);
|
|
87
|
+
}, [destinationTokenAmount, destinationToken.decimals, setDstAmountInput, setIsSrcInputDirty]);
|
|
87
88
|
const selectedRecipientOrDefault = selectedRecipientAddress ?? recipientAddress;
|
|
88
89
|
const expectedDstAmountRaw = anyspendQuote?.data?.currencyOut?.amount ?? "0";
|
|
89
90
|
const buildCustomPayload = (_recipient) => {
|
|
@@ -223,7 +224,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
|
|
|
223
224
|
const headerContent = header ? (header({ anyspendPrice: anyspendQuote, isLoadingAnyspendPrice: isLoadingAnyspendQuote })) : (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsxs("div", { children: [_jsx("h1", { className: "text-as-primary text-xl font-bold", children: actionLabel }), _jsx("p", { className: "text-as-secondary text-sm", children: "Pay from any token to execute a custom exact-in transaction." })] }) }));
|
|
224
225
|
const mainView = (_jsxs("div", { className: classes?.container ||
|
|
225
226
|
"anyspend-custom-exact-in-container mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [headerContent, _jsx("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [paymentType === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : (_jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: _jsx(PanelOnramp, { srcAmountOnRamp: srcAmount, setSrcAmountOnRamp: setSrcAmount, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: selectedRecipientOrDefault, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, hideDstToken: true, destinationAmount: dstAmount, onDestinationTokenChange: () => { }, onDestinationChainChange: () => { }, fiatPaymentMethodIndex: PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: PanelView.RECIPIENT_SELECTION, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(PanelView.FEE_DETAIL), customUsdInputValues: customUsdInputValues, customRecipientLabel: customRecipientLabel }) })), _jsx("div", { className: cn("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: _jsx(Button, { variant: "ghost", className: classes?.swapDirectionButton ||
|
|
226
|
-
"swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", children: _jsx("div", { className: "relative flex items-center justify-center transition-opacity", children: _jsx(ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && (_jsx(CryptoReceiveSection, { isDepositMode: false, isBuyMode: false, effectiveRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => setActivePanel(PanelView.RECIPIENT_SELECTION), dstAmount: isSrcInputDirty
|
|
227
|
+
"swap-direction-button border-as-stroke bg-as-surface-primary z-10 h-10 w-10 cursor-default rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", children: _jsx("div", { className: "relative flex items-center justify-center transition-opacity", children: _jsx(ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }) }), paymentType === "crypto" && (_jsx(CryptoReceiveSection, { isDepositMode: false, isBuyMode: false, effectiveRecipientAddress: selectedRecipientOrDefault, recipientName: recipientName || undefined, customRecipientLabel: customRecipientLabel, onSelectRecipient: () => setActivePanel(PanelView.RECIPIENT_SELECTION), dstAmount: isSrcInputDirty ? dstAmount : dstAmountInput, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
|
|
227
228
|
setIsSrcInputDirty(false);
|
|
228
229
|
setDstAmountInput(value);
|
|
229
230
|
}, disableAmountInput: !!destinationTokenAmount, anyspendQuote: isDirectTransfer ? undefined : anyspendQuote, onShowPointsDetail: isDirectTransfer ? undefined : () => setActivePanel(PanelView.POINTS_DETAIL), onShowFeeDetail: isDirectTransfer ? undefined : () => setActivePanel(PanelView.FEE_DETAIL) }))] }) }), _jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: cn("mt-4 flex w-full max-w-[460px] flex-col gap-2"), children: _jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (btnInfo.error && classes?.mainButtonError) ||
|
|
@@ -206,5 +206,5 @@ export function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, p
|
|
|
206
206
|
// Deposit view
|
|
207
207
|
return (_jsxs("div", { className: depositClasses?.form || "anyspend-deposit anyspend-deposit-form relative", children: [shouldShowChainSelection && (_jsxs("button", { onClick: handleBack, className: depositClasses?.backButton ||
|
|
208
208
|
"anyspend-deposit-back-button text-as-secondary hover:text-as-primary absolute left-4 top-4 z-10 flex items-center gap-1", children: [_jsx("svg", { className: depositClasses?.backIcon || "anyspend-deposit-back-icon h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }), _jsx("span", { className: depositClasses?.backText || "anyspend-deposit-back-text text-sm", children: "Back" })] })), onClose && (_jsx("button", { onClick: onClose, className: depositClasses?.closeButton ||
|
|
209
|
-
"anyspend-deposit-close-button text-as-secondary hover:text-as-primary absolute right-4 top-4 z-10", children: _jsx("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })), _jsx("div", { className: depositClasses?.formContent || cn("anyspend-deposit-form-content", shouldShowChainSelection && "pt-8"), children: isCustomDeposit ? (_jsx(AnySpendCustomExactIn, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, paymentType: paymentType, sourceTokenAddress: sourceTokenAddress, sourceTokenChainId: selectedChainId, destinationToken: destinationToken, destinationChainId: destinationTokenChainId, orderType: effectiveOrderType, minDestinationAmount: minDestinationAmount, header: header ?? defaultHeader, onSuccess: onSuccess, onOpenCustomModal: onOpenCustomModal, mainFooter: mainFooter, onTokenSelect: onTokenSelect, customUsdInputValues: customUsdInputValues, preferEoa: preferEoa, customExactInConfig: depositContractConfig, returnToHomeUrl: returnToHomeUrl, customRecipientLabel: customRecipientLabel, returnHomeLabel: returnHomeLabel, classes: classes?.customExactIn, allowDirectTransfer: allowDirectTransfer, destinationTokenAmount: destinationTokenAmount }, selectedChainId)) : (_jsx(AnySpend, { loadOrder: loadOrder, mode: mode, defaultActiveTab: paymentType, recipientAddress: recipientAddress, sourceChainId: selectedChainId, destinationTokenAddress: destinationTokenAddress, destinationTokenChainId: destinationTokenChainId, onSuccess: txHash => onSuccess?.(txHash ?? ""), onTokenSelect: onTokenSelect, customUsdInputValues: customUsdInputValues, hideHeader: true, hideBottomNavigation: true, disableUrlParamManagement: true, returnToHomeUrl: returnToHomeUrl, customRecipientLabel: customRecipientLabel, returnHomeLabel: returnHomeLabel, classes: classes?.anySpend, allowDirectTransfer: allowDirectTransfer
|
|
209
|
+
"anyspend-deposit-close-button text-as-secondary hover:text-as-primary absolute right-4 top-4 z-10", children: _jsx("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })), _jsx("div", { className: depositClasses?.formContent || cn("anyspend-deposit-form-content", shouldShowChainSelection && "pt-8"), children: isCustomDeposit ? (_jsx(AnySpendCustomExactIn, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, paymentType: paymentType, sourceTokenAddress: sourceTokenAddress, sourceTokenChainId: selectedChainId, destinationToken: destinationToken, destinationChainId: destinationTokenChainId, orderType: effectiveOrderType, minDestinationAmount: minDestinationAmount, header: header ?? defaultHeader, onSuccess: onSuccess, onOpenCustomModal: onOpenCustomModal, mainFooter: mainFooter, onTokenSelect: onTokenSelect, customUsdInputValues: customUsdInputValues, preferEoa: preferEoa, customExactInConfig: depositContractConfig, returnToHomeUrl: returnToHomeUrl, customRecipientLabel: customRecipientLabel, returnHomeLabel: returnHomeLabel, classes: classes?.customExactIn, allowDirectTransfer: allowDirectTransfer, destinationTokenAmount: destinationTokenAmount }, selectedChainId)) : (_jsx(AnySpend, { loadOrder: loadOrder, mode: mode, defaultActiveTab: paymentType, recipientAddress: recipientAddress, sourceChainId: selectedChainId, destinationTokenAddress: destinationTokenAddress, destinationTokenChainId: destinationTokenChainId, onSuccess: txHash => onSuccess?.(txHash ?? ""), onTokenSelect: onTokenSelect, customUsdInputValues: customUsdInputValues, hideHeader: true, hideBottomNavigation: true, disableUrlParamManagement: true, returnToHomeUrl: returnToHomeUrl, customRecipientLabel: customRecipientLabel, returnHomeLabel: returnHomeLabel, classes: classes?.anySpend, allowDirectTransfer: allowDirectTransfer }, selectedChainId)) }), _jsx(ChainWarningText, { chainId: destinationTokenChainId, classes: classes?.chainWarningText || { root: "px-4 pb-4" } })] }));
|
|
210
210
|
}
|
|
@@ -345,25 +345,6 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
|
|
|
345
345
|
handlePayment();
|
|
346
346
|
}
|
|
347
347
|
}, [isPayableState, isComponentReady, handlePayment]);
|
|
348
|
-
// Auto-redirect to redirectUrl when order is executed (for onramp orders)
|
|
349
|
-
useEffect(() => {
|
|
350
|
-
if (order.status === "executed" && order.onrampMetadata?.redirectUrl) {
|
|
351
|
-
const baseUrl = order.onrampMetadata.redirectUrl;
|
|
352
|
-
try {
|
|
353
|
-
const url = new URL(baseUrl);
|
|
354
|
-
// Prevent Open Redirect vulnerabilities by ensuring the protocol is http or https
|
|
355
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
356
|
-
console.error(`Attempted redirect to a URL with an invalid protocol: ${url.protocol}`);
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
const redirectUrl = `${baseUrl.replace(/\/$/, "")}/${order.id}`;
|
|
360
|
-
window.location.href = redirectUrl;
|
|
361
|
-
}
|
|
362
|
-
catch (error) {
|
|
363
|
-
console.error("Invalid redirect URL provided:", baseUrl, error);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}, [order.status, order.onrampMetadata?.redirectUrl, order.id]);
|
|
367
348
|
if (!srcToken || !dstToken) {
|
|
368
349
|
return _jsx("div", { children: "Loading..." });
|
|
369
350
|
}
|
|
@@ -89,9 +89,9 @@ function StripePaymentForm({ order, clientSecret, onPaymentSuccess, }) {
|
|
|
89
89
|
}
|
|
90
90
|
// At this point TypeScript knows result.paymentIntent exists and error is undefined
|
|
91
91
|
console.log("@@stripe-web2-payment:success:", JSON.stringify({ orderId: order.id, paymentIntentId: result.paymentIntent.id }, null, 2));
|
|
92
|
-
// Payment succeeded
|
|
92
|
+
// Payment succeeded without redirect - handle success in the modal
|
|
93
93
|
setMessage(null);
|
|
94
|
-
//
|
|
94
|
+
// Add waitingForDeposit=true to query params
|
|
95
95
|
const currentUrl = new URL(window.location.href);
|
|
96
96
|
currentUrl.searchParams.set("waitingForDeposit", "true");
|
|
97
97
|
window.history.replaceState(null, "", currentUrl.toString());
|
|
@@ -51,6 +51,4 @@ export declare function AnySpend(props: {
|
|
|
51
51
|
classes?: AnySpendClasses;
|
|
52
52
|
/** When true, allows direct transfer without swap if source and destination token/chain are the same */
|
|
53
53
|
allowDirectTransfer?: boolean;
|
|
54
|
-
/** Fixed destination token amount (in wei/smallest unit). When provided, user cannot change the amount. */
|
|
55
|
-
destinationTokenAmount?: string;
|
|
56
54
|
}): import("react/jsx-runtime").JSX.Element;
|
package/package.json
CHANGED
|
@@ -45,7 +45,7 @@ import invariant from "invariant";
|
|
|
45
45
|
import { ArrowDown, CheckCircle, HistoryIcon, Loader2 } from "lucide-react";
|
|
46
46
|
import { motion } from "motion/react";
|
|
47
47
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
48
|
-
import {
|
|
48
|
+
import { parseUnits } from "viem";
|
|
49
49
|
import { base, mainnet } from "viem/chains";
|
|
50
50
|
import { components } from "../../types/api";
|
|
51
51
|
import { useAutoSelectCryptoPaymentMethod } from "../hooks/useAutoSelectCryptoPaymentMethod";
|
|
@@ -124,8 +124,6 @@ export function AnySpend(props: {
|
|
|
124
124
|
classes?: AnySpendClasses;
|
|
125
125
|
/** When true, allows direct transfer without swap if source and destination token/chain are the same */
|
|
126
126
|
allowDirectTransfer?: boolean;
|
|
127
|
-
/** Fixed destination token amount (in wei/smallest unit). When provided, user cannot change the amount. */
|
|
128
|
-
destinationTokenAmount?: string;
|
|
129
127
|
}) {
|
|
130
128
|
const fingerprintConfig = getFingerprintConfig();
|
|
131
129
|
|
|
@@ -157,7 +155,6 @@ function AnySpendInner({
|
|
|
157
155
|
returnHomeLabel,
|
|
158
156
|
classes,
|
|
159
157
|
allowDirectTransfer = false,
|
|
160
|
-
destinationTokenAmount,
|
|
161
158
|
}: {
|
|
162
159
|
sourceChainId?: number;
|
|
163
160
|
destinationTokenAddress?: string;
|
|
@@ -178,7 +175,6 @@ function AnySpendInner({
|
|
|
178
175
|
returnHomeLabel?: string;
|
|
179
176
|
classes?: AnySpendClasses;
|
|
180
177
|
allowDirectTransfer?: boolean;
|
|
181
|
-
destinationTokenAmount?: string;
|
|
182
178
|
}) {
|
|
183
179
|
const searchParams = useSearchParamsSSR();
|
|
184
180
|
const router = useRouter();
|
|
@@ -372,18 +368,6 @@ function AnySpendInner({
|
|
|
372
368
|
appliedDstMetadataRef.current = false;
|
|
373
369
|
}, [selectedDstToken.address, selectedDstToken.chainId]);
|
|
374
370
|
|
|
375
|
-
// Prefill destination amount if provided (for fixed amount mode)
|
|
376
|
-
const appliedDestinationAmount = useRef(false);
|
|
377
|
-
useEffect(() => {
|
|
378
|
-
// Only apply when we have real metadata (not default decimals)
|
|
379
|
-
if (destinationTokenAmount && dstTokenMetadata?.decimals && !appliedDestinationAmount.current) {
|
|
380
|
-
appliedDestinationAmount.current = true;
|
|
381
|
-
const formattedAmount = formatUnits(BigInt(destinationTokenAmount), dstTokenMetadata.decimals);
|
|
382
|
-
setDstAmount(formattedAmount);
|
|
383
|
-
setIsSrcInputDirty(false); // Switch to EXACT_OUTPUT mode
|
|
384
|
-
}
|
|
385
|
-
}, [destinationTokenAmount, dstTokenMetadata]);
|
|
386
|
-
|
|
387
371
|
// Load swap configuration from URL on initial render
|
|
388
372
|
useEffect(() => {
|
|
389
373
|
// Skip if we've already processed the URL, if we have an order to load, or if URL param management is disabled
|
|
@@ -681,12 +665,9 @@ function AnySpendInner({
|
|
|
681
665
|
anyspendQuote.data.currencyOut?.currency?.decimals
|
|
682
666
|
) {
|
|
683
667
|
if (isSrcInputDirty) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
688
|
-
setDstAmount(formatTokenAmount(BigInt(amount), decimals, 6, false));
|
|
689
|
-
}
|
|
668
|
+
const amount = anyspendQuote.data.currencyOut.amount;
|
|
669
|
+
const decimals = anyspendQuote.data.currencyOut.currency.decimals;
|
|
670
|
+
setDstAmount(formatTokenAmount(BigInt(amount), decimals, 6, false));
|
|
690
671
|
} else {
|
|
691
672
|
const amount = anyspendQuote.data.currencyIn.amount;
|
|
692
673
|
const decimals = anyspendQuote.data.currencyIn.currency.decimals;
|
|
@@ -694,15 +675,12 @@ function AnySpendInner({
|
|
|
694
675
|
}
|
|
695
676
|
} else {
|
|
696
677
|
if (isSrcInputDirty) {
|
|
697
|
-
|
|
698
|
-
if (!destinationTokenAmount) {
|
|
699
|
-
setDstAmount("");
|
|
700
|
-
}
|
|
678
|
+
setDstAmount("");
|
|
701
679
|
} else {
|
|
702
680
|
setSrcAmount("");
|
|
703
681
|
}
|
|
704
682
|
}
|
|
705
|
-
}, [anyspendQuote, isSrcInputDirty
|
|
683
|
+
}, [anyspendQuote, isSrcInputDirty]);
|
|
706
684
|
|
|
707
685
|
useEffect(() => {
|
|
708
686
|
if (oat?.data?.order.status === "executed" && !onSuccessCalled.current) {
|
|
@@ -1328,7 +1306,6 @@ function AnySpendInner({
|
|
|
1328
1306
|
setIsSrcInputDirty(false);
|
|
1329
1307
|
setDstAmount(value);
|
|
1330
1308
|
}}
|
|
1331
|
-
disableAmountInput={!!destinationTokenAmount}
|
|
1332
1309
|
anyspendQuote={isDirectTransfer ? undefined : anyspendQuote}
|
|
1333
1310
|
onShowPointsDetail={
|
|
1334
1311
|
isDirectTransfer ? undefined : () => navigateToPanel(PanelView.POINTS_DETAIL, "forward")
|
|
@@ -222,13 +222,14 @@ function AnySpendCustomExactInInner({
|
|
|
222
222
|
// Prefill destination amount if provided (for EXACT_OUTPUT mode)
|
|
223
223
|
const appliedDestinationAmount = useRef(false);
|
|
224
224
|
useEffect(() => {
|
|
225
|
-
if (destinationTokenAmount &&
|
|
225
|
+
if (destinationTokenAmount && !appliedDestinationAmount.current) {
|
|
226
226
|
appliedDestinationAmount.current = true;
|
|
227
|
+
// Convert wei to human-readable format
|
|
227
228
|
const formattedAmount = formatUnits(destinationTokenAmount, destinationToken.decimals);
|
|
228
229
|
setDstAmountInput(formattedAmount);
|
|
229
230
|
setIsSrcInputDirty(false); // Switch to EXACT_OUTPUT mode
|
|
230
231
|
}
|
|
231
|
-
}, [destinationTokenAmount, destinationToken, setDstAmountInput, setIsSrcInputDirty]);
|
|
232
|
+
}, [destinationTokenAmount, destinationToken.decimals, setDstAmountInput, setIsSrcInputDirty]);
|
|
232
233
|
|
|
233
234
|
const selectedRecipientOrDefault = selectedRecipientAddress ?? recipientAddress;
|
|
234
235
|
|
|
@@ -473,7 +474,7 @@ function AnySpendCustomExactInInner({
|
|
|
473
474
|
recipientName={recipientName || undefined}
|
|
474
475
|
customRecipientLabel={customRecipientLabel}
|
|
475
476
|
onSelectRecipient={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
|
|
476
|
-
dstAmount={isSrcInputDirty
|
|
477
|
+
dstAmount={isSrcInputDirty ? dstAmount : dstAmountInput}
|
|
477
478
|
dstToken={selectedDstToken}
|
|
478
479
|
dstTokenSymbol={DESTINATION_TOKEN_DETAILS.SYMBOL}
|
|
479
480
|
dstTokenLogoURI={DESTINATION_TOKEN_DETAILS.LOGO_URI}
|
|
@@ -493,25 +493,6 @@ export const OrderDetails = memo(function OrderDetails({
|
|
|
493
493
|
}
|
|
494
494
|
}, [isPayableState, isComponentReady, handlePayment]);
|
|
495
495
|
|
|
496
|
-
// Auto-redirect to redirectUrl when order is executed (for onramp orders)
|
|
497
|
-
useEffect(() => {
|
|
498
|
-
if (order.status === "executed" && order.onrampMetadata?.redirectUrl) {
|
|
499
|
-
const baseUrl = order.onrampMetadata.redirectUrl;
|
|
500
|
-
try {
|
|
501
|
-
const url = new URL(baseUrl);
|
|
502
|
-
// Prevent Open Redirect vulnerabilities by ensuring the protocol is http or https
|
|
503
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
504
|
-
console.error(`Attempted redirect to a URL with an invalid protocol: ${url.protocol}`);
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
const redirectUrl = `${baseUrl.replace(/\/$/, "")}/${order.id}`;
|
|
508
|
-
window.location.href = redirectUrl;
|
|
509
|
-
} catch (error) {
|
|
510
|
-
console.error("Invalid redirect URL provided:", baseUrl, error);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}, [order.status, order.onrampMetadata?.redirectUrl, order.id]);
|
|
514
|
-
|
|
515
496
|
if (!srcToken || !dstToken) {
|
|
516
497
|
return <div>Loading...</div>;
|
|
517
498
|
}
|
|
@@ -159,10 +159,10 @@ function StripePaymentForm({
|
|
|
159
159
|
JSON.stringify({ orderId: order.id, paymentIntentId: result.paymentIntent.id }, null, 2),
|
|
160
160
|
);
|
|
161
161
|
|
|
162
|
-
// Payment succeeded
|
|
162
|
+
// Payment succeeded without redirect - handle success in the modal
|
|
163
163
|
setMessage(null);
|
|
164
164
|
|
|
165
|
-
//
|
|
165
|
+
// Add waitingForDeposit=true to query params
|
|
166
166
|
const currentUrl = new URL(window.location.href);
|
|
167
167
|
currentUrl.searchParams.set("waitingForDeposit", "true");
|
|
168
168
|
window.history.replaceState(null, "", currentUrl.toString());
|