@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.
@@ -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, destinationTokenAmount, }) {
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
- // Don't override dstAmount if we have a fixed destinationTokenAmount
472
- if (!destinationTokenAmount) {
473
- const amount = anyspendQuote.data.currencyOut.amount;
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
- // Don't reset dstAmount if we have a fixed destinationTokenAmount
487
- if (!destinationTokenAmount) {
488
- setDstAmount("");
489
- }
472
+ setDstAmount("");
490
473
  }
491
474
  else {
492
475
  setSrcAmount("");
493
476
  }
494
477
  }
495
- }, [anyspendQuote, isSrcInputDirty, destinationTokenAmount]);
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
- }, disableAmountInput: !!destinationTokenAmount, 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) ||
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 && destinationToken?.decimals && !appliedDestinationAmount.current) {
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 && !destinationTokenAmount ? dstAmount : dstAmountInput, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
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, destinationTokenAmount: destinationTokenAmount }, selectedChainId)) }), (0, jsx_runtime_1.jsx)(WarningText_1.ChainWarningText, { chainId: destinationTokenChainId, classes: classes?.chainWarningText || { root: "px-4 pb-4" } })] }));
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
- // Stay on page and show waiting state (redirect will happen in OrderDetails when order is executed)
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 { formatUnits, parseUnits } from "viem";
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, destinationTokenAmount, }) {
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
- // Don't override dstAmount if we have a fixed destinationTokenAmount
465
- if (!destinationTokenAmount) {
466
- const amount = anyspendQuote.data.currencyOut.amount;
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
- // Don't reset dstAmount if we have a fixed destinationTokenAmount
480
- if (!destinationTokenAmount) {
481
- setDstAmount("");
482
- }
465
+ setDstAmount("");
483
466
  }
484
467
  else {
485
468
  setSrcAmount("");
486
469
  }
487
470
  }
488
- }, [anyspendQuote, isSrcInputDirty, destinationTokenAmount]);
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
- }, disableAmountInput: !!destinationTokenAmount, 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) ||
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 && destinationToken?.decimals && !appliedDestinationAmount.current) {
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 && !destinationTokenAmount ? dstAmount : dstAmountInput, dstToken: selectedDstToken, dstTokenSymbol: DESTINATION_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: DESTINATION_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
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, destinationTokenAmount: destinationTokenAmount }, selectedChainId)) }), _jsx(ChainWarningText, { chainId: destinationTokenChainId, classes: classes?.chainWarningText || { root: "px-4 pb-4" } })] }));
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
- // Stay on page and show waiting state (redirect will happen in OrderDetails when order is executed)
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.1.63-alpha.6",
3
+ "version": "0.1.63",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -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 { formatUnits, parseUnits } from "viem";
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
- // Don't override dstAmount if we have a fixed destinationTokenAmount
685
- if (!destinationTokenAmount) {
686
- const amount = anyspendQuote.data.currencyOut.amount;
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
- // Don't reset dstAmount if we have a fixed destinationTokenAmount
698
- if (!destinationTokenAmount) {
699
- setDstAmount("");
700
- }
678
+ setDstAmount("");
701
679
  } else {
702
680
  setSrcAmount("");
703
681
  }
704
682
  }
705
- }, [anyspendQuote, isSrcInputDirty, destinationTokenAmount]);
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 && destinationToken?.decimals && !appliedDestinationAmount.current) {
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 && !destinationTokenAmount ? dstAmount : dstAmountInput}
477
+ dstAmount={isSrcInputDirty ? dstAmount : dstAmountInput}
477
478
  dstToken={selectedDstToken}
478
479
  dstTokenSymbol={DESTINATION_TOKEN_DETAILS.SYMBOL}
479
480
  dstTokenLogoURI={DESTINATION_TOKEN_DETAILS.LOGO_URI}
@@ -719,7 +719,6 @@ export function AnySpendDeposit({
719
719
  returnHomeLabel={returnHomeLabel}
720
720
  classes={classes?.anySpend}
721
721
  allowDirectTransfer={allowDirectTransfer}
722
- destinationTokenAmount={destinationTokenAmount}
723
722
  />
724
723
  )}
725
724
  </div>
@@ -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
- // Stay on page and show waiting state (redirect will happen in OrderDetails when order is executed)
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());