@b3dotfun/sdk 0.0.62-alpha.2 → 0.0.62-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +61 -23
  2. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +3 -0
  3. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +4 -4
  4. package/dist/cjs/anyspend/react/components/common/CryptoPaySection.js +4 -6
  5. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +9 -17
  6. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.d.ts +6 -1
  7. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +11 -1
  8. package/dist/cjs/anyspend/react/components/common/OrderDetails.js +56 -145
  9. package/dist/cjs/anyspend/react/components/common/OrderTokenAmount.d.ts +2 -1
  10. package/dist/cjs/anyspend/react/components/common/OrderTokenAmount.js +39 -15
  11. package/dist/cjs/anyspend/react/components/common/PaySection.js +1 -1
  12. package/dist/cjs/anyspend/react/components/common/TokenBalance.js +1 -1
  13. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +12 -11
  14. package/dist/cjs/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.d.ts +26 -0
  15. package/dist/cjs/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.js +56 -0
  16. package/dist/cjs/anyspend/react/hooks/useAutoSetActiveWalletFromWagmi.d.ts +10 -0
  17. package/dist/cjs/anyspend/react/hooks/useAutoSetActiveWalletFromWagmi.js +73 -0
  18. package/dist/cjs/anyspend/react/hooks/useConnectedWalletDisplay.d.ts +14 -0
  19. package/dist/cjs/anyspend/react/hooks/useConnectedWalletDisplay.js +57 -0
  20. package/dist/cjs/anyspend/react/hooks/usePhantomTransfer.d.ts +36 -0
  21. package/dist/cjs/anyspend/react/hooks/usePhantomTransfer.js +211 -0
  22. package/dist/cjs/global-account/react/hooks/index.d.ts +2 -1
  23. package/dist/cjs/global-account/react/hooks/index.js +5 -3
  24. package/dist/cjs/global-account/react/hooks/useTokenBalanceDirect.d.ts +12 -0
  25. package/dist/cjs/global-account/react/hooks/useTokenBalanceDirect.js +62 -0
  26. package/dist/cjs/global-account/react/hooks/useTokenFromUrl.js +4 -3
  27. package/dist/esm/anyspend/react/components/AnySpend.js +62 -24
  28. package/dist/esm/anyspend/react/components/AnySpendCustom.js +3 -0
  29. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +4 -4
  30. package/dist/esm/anyspend/react/components/common/CryptoPaySection.js +5 -7
  31. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +9 -17
  32. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.d.ts +6 -1
  33. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +11 -1
  34. package/dist/esm/anyspend/react/components/common/OrderDetails.js +57 -146
  35. package/dist/esm/anyspend/react/components/common/OrderTokenAmount.d.ts +2 -1
  36. package/dist/esm/anyspend/react/components/common/OrderTokenAmount.js +40 -16
  37. package/dist/esm/anyspend/react/components/common/PaySection.js +1 -1
  38. package/dist/esm/anyspend/react/components/common/TokenBalance.js +2 -2
  39. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +12 -11
  40. package/dist/esm/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.d.ts +26 -0
  41. package/dist/esm/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.js +53 -0
  42. package/dist/esm/anyspend/react/hooks/useAutoSetActiveWalletFromWagmi.d.ts +10 -0
  43. package/dist/esm/anyspend/react/hooks/useAutoSetActiveWalletFromWagmi.js +70 -0
  44. package/dist/esm/anyspend/react/hooks/useConnectedWalletDisplay.d.ts +14 -0
  45. package/dist/esm/anyspend/react/hooks/useConnectedWalletDisplay.js +54 -0
  46. package/dist/esm/anyspend/react/hooks/usePhantomTransfer.d.ts +36 -0
  47. package/dist/esm/anyspend/react/hooks/usePhantomTransfer.js +208 -0
  48. package/dist/esm/global-account/react/hooks/index.d.ts +2 -1
  49. package/dist/esm/global-account/react/hooks/index.js +2 -1
  50. package/dist/esm/global-account/react/hooks/useTokenBalanceDirect.d.ts +12 -0
  51. package/dist/esm/global-account/react/hooks/useTokenBalanceDirect.js +59 -0
  52. package/dist/esm/global-account/react/hooks/useTokenFromUrl.js +4 -3
  53. package/dist/types/anyspend/react/components/common/CryptoReceiveSection.d.ts +6 -1
  54. package/dist/types/anyspend/react/components/common/OrderTokenAmount.d.ts +2 -1
  55. package/dist/types/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.d.ts +26 -0
  56. package/dist/types/anyspend/react/hooks/useAutoSetActiveWalletFromWagmi.d.ts +10 -0
  57. package/dist/types/anyspend/react/hooks/useConnectedWalletDisplay.d.ts +14 -0
  58. package/dist/types/anyspend/react/hooks/usePhantomTransfer.d.ts +36 -0
  59. package/dist/types/global-account/react/hooks/index.d.ts +2 -1
  60. package/dist/types/global-account/react/hooks/useTokenBalanceDirect.d.ts +12 -0
  61. package/package.json +1 -1
  62. package/src/anyspend/react/components/AnySpend.tsx +73 -22
  63. package/src/anyspend/react/components/AnySpendCustom.tsx +4 -0
  64. package/src/anyspend/react/components/AnyspendDepositHype.tsx +7 -3
  65. package/src/anyspend/react/components/common/CryptoPaySection.tsx +5 -7
  66. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +9 -18
  67. package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +22 -0
  68. package/src/anyspend/react/components/common/OrderDetails.tsx +66 -188
  69. package/src/anyspend/react/components/common/OrderTokenAmount.tsx +48 -17
  70. package/src/anyspend/react/components/common/PaySection.tsx +1 -0
  71. package/src/anyspend/react/components/common/TokenBalance.tsx +2 -2
  72. package/src/anyspend/react/hooks/useAnyspendFlow.ts +13 -10
  73. package/src/anyspend/react/hooks/useAutoSelectCryptoPaymentMethod.ts +72 -0
  74. package/src/anyspend/react/hooks/useAutoSetActiveWalletFromWagmi.ts +80 -0
  75. package/src/anyspend/react/hooks/useConnectedWalletDisplay.ts +69 -0
  76. package/src/anyspend/react/hooks/usePhantomTransfer.ts +301 -0
  77. package/src/global-account/react/hooks/index.ts +2 -1
  78. package/src/global-account/react/hooks/useTokenBalanceDirect.tsx +84 -0
  79. package/src/global-account/react/hooks/useTokenFromUrl.tsx +6 -5
@@ -6,6 +6,7 @@ import invariant from "invariant";
6
6
  import { motion } from "motion/react";
7
7
  import { useEffect, useMemo, useRef } from "react";
8
8
  import { toast } from "sonner";
9
+ import { useActiveWallet, useSetActiveWallet } from "thirdweb/react";
9
10
  import { base } from "viem/chains";
10
11
  import { PanelView, useAnyspendFlow } from "../hooks/useAnyspendFlow.js";
11
12
  import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper.js";
@@ -17,10 +18,9 @@ import { FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaym
17
18
  import { OrderDetails } from "./common/OrderDetails.js";
18
19
  import { PointsDetailPanel } from "./common/PointsDetailPanel.js";
19
20
  import { RecipientSelection } from "./common/RecipientSelection.js";
20
- import { useActiveWallet, useSetActiveWallet } from "thirdweb/react";
21
21
  import { ArrowDown, Loader2 } from "lucide-react";
22
- import { PanelOnramp } from "./common/PanelOnramp.js";
23
22
  import { useGlobalWalletState } from "../../utils/index.js";
23
+ import { PanelOnramp } from "./common/PanelOnramp.js";
24
24
  const SLIPPAGE_PERCENT = 3;
25
25
  export const HYPE_TOKEN_DETAILS = {
26
26
  SYMBOL: "HYPE",
@@ -128,10 +128,10 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
128
128
  await handleFiatOrder();
129
129
  }
130
130
  };
131
- const mainView = (_jsxs("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsx("div", { children: _jsx("h1", { className: "text-as-primary text-xl font-bold", children: paymentType === "crypto" ? "Deposit Crypto" : "Fund with Fiat" }) }) }), _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: selectedCryptoPaymentMethod, 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: recipientAddress, destinationToken: B3_TOKEN, destinationChainId: base.id, dstTokenSymbol: HYPE_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 }) })), _jsx("div", { className: cn("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: _jsx(Button, { variant: "ghost", className: cn("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: true, selectedRecipientAddress: recipientAddress, recipientName: recipientName || undefined, onSelectRecipient: () => setActivePanel(PanelView.RECIPIENT_SELECTION), dstAmount: dstAmount, dstToken: B3_TOKEN, dstTokenSymbol: HYPE_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: HYPE_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: base.id, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
131
+ const mainView = (_jsxs("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsx("div", { children: _jsx("h1", { className: "text-as-primary text-xl font-bold", children: paymentType === "crypto" ? "Deposit Crypto" : "Fund with Fiat" }) }) }), _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: selectedCryptoPaymentMethod, 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: recipientAddress, destinationToken: B3_TOKEN, destinationChainId: base.id, dstTokenSymbol: HYPE_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 }) })), _jsx("div", { className: cn("relative -my-1 flex h-0 items-center justify-center", paymentType === "fiat" && "hidden"), children: _jsx(Button, { variant: "ghost", className: cn("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: true, selectedRecipientAddress: selectedRecipientAddress, recipientName: recipientName || undefined, onSelectRecipient: () => setActivePanel(PanelView.RECIPIENT_SELECTION), setRecipientAddress: setSelectedRecipientAddress, recipientAddressFromProps: recipientAddress, globalAddress: globalAddress, dstAmount: dstAmount, dstToken: B3_TOKEN, dstTokenSymbol: HYPE_TOKEN_DETAILS.SYMBOL, dstTokenLogoURI: HYPE_TOKEN_DETAILS.LOGO_URI, selectedDstChainId: base.id, setSelectedDstChainId: () => { }, setSelectedDstToken: () => { }, isSrcInputDirty: isSrcInputDirty, onChangeDstAmount: value => {
132
132
  setIsSrcInputDirty(false);
133
133
  setSrcAmount(value);
134
- }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL), onShowFeeDetail: () => 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: 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] }) }) }), mainFooter ? mainFooter : null] }));
134
+ }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL), onShowFeeDetail: () => setActivePanel(PanelView.FEE_DETAIL), selectedCryptoPaymentMethod: selectedCryptoPaymentMethod }))] }) }), _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: 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] }) }) }), mainFooter ? mainFooter : null] }));
135
135
  // Handle crypto order creation
136
136
  const handleCryptoOrder = async () => {
137
137
  try {
@@ -1,21 +1,19 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useAccountWallet, useProfile, useTokenData } from "../../../../global-account/react/index.js";
2
+ import { useProfile, useTokenData } from "../../../../global-account/react/index.js";
3
3
  import { formatUsername } from "../../../../shared/utils/index.js";
4
4
  import { shortenAddress } from "../../../../shared/utils/formatAddress.js";
5
5
  import { formatDisplayNumber } from "../../../../shared/utils/number.js";
6
6
  import { ChevronRight, Info } from "lucide-react";
7
7
  import { motion } from "motion/react";
8
8
  import { useEffect, useRef } from "react";
9
+ import { useConnectedWalletDisplay } from "../../hooks/useConnectedWalletDisplay.js";
9
10
  import { CryptoPaymentMethodType } from "./CryptoPaymentMethod.js";
10
11
  import { OrderTokenAmount } from "./OrderTokenAmount.js";
11
12
  import { TokenBalance } from "./TokenBalance.js";
12
13
  export function CryptoPaySection({ selectedSrcChainId, setSelectedSrcChainId, selectedSrcToken, setSelectedSrcToken, srcAmount, setSrcAmount, isSrcInputDirty, setIsSrcInputDirty, selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod, anyspendQuote, onTokenSelect, onShowFeeDetail, }) {
13
- const { connectedSmartWallet, connectedEOAWallet } = useAccountWallet();
14
14
  const { data: srcTokenMetadata } = useTokenData(selectedSrcToken?.chainId, selectedSrcToken?.address);
15
- // Determine which address to use based on payment method
16
- const walletAddress = selectedCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET
17
- ? connectedSmartWallet?.getAccount()?.address
18
- : connectedEOAWallet?.getAccount()?.address;
15
+ // Use custom hook to determine wallet address based on payment method
16
+ const { walletAddress } = useConnectedWalletDisplay(selectedCryptoPaymentMethod);
19
17
  const { data: profileData } = useProfile({ address: walletAddress });
20
18
  const connectedName = profileData?.displayName;
21
19
  // Add ref to track if we've applied metadata
@@ -42,7 +40,7 @@ export function CryptoPaySection({ selectedSrcChainId, setSelectedSrcChainId, se
42
40
  useEffect(() => {
43
41
  appliedSrcMetadataRef.current = false;
44
42
  }, [selectedSrcToken.address, selectedSrcToken.chainId]);
45
- return (_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, ease: "easeInOut" }, className: "pay-section bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "text-as-primary/50 flex h-7 items-center gap-1.5 text-sm", children: ["Pay", !isSrcInputDirty && anyspendQuote?.data?.fee && onShowFeeDetail && (_jsx("button", { onClick: onShowFeeDetail, className: "text-as-primary/40 hover:text-as-primary/60 transition-colors", children: _jsx(Info, { className: "h-4 w-4" }) }))] }), _jsx("button", { className: "text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors focus:!outline-none", onClick: onSelectCryptoPaymentMethod, children: selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (_jsxs(_Fragment, { children: [walletAddress ? (_jsx("div", { className: "flex items-center gap-1", children: connectedName ? formatUsername(connectedName) : shortenAddress(walletAddress || "") })) : ("Connect wallet"), _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET ? (_jsxs(_Fragment, { children: ["Global Account", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (_jsxs(_Fragment, { children: ["Transfer crypto", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : (_jsxs(_Fragment, { children: ["Select payment method", _jsx(ChevronRight, { className: "h-4 w-4" })] })) })] }), _jsx(OrderTokenAmount, { address: walletAddress, context: "from", inputValue: srcAmount, onChangeInput: value => {
43
+ return (_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, ease: "easeInOut" }, className: "pay-section bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "text-as-primary/50 flex h-7 items-center gap-1.5 text-sm", children: ["Pay", !isSrcInputDirty && anyspendQuote?.data?.fee && onShowFeeDetail && (_jsx("button", { onClick: onShowFeeDetail, className: "text-as-primary/40 hover:text-as-primary/60 transition-colors", children: _jsx(Info, { className: "h-4 w-4" }) }))] }), _jsx("button", { className: "text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors focus:!outline-none", onClick: onSelectCryptoPaymentMethod, children: selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (_jsxs(_Fragment, { children: [walletAddress ? (_jsx("div", { className: "flex items-center gap-1", children: connectedName ? formatUsername(connectedName) : shortenAddress(walletAddress || "") })) : ("Connect wallet"), _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET ? (_jsxs(_Fragment, { children: ["Global Account", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (_jsxs(_Fragment, { children: ["Transfer crypto", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : (_jsxs(_Fragment, { children: ["Select payment method", _jsx(ChevronRight, { className: "h-4 w-4" })] })) })] }), _jsx(OrderTokenAmount, { address: walletAddress, walletAddress: walletAddress, context: "from", inputValue: srcAmount, onChangeInput: value => {
46
44
  setIsSrcInputDirty(true);
47
45
  setSrcAmount(value);
48
46
  }, chainId: selectedSrcChainId, setChainId: setSelectedSrcChainId, token: selectedSrcToken, setToken: setSelectedSrcToken, onTokenSelect: onTokenSelect }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-as-primary/50 flex h-5 items-center text-sm", children: formatDisplayNumber(anyspendQuote?.data?.currencyIn?.amountUsd, {
@@ -13,6 +13,7 @@ import { toast } from "sonner";
13
13
  import { useActiveWallet, useSetActiveWallet, useWalletInfo } from "thirdweb/react";
14
14
  import { createWallet } from "thirdweb/wallets";
15
15
  import { useAccount, useConnect, useDisconnect, useWalletClient } from "wagmi";
16
+ import { useConnectedWalletDisplay } from "../../hooks/useConnectedWalletDisplay.js";
16
17
  export var CryptoPaymentMethodType;
17
18
  (function (CryptoPaymentMethodType) {
18
19
  CryptoPaymentMethodType["NONE"] = "none";
@@ -22,7 +23,7 @@ export var CryptoPaymentMethodType;
22
23
  })(CryptoPaymentMethodType || (CryptoPaymentMethodType = {}));
23
24
  export function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentMethod, isCreatingOrder, onBack, onSelectPaymentMethod, }) {
24
25
  const { wallet: globalWallet, connectedEOAWallet: connectedEOAWallet, connectedSmartWallet: connectedSmartWallet, } = useAccountWallet();
25
- const { connector, address, isConnected: wagmiWalletIsConnected } = useAccount();
26
+ const { connector, address } = useAccount();
26
27
  const { connect, connectors, isPending } = useConnect();
27
28
  const { disconnect } = useDisconnect();
28
29
  const { data: walletClient } = useWalletClient();
@@ -33,19 +34,8 @@ export function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentM
33
34
  const setGlobalAccountWallet = useGlobalWalletState(state => state.setGlobalAccountWallet);
34
35
  const isConnected = !!connectedEOAWallet;
35
36
  const globalAddress = connectedSmartWallet?.getAccount()?.address;
36
- // Helper function to check if two addresses are the same
37
- const isSameAddress = (addr1, addr2) => {
38
- if (!addr1 || !addr2)
39
- return false;
40
- return addr1.toLowerCase() === addr2.toLowerCase();
41
- };
42
- // Check if connectedEOAWallet and wagmi wallet represent the same wallet
43
- const connectedEOAAddress = connectedEOAWallet?.getAccount()?.address;
44
- const wagmiAddress = address;
45
- const isWalletDuplicated = isSameAddress(connectedEOAAddress, wagmiAddress);
46
- // Determine which wallet to show (prefer connectedEOAWallet if both exist and are the same)
47
- const shouldShowConnectedEOA = !!connectedEOAWallet;
48
- const shouldShowWagmiWallet = wagmiWalletIsConnected && (!isWalletDuplicated || !connectedEOAWallet);
37
+ // Use custom hook to determine wallet display logic
38
+ const { shouldShowConnectedEOA, shouldShowWagmiWallet } = useConnectedWalletDisplay(selectedPaymentMethod);
49
39
  // Map wagmi connector names to thirdweb wallet IDs
50
40
  const getThirdwebWalletId = (connectorName) => {
51
41
  const walletMap = {
@@ -173,9 +163,11 @@ export function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentM
173
163
  setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
174
164
  onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
175
165
  setGlobalAccountWallet(activeWallet);
176
- setActiveWallet(connectedEOAWallet);
166
+ if (connectedEOAWallet) {
167
+ setActiveWallet(connectedEOAWallet);
168
+ }
177
169
  toast.success(`Selected ${eoaWalletInfo?.name || connector?.name || "wallet"}`);
178
- }, className: cn("crypto-payment-method-connect-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md", selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
170
+ }, className: cn("crypto-payment-method-connect-wallet eoa-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md", selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
179
171
  ? "connected-wallet border-as-brand bg-as-brand/5"
180
172
  : "border-as-border-secondary bg-as-surface-primary hover:border-as-secondary/80"), children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "wallet-icon flex h-10 w-10 items-center justify-center rounded-full bg-blue-100", children: _jsx(Wallet, { className: "h-5 w-5 text-blue-600" }) }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-as-primary font-semibold", children: eoaWalletInfo?.name || connector?.name || "Connected Wallet" }), _jsx("span", { className: "text-as-primary/60 text-sm", children: shortenAddress(connectedEOAWallet?.getAccount()?.address || "") })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET && (_jsx("div", { className: "h-2 w-2 rounded-full bg-green-500" })), _jsx("button", { onClick: e => {
181
173
  e.stopPropagation();
@@ -195,7 +187,7 @@ export function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentM
195
187
  }
196
188
  }
197
189
  toast.success(`Selected ${connector?.name || "wallet"}`);
198
- }, className: cn("crypto-payment-method-connect-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md", selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
190
+ }, className: cn("crypto-payment-method-connect-wallet wagmi-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md", selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
199
191
  ? "connected-wallet border-as-brand bg-as-brand/5"
200
192
  : "border-as-border-secondary bg-as-surface-primary hover:border-as-secondary/80"), children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "wallet-icon flex h-10 w-10 items-center justify-center rounded-full bg-blue-100", children: _jsx(Wallet, { className: "h-5 w-5 text-blue-600" }) }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-as-primary font-semibold", children: connector?.name || "Connected Wallet" }), _jsx("span", { className: "text-as-primary/60 text-sm", children: shortenAddress(address || "") })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET && (_jsx("div", { className: "h-2 w-2 rounded-full bg-green-500" })), _jsx("button", { onClick: e => {
201
193
  e.stopPropagation();
@@ -1,10 +1,14 @@
1
1
  import { components } from "../../../types/api";
2
+ import { CryptoPaymentMethodType } from "./CryptoPaymentMethod";
2
3
  interface CryptoReceiveSectionProps {
3
4
  isDepositMode?: boolean;
4
5
  isBuyMode?: boolean;
5
6
  selectedRecipientAddress?: string;
6
7
  recipientName?: string;
7
8
  onSelectRecipient: () => void;
9
+ setRecipientAddress?: (address: string | undefined) => void;
10
+ recipientAddressFromProps?: string;
11
+ globalAddress?: string;
8
12
  dstAmount: string;
9
13
  dstToken: components["schemas"]["Token"];
10
14
  selectedDstChainId?: number;
@@ -17,6 +21,7 @@ interface CryptoReceiveSectionProps {
17
21
  dstTokenLogoURI?: string;
18
22
  onShowPointsDetail?: () => void;
19
23
  onShowFeeDetail?: () => void;
24
+ selectedCryptoPaymentMethod?: CryptoPaymentMethodType;
20
25
  }
21
- export declare function CryptoReceiveSection({ isDepositMode, isBuyMode, selectedRecipientAddress, recipientName, onSelectRecipient, dstAmount, dstToken, selectedDstChainId, setSelectedDstChainId, setSelectedDstToken, isSrcInputDirty, onChangeDstAmount, anyspendQuote, dstTokenSymbol, dstTokenLogoURI, onShowPointsDetail, onShowFeeDetail, }: CryptoReceiveSectionProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function CryptoReceiveSection({ isDepositMode, isBuyMode, selectedRecipientAddress, recipientName, onSelectRecipient, setRecipientAddress, recipientAddressFromProps, globalAddress, dstAmount, dstToken, selectedDstChainId, setSelectedDstChainId, setSelectedDstToken, isSrcInputDirty, onChangeDstAmount, anyspendQuote, dstTokenSymbol, dstTokenLogoURI, onShowPointsDetail, onShowFeeDetail, selectedCryptoPaymentMethod, }: CryptoReceiveSectionProps): import("react/jsx-runtime").JSX.Element;
22
27
  export {};
@@ -5,11 +5,21 @@ import { shortenAddress } from "../../../../shared/utils/formatAddress.js";
5
5
  import { formatDisplayNumber } from "../../../../shared/utils/number.js";
6
6
  import { ChevronRight, Info } from "lucide-react";
7
7
  import { motion } from "motion/react";
8
+ import { useEffect } from "react";
8
9
  import { useFeatureFlags } from "../../contexts/FeatureFlagsContext.js";
10
+ import { useConnectedWalletDisplay } from "../../hooks/useConnectedWalletDisplay.js";
9
11
  import { OrderTokenAmount } from "./OrderTokenAmount.js";
10
12
  import { PointsBadge } from "./PointsBadge.js";
11
- export function CryptoReceiveSection({ isDepositMode = false, isBuyMode = false, selectedRecipientAddress, recipientName, onSelectRecipient, dstAmount, dstToken, selectedDstChainId, setSelectedDstChainId, setSelectedDstToken, isSrcInputDirty, onChangeDstAmount, anyspendQuote, dstTokenSymbol, dstTokenLogoURI, onShowPointsDetail, onShowFeeDetail, }) {
13
+ export function CryptoReceiveSection({ isDepositMode = false, isBuyMode = false, selectedRecipientAddress, recipientName, onSelectRecipient, setRecipientAddress, recipientAddressFromProps, globalAddress, dstAmount, dstToken, selectedDstChainId, setSelectedDstChainId, setSelectedDstToken, isSrcInputDirty, onChangeDstAmount, anyspendQuote, dstTokenSymbol, dstTokenLogoURI, onShowPointsDetail, onShowFeeDetail, selectedCryptoPaymentMethod, }) {
12
14
  const featureFlags = useFeatureFlags();
15
+ // Get wallet address based on selected payment method
16
+ const { walletAddress } = useConnectedWalletDisplay(selectedCryptoPaymentMethod);
17
+ // Set default recipient address when wallet changes
18
+ useEffect(() => {
19
+ if (setRecipientAddress) {
20
+ setRecipientAddress(recipientAddressFromProps || walletAddress || globalAddress);
21
+ }
22
+ }, [recipientAddressFromProps, walletAddress, globalAddress, setRecipientAddress]);
13
23
  return (_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.1, ease: "easeInOut" }, className: "receive-section bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6", children: [_jsxs("div", { className: "flex w-full items-center justify-between", children: [_jsxs("div", { className: "text-as-primary/50 flex h-7 items-center gap-1.5 text-sm", children: [isDepositMode ? "Deposit" : "Receive", isSrcInputDirty && anyspendQuote?.data?.fee && onShowFeeDetail && (_jsx("button", { onClick: onShowFeeDetail, className: "text-as-primary/40 hover:text-as-primary/60 transition-colors", children: _jsx(Info, { className: "h-4 w-4" }) }))] }), selectedRecipientAddress ? (_jsx("button", { className: cn("text-as-tertiarry flex h-7 items-center gap-2 rounded-lg"), onClick: onSelectRecipient, children: _jsxs(_Fragment, { children: [_jsx("span", { className: "text-as-tertiarry flex items-center gap-1 text-sm", children: recipientName ? formatUsername(recipientName) : shortenAddress(selectedRecipientAddress || "") }), _jsx(ChevronRight, { className: "h-4 w-4" })] }) })) : (_jsx("button", { className: "text-as-primary/70 flex items-center gap-1 rounded-lg", onClick: onSelectRecipient, children: _jsx("div", { className: "text-sm font-medium", children: "Select recipient" }) }))] }), isBuyMode || isDepositMode ? (
14
24
  // Fixed destination token display for buy mode and deposit mode
15
25
  _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-as-primary text-2xl font-bold", children: dstAmount || "0" }), _jsxs("div", { className: "bg-as-brand/10 border-as-brand/30 flex items-center gap-3 rounded-xl border px-4 py-3", children: [(dstTokenLogoURI || dstToken.metadata?.logoURI) && (_jsx("img", { src: dstTokenLogoURI || dstToken.metadata?.logoURI, alt: dstTokenSymbol || dstToken.symbol, className: "h-8 w-8 rounded-full" })), _jsx("span", { className: "text-as-brand text-lg font-bold", children: dstTokenSymbol || dstToken.symbol })] })] })) : (
@@ -6,18 +6,17 @@ import { useRouter, useSearchParams } from "../../../../shared/react/hooks/index
6
6
  import { cn } from "../../../../shared/utils/index.js";
7
7
  import centerTruncate from "../../../../shared/utils/centerTruncate.js";
8
8
  import { formatTokenAmount } from "../../../../shared/utils/number.js";
9
- import { createAssociatedTokenAccountInstruction, createTransferCheckedInstruction, getAssociatedTokenAddressSync, } from "@solana/spl-token";
10
- import { ComputeBudgetProgram, Connection, PublicKey, SystemProgram, Transaction } from "@solana/web3.js";
11
9
  import { WalletCoinbase, WalletMetamask, WalletPhantom, WalletTrust, WalletWalletConnect } from "@web3icons/react";
12
10
  import { CheckIcon, ChevronRight, Copy, ExternalLink, Home, Loader2, RefreshCcw } from "lucide-react";
13
11
  import { motion } from "motion/react";
14
12
  import { QRCodeSVG } from "qrcode.react";
15
- import { memo, useCallback, useEffect, useMemo, useState } from "react";
13
+ import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
16
14
  import TimeAgo from "react-timeago";
17
15
  import { toast } from "sonner";
18
16
  import { encodeFunctionData, erc20Abi } from "viem";
19
17
  import { b3 } from "viem/chains";
20
18
  import { useWaitForTransactionReceipt, useWalletClient } from "wagmi";
19
+ import { usePhantomTransfer } from "../../hooks/usePhantomTransfer.js";
21
20
  import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "./Accordion.js";
22
21
  import ConnectWalletPayment from "./ConnectWalletPayment.js";
23
22
  import { CryptoPaymentMethodType } from "./CryptoPaymentMethod.js";
@@ -149,6 +148,10 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
149
148
  const [showQRCode, setShowQRCode] = useState(false);
150
149
  const { isLoading: txLoading, isSuccess: txSuccess } = useWaitForTransactionReceipt({ hash: txHash });
151
150
  const { switchChainAndExecuteWithEOA, switchChainAndExecute, isSwitchingOrExecuting } = useUnifiedChainSwitchAndExecute();
151
+ // Track if auto-payment was attempted to avoid re-triggering
152
+ const autoPaymentAttempted = useRef(false);
153
+ // Track if component is ready for auto-payment (all data loaded)
154
+ const [isComponentReady, setIsComponentReady] = useState(false);
152
155
  const roundedUpSrcAmount = useMemo(() => {
153
156
  // Display the full transfer amount without rounding since users need to see the exact value they're transferring.
154
157
  // Use 21 significant digits (max allowed by Intl.NumberFormat)
@@ -204,19 +207,25 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
204
207
  setTxHash(txHash);
205
208
  }
206
209
  }, [order, switchChainAndExecuteWithEOA, switchChainAndExecute, depositDeficit, effectiveCryptoPaymentMethod]);
210
+ // Use Phantom transfer hook for Solana payments
211
+ const { initiateTransfer: initiatePhantomTransfer, getConnectedAddress: getPhantomAddress } = usePhantomTransfer();
207
212
  // Main payment handler that triggers chain switch and payment
208
- const handlePayment = async () => {
213
+ const handlePayment = useCallback(async () => {
209
214
  console.log("Initiating payment process. Target chain:", order.srcChain, "Current chain:", walletClient?.chain?.id);
210
215
  if (order.srcChain === RELAY_SOLANA_MAINNET_CHAIN_ID) {
211
216
  // Use the existing depositDeficit calculation to determine amount to send
212
217
  const amountToSend = depositDeficit > BigInt(0) ? depositDeficit.toString() : order.srcAmount;
213
- await initiatePhantomTransfer(amountToSend, order.srcTokenAddress, order.globalAddress);
218
+ await initiatePhantomTransfer({
219
+ amountLamports: amountToSend,
220
+ tokenAddress: order.srcTokenAddress,
221
+ recipientAddress: order.globalAddress,
222
+ });
214
223
  }
215
224
  else {
216
225
  // Use unified payment process for both EOA and AA wallets
217
226
  await handleUnifiedPaymentProcess();
218
227
  }
219
- };
228
+ }, [order, walletClient?.chain?.id, depositDeficit, handleUnifiedPaymentProcess, initiatePhantomTransfer]);
220
229
  // When waitingForDeposit is true, we show a message to the user to wait for the deposit to be processed.
221
230
  const setWaitingForDeposit = useCallback(() => {
222
231
  if (disableUrlParamManagement)
@@ -254,16 +263,50 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
254
263
  setTxHash(undefined);
255
264
  }
256
265
  }, [setWaitingForDeposit, txSuccess]);
257
- const isPhantomMobile = useMemo(() => navigator.userAgent.includes("Phantom"), []);
258
- const isPhantomBrowser = useMemo(() => window.phantom?.solana?.isPhantom, []);
259
266
  // Get connected Phantom wallet address if available
260
- const phantomWalletAddress = useMemo(() => {
261
- const phantom = window.phantom?.solana;
262
- if (phantom?.isConnected && phantom?.publicKey) {
263
- return phantom.publicKey.toString();
267
+ const phantomWalletAddress = useMemo(() => getPhantomAddress(), [getPhantomAddress]);
268
+ // Calculate status display before using it
269
+ const { text: statusText, status: statusDisplay } = getStatusDisplay(order);
270
+ // Memoize the payable state calculation to avoid recalculating on every render
271
+ const isPayableState = useMemo(() => {
272
+ const waitingForDeposit = new URLSearchParams(window.location.search).get("waitingForDeposit") === "true";
273
+ return (refundTxs.length === 0 &&
274
+ !executeTx &&
275
+ !(relayTxs.length > 0 && relayTxs.every(tx => tx.status === "success")) &&
276
+ !depositTxs?.length &&
277
+ !waitingForDeposit &&
278
+ statusDisplay === "processing" &&
279
+ !order.onrampMetadata &&
280
+ (effectiveCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ||
281
+ effectiveCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET));
282
+ }, [
283
+ refundTxs.length,
284
+ executeTx,
285
+ relayTxs,
286
+ depositTxs?.length,
287
+ statusDisplay,
288
+ order.onrampMetadata,
289
+ effectiveCryptoPaymentMethod,
290
+ ]);
291
+ // Mark component as ready once all critical data is available
292
+ // This ensures we don't trigger payment before the component has fully initialized
293
+ useEffect(() => {
294
+ if (!isComponentReady && srcToken && dstToken && statusDisplay) {
295
+ setIsComponentReady(true);
264
296
  }
265
- return null;
266
- }, []);
297
+ }, [isComponentReady, srcToken, dstToken, statusDisplay]);
298
+ // Auto-trigger payment when component is ready and order is in payable state
299
+ // This effect only runs when isPayableState or isComponentReady changes
300
+ useEffect(() => {
301
+ // Only trigger payment if:
302
+ // 1. We haven't attempted payment yet
303
+ // 2. Component is fully ready (all data loaded)
304
+ // 3. Order is in a payable state
305
+ if (!autoPaymentAttempted.current && isComponentReady && isPayableState) {
306
+ autoPaymentAttempted.current = true;
307
+ handlePayment();
308
+ }
309
+ }, [isPayableState, isComponentReady, handlePayment]);
267
310
  if (!srcToken || !dstToken) {
268
311
  return _jsx("div", { children: "Loading..." });
269
312
  }
@@ -278,138 +321,6 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
278
321
  const formattedActualDstAmount = actualDstAmount
279
322
  ? formatTokenAmount(BigInt(actualDstAmount), dstToken.decimals)
280
323
  : undefined;
281
- const { text: statusText, status: statusDisplay } = getStatusDisplay(order);
282
- const initiatePhantomTransfer = async (amountLamports, tokenAddress, recipientAddress) => {
283
- try {
284
- if (!isPhantomBrowser && !isPhantomMobile) {
285
- toast.error("Phantom wallet not installed. Please install Phantom wallet to continue.");
286
- return;
287
- }
288
- // Step 2: Ensure Phantom is connected/unlocked
289
- const phantom = window.phantom?.solana;
290
- if (!phantom) {
291
- toast.error("Phantom wallet not accessible");
292
- return;
293
- }
294
- // Connect and unlock wallet if needed
295
- let publicKey;
296
- try {
297
- const connection = await phantom.connect();
298
- publicKey = connection.publicKey;
299
- }
300
- catch (connectError) {
301
- toast.error("Failed to connect to Phantom wallet");
302
- return;
303
- }
304
- // Step 3: Create transaction with priority fees
305
- const connection = new Connection("https://mainnet.helius-rpc.com/?api-key=efafd9b3-1807-4cf8-8aa4-3d984f56d8fb");
306
- const fromPubkey = new PublicKey(publicKey.toString());
307
- const toPubkey = new PublicKey(recipientAddress);
308
- const amount = BigInt(amountLamports);
309
- // Step 4: Get recent priority fees to determine optimal pricing
310
- let priorityFee = 10000; // Default fallback (10,000 micro-lamports)
311
- try {
312
- const recentFees = await connection.getRecentPrioritizationFees({
313
- lockedWritableAccounts: [fromPubkey],
314
- });
315
- if (recentFees && recentFees.length > 0) {
316
- // Use 75th percentile of recent fees for good priority
317
- const sortedFees = recentFees.map(fee => fee.prioritizationFee).sort((a, b) => a - b);
318
- const percentile75Index = Math.floor(sortedFees.length * 0.75);
319
- priorityFee = Math.max(sortedFees[percentile75Index] || 10000, 10000);
320
- }
321
- }
322
- catch (feeError) {
323
- console.warn("Failed to fetch recent priority fees, using default:", feeError);
324
- }
325
- let transaction;
326
- // Check if this is native SOL transfer
327
- if (tokenAddress === "11111111111111111111111111111111") {
328
- // Native SOL transfer with priority fees
329
- const computeUnitLimit = 1000; // SOL transfer + compute budget instructions need ~600-800 CU
330
- const computeUnitPrice = Math.min(priorityFee, 100000); // Cap at 100k micro-lamports for safety
331
- transaction = new Transaction()
332
- .add(
333
- // Set compute unit limit first (must come before other instructions)
334
- ComputeBudgetProgram.setComputeUnitLimit({
335
- units: computeUnitLimit,
336
- }))
337
- .add(
338
- // Set priority fee
339
- ComputeBudgetProgram.setComputeUnitPrice({
340
- microLamports: computeUnitPrice,
341
- }))
342
- .add(
343
- // Actual transfer instruction
344
- SystemProgram.transfer({
345
- fromPubkey,
346
- toPubkey,
347
- lamports: Number(amount),
348
- }));
349
- console.log(`Using priority fee: ${computeUnitPrice} micro-lamports per CU, limit: ${computeUnitLimit} CU`);
350
- }
351
- else {
352
- // SPL Token transfer with priority fees
353
- const mintPubkey = new PublicKey(tokenAddress);
354
- // Get associated token accounts
355
- const fromTokenAccount = getAssociatedTokenAddressSync(mintPubkey, fromPubkey);
356
- const toTokenAccount = getAssociatedTokenAddressSync(mintPubkey, toPubkey);
357
- // Check if destination token account exists
358
- const toTokenAccountInfo = await connection.getAccountInfo(toTokenAccount);
359
- const needsDestinationAccount = !toTokenAccountInfo;
360
- // Get mint info to determine decimals
361
- const mintInfo = await connection.getParsedAccountInfo(mintPubkey);
362
- const decimals = mintInfo.value?.data?.parsed?.info?.decimals || 9;
363
- // SPL transfers need more compute units than SOL transfers
364
- // Add extra CU if we need to create destination account
365
- const computeUnitLimit = needsDestinationAccount ? 40000 : 20000;
366
- const computeUnitPrice = Math.min(priorityFee, 100000);
367
- // Create transfer instruction
368
- const transferInstruction = createTransferCheckedInstruction(fromTokenAccount, mintPubkey, toTokenAccount, fromPubkey, Number(amount), decimals);
369
- transaction = new Transaction()
370
- .add(ComputeBudgetProgram.setComputeUnitLimit({
371
- units: computeUnitLimit,
372
- }))
373
- .add(ComputeBudgetProgram.setComputeUnitPrice({
374
- microLamports: computeUnitPrice,
375
- }));
376
- // Add create destination account instruction if needed
377
- if (needsDestinationAccount) {
378
- transaction.add(createAssociatedTokenAccountInstruction(fromPubkey, // payer
379
- toTokenAccount, // ata
380
- toPubkey, // owner
381
- mintPubkey));
382
- }
383
- // Add the transfer instruction
384
- transaction.add(transferInstruction);
385
- console.log(`SPL Token transfer: ${computeUnitPrice} micro-lamports per CU, limit: ${computeUnitLimit} CU, creating destination: ${needsDestinationAccount}`);
386
- }
387
- // Step 5: Get latest blockhash and simulate transaction to verify
388
- const { blockhash } = await connection.getLatestBlockhash("confirmed");
389
- transaction.recentBlockhash = blockhash;
390
- transaction.feePayer = fromPubkey;
391
- // Step 6: Sign and send transaction with priority fees
392
- const signedTransaction = await phantom.signAndSendTransaction(transaction);
393
- toast.success(`Transaction successful! Signature: ${signedTransaction.signature}`);
394
- console.log("Transaction sent with priority fees. Signature:", signedTransaction.signature);
395
- }
396
- catch (error) {
397
- console.error("Transfer error:", error);
398
- const errorMessage = error instanceof Error ? error.message : String(error);
399
- if (errorMessage.includes("User rejected")) {
400
- toast.error("Transaction was cancelled by user");
401
- }
402
- else if (errorMessage.includes("insufficient")) {
403
- toast.error("Insufficient balance for this transaction");
404
- }
405
- else if (errorMessage.includes("blockhash not found")) {
406
- toast.error("Network congestion detected. Please try again in a moment.");
407
- }
408
- else {
409
- toast.error(`Transfer failed: ${errorMessage}`);
410
- }
411
- }
412
- };
413
324
  if (refundTxs.length > 0) {
414
325
  return (_jsxs(_Fragment, { children: [_jsx(OrderStatus, { order: order, selectedCryptoPaymentMethod: effectiveCryptoPaymentMethod }), _jsx(OrderDetailsCollapsible, { order: order, dstToken: dstToken, tournament: tournament, nft: nft, recipientName: recipientName, formattedExpectedDstAmount: formattedExpectedDstAmount, points: points }), _jsx(Accordion, { type: "single", collapsible: true, className: "order-details-accordion w-full", children: _jsxs(AccordionItem, { value: "refund-details", className: "order-details-refund-item", children: [_jsx(AccordionTrigger, { className: "accordion-trigger", children: "Transaction Details" }), _jsx(AccordionContent, { className: "accordion-content pl-2", children: _jsxs("div", { className: "relative flex w-full flex-col gap-4", children: [_jsx("div", { className: "bg-as-surface-secondary absolute bottom-2 left-4 top-2 z-[5] w-2", children: _jsx(motion.div, { className: "bg-as-border-primary absolute left-[2px] top-0 z-10 w-[3px]", initial: { height: "0%" }, animate: { height: "100%" }, transition: { duration: 1.5, ease: "easeInOut" } }) }), depositTxs
415
326
  ? depositTxs.map(dTx => (_jsx(TransactionDetails, { title: order.onrampMetadata?.vendor === "stripe-web2"
@@ -1,5 +1,5 @@
1
1
  import { components } from "../../../../anyspend/types/api";
2
- export declare function OrderTokenAmount({ disabled, inputValue, onChangeInput, context, address, chainId, setChainId, token, setToken, hideTokenSelect, canEditAmount, className, innerClassName, amountClassName, tokenSelectClassName, onTokenSelect, }: {
2
+ export declare function OrderTokenAmount({ disabled, inputValue, onChangeInput, context, address, chainId, setChainId, token, setToken, hideTokenSelect, canEditAmount, className, innerClassName, amountClassName, tokenSelectClassName, onTokenSelect, walletAddress, }: {
3
3
  disabled?: boolean;
4
4
  inputValue: string;
5
5
  onChangeInput: (value: string) => void;
@@ -18,4 +18,5 @@ export declare function OrderTokenAmount({ disabled, inputValue, onChangeInput,
18
18
  onTokenSelect?: (token: components["schemas"]["Token"], event: {
19
19
  preventDefault: () => void;
20
20
  }) => void;
21
+ walletAddress?: string | undefined;
21
22
  }): import("react/jsx-runtime").JSX.Element;
@@ -3,27 +3,55 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { ChevronsUpDown } from "lucide-react";
4
4
  import { useEffect, useRef } from "react";
5
5
  import { NumericFormat } from "react-number-format";
6
+ import { formatUnits } from "viem";
6
7
  import { ALL_CHAINS, RELAY_SOLANA_MAINNET_CHAIN_ID } from "../../../../anyspend/index.js";
7
- import { Button } from "../../../../global-account/react/index.js";
8
+ import { getNativeRequired } from "../../../../anyspend/utils/chain.js";
9
+ import { isNativeToken } from "../../../../anyspend/utils/token.js";
10
+ import { Button, useTokenBalance } from "../../../../global-account/react/index.js";
8
11
  import { cn } from "../../../../shared/utils/index.js";
9
12
  import { TokenSelector } from "@relayprotocol/relay-kit-ui";
10
13
  import { ChainTokenIcon } from "./ChainTokenIcon.js";
11
- export function OrderTokenAmount({ disabled, inputValue, onChangeInput, context, address, chainId, setChainId, token, setToken, hideTokenSelect = false, canEditAmount = true, className, innerClassName, amountClassName, tokenSelectClassName, onTokenSelect, }) {
14
+ export function OrderTokenAmount({ disabled, inputValue, onChangeInput, context, address, chainId, setChainId, token, setToken, hideTokenSelect = false, canEditAmount = true, className, innerClassName, amountClassName, tokenSelectClassName, onTokenSelect, walletAddress, }) {
12
15
  // Track previous token to detect changes
13
16
  const prevTokenRef = useRef(token.address);
17
+ // Track if initial balance has been set
18
+ const initialBalanceSetRef = useRef(false);
19
+ // Only get token balance when context is "from" (for setting max amount)
20
+ const { rawBalance } = useTokenBalance({
21
+ token,
22
+ address: context === "from" && walletAddress ? walletAddress : undefined,
23
+ });
24
+ // Reset balance ref when token address or chain changes
14
25
  useEffect(() => {
15
- // Only trigger when token actually changes
16
- if (prevTokenRef.current !== token.address) {
17
- console.log(`Token changed from ${prevTokenRef.current} to ${token.address}`);
18
- // For "from" context, reset to default value when token changes
19
- if (context === "from") {
20
- // Reset input to default for new token
21
- onChangeInput("0.01");
26
+ initialBalanceSetRef.current = false;
27
+ }, [token.address, token.chainId]);
28
+ useEffect(() => {
29
+ // Only handle "from" context
30
+ if (context !== "from")
31
+ return;
32
+ // Check if token changed or if this is the initial load with balance
33
+ const isTokenChanged = prevTokenRef.current !== token.address;
34
+ const isInitialLoad = !initialBalanceSetRef.current && rawBalance;
35
+ if ((isTokenChanged || isInitialLoad) && rawBalance) {
36
+ console.log(`Setting max balance - Token: ${token.address}, Changed: ${isTokenChanged}, Initial: ${isInitialLoad}`);
37
+ // Calculate max amount with gas reserve for native tokens
38
+ let maxAmount;
39
+ if (isNativeToken(token.address)) {
40
+ const gasReserve = getNativeRequired(token.chainId);
41
+ // Ensure we don't go negative
42
+ maxAmount = rawBalance > gasReserve ? rawBalance - gasReserve : BigInt(0);
43
+ }
44
+ else {
45
+ // For ERC20 tokens, use full balance
46
+ maxAmount = rawBalance;
22
47
  }
23
- // Update ref to current token
48
+ // Set the max amount as input value
49
+ onChangeInput(formatUnits(maxAmount, token.decimals));
50
+ // Update refs
24
51
  prevTokenRef.current = token.address;
52
+ initialBalanceSetRef.current = true;
25
53
  }
26
- }, [token.address, chainId, context, onChangeInput]);
54
+ }, [token.address, token.chainId, token.decimals, chainId, context, onChangeInput, rawBalance]);
27
55
  const handleTokenSelect = (newToken) => {
28
56
  const token = {
29
57
  address: newToken.address,
@@ -50,12 +78,8 @@ export function OrderTokenAmount({ disabled, inputValue, onChangeInput, context,
50
78
  prevTokenRef.current = "changing"; // Temporary value to force effect
51
79
  // Set the chain ID first
52
80
  setChainId(newToken.chainId);
53
- // Then set the new token
81
+ // Then set the new token - the useEffect will handle setting the max balance
54
82
  setToken(token);
55
- // If this is the source token, reset the amount immediately
56
- if (context === "from") {
57
- onChangeInput("0.01");
58
- }
59
83
  };
60
84
  return (_jsx("div", { className: cn("border-as-stroke flex w-full flex-col gap-2 rounded-xl", className), children: _jsxs("div", { className: cn("flex items-center justify-between gap-3", innerClassName), children: [!canEditAmount ? (_jsx("h2", { className: cn("text-3xl font-medium text-white", amountClassName), children: inputValue || "--" })) : (_jsx(NumericFormat, { decimalSeparator: ".", allowedDecimalSeparators: [","], thousandSeparator: true, inputMode: "decimal", autoComplete: "off", autoCorrect: "off", type: "text", placeholder: "0.00", minLength: 1, maxLength: 30, spellCheck: "false", className: cn("placeholder:text-as-primary/70 disabled:text-as-primary/70 text-as-primary w-full bg-transparent text-4xl font-semibold leading-[42px] outline-none sm:text-[30px]", amountClassName), pattern: "^[0-9]*[.,]?[0-9]*$", disabled: disabled, value: inputValue, allowNegative: false, onChange: e => onChangeInput(e.currentTarget.value) }, `input-${token.address}-${chainId}`)), !hideTokenSelect && (_jsx(TokenSelector, { address: address, chainIdsFilter: Object.values(ALL_CHAINS).map(chain => chain.id), context: context, fromChainWalletVMSupported: true, isValidAddress: true, lockedChainIds: Object.values(ALL_CHAINS).map(chain => chain.id), multiWalletSupportEnabled: true, onAnalyticEvent: undefined, popularChainIds: [1, 8453, RELAY_SOLANA_MAINNET_CHAIN_ID], setToken: handleTokenSelect, supportedWalletVMs: ["evm", "svm"], token: undefined, trigger: _jsxs(Button, { variant: "outline", role: "combobox", className: cn("token-selector-button bg-b3-react-background border-as-stroke flex h-auto w-fit shrink-0 items-center justify-center gap-2 rounded-xl border-2 px-2 py-1 pr-2 text-center", tokenSelectClassName), children: [token.metadata.logoURI ? (_jsx(ChainTokenIcon, { chainUrl: ALL_CHAINS[chainId].logoUrl, tokenUrl: token.metadata.logoURI, className: "h-8 min-h-8 w-8 min-w-8" })) : (_jsx("div", { className: "h-8 w-8 rounded-full bg-gray-700" })), _jsxs("div", { className: "flex flex-col items-start gap-0", children: [_jsx("div", { className: "text-as-primary font-semibold", children: token.symbol }), _jsx("div", { className: "text-as-primary/70 text-xs", children: ALL_CHAINS[chainId].name })] }), _jsx(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-70" })] }) }, `selector-${context}-${token.address}-${chainId}`))] }) }, `${context}-${token.address}-${chainId}`));
61
85
  }
@@ -39,7 +39,7 @@ export function CryptoPaySection({ selectedSrcChainId, setSelectedSrcChainId, se
39
39
  useEffect(() => {
40
40
  appliedSrcMetadataRef.current = false;
41
41
  }, [selectedSrcToken.address, selectedSrcToken.chainId]);
42
- return (_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, ease: "easeInOut" }, className: "pay-section bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-as-primary/50 flex h-7 items-center text-sm", children: "Pay" }), _jsx("button", { className: "text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors focus:!outline-none", onClick: onSelectCryptoPaymentMethod, children: selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (_jsxs(_Fragment, { children: [isConnected ? (_jsx("div", { className: "flex items-center gap-1", children: connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "") })) : ("Connect wallet"), _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET ? (_jsxs(_Fragment, { children: ["Global Account", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (_jsxs(_Fragment, { children: ["Transfer crypto", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : (_jsxs(_Fragment, { children: ["Select payment method", _jsx(ChevronRight, { className: "h-4 w-4" })] })) })] }), _jsx(OrderTokenAmount, { address: connectedAddress, context: "from", inputValue: srcAmount, onChangeInput: value => {
42
+ return (_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, ease: "easeInOut" }, className: "pay-section bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-as-primary/50 flex h-7 items-center text-sm", children: "Pay" }), _jsx("button", { className: "text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors focus:!outline-none", onClick: onSelectCryptoPaymentMethod, children: selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (_jsxs(_Fragment, { children: [isConnected ? (_jsx("div", { className: "flex items-center gap-1", children: connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "") })) : ("Connect wallet"), _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET ? (_jsxs(_Fragment, { children: ["Global Account", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (_jsxs(_Fragment, { children: ["Transfer crypto", _jsx(ChevronRight, { className: "h-4 w-4" })] })) : (_jsxs(_Fragment, { children: ["Select payment method", _jsx(ChevronRight, { className: "h-4 w-4" })] })) })] }), _jsx(OrderTokenAmount, { address: connectedAddress, walletAddress: connectedAddress, context: "from", inputValue: srcAmount, onChangeInput: value => {
43
43
  setIsSrcInputDirty(true);
44
44
  setSrcAmount(value);
45
45
  }, chainId: selectedSrcChainId, setChainId: setSelectedSrcChainId, token: selectedSrcToken, setToken: setSelectedSrcToken }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-as-primary/50 flex h-5 items-center text-sm", children: formatDisplayNumber(anyspendQuote?.data?.currencyIn?.amountUsd, {
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { getNativeRequired } from "../../../../anyspend/utils/chain.js";
3
3
  import { isNativeToken } from "../../../../anyspend/utils/token.js";
4
- import { useTokenBalance } from "../../../../global-account/react/index.js";
4
+ import { useTokenBalanceDirect } from "../../../../global-account/react/index.js";
5
5
  import { formatUnits } from "viem";
6
6
  export function TokenBalance({ token, walletAddress, onChangeInput, }) {
7
- const { rawBalance, formattedBalance, isLoading } = useTokenBalance({
7
+ const { rawBalance, formattedBalance, isLoading } = useTokenBalanceDirect({
8
8
  token,
9
9
  address: walletAddress,
10
10
  });