@b3dotfun/sdk 0.1.70-alpha.14 → 0.1.70-alpha.16

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.
@@ -20,7 +20,8 @@ export declare enum PanelView {
20
20
  FEE_DETAIL = 9,
21
21
  DIRECT_TRANSFER_SUCCESS = 10,
22
22
  FIAT_KYC = 11,
23
- FIAT_AUTH = 12
23
+ FIAT_AUTH = 12,
24
+ PURE_TRANSFER_ADDRESS = 13
24
25
  }
25
26
  export declare function AnySpend(props: {
26
27
  mode?: "page" | "modal";
@@ -42,6 +42,7 @@ const LoginStep_1 = require("../../../global-account/react/components/SignInWith
42
42
  const PanelOnramp_1 = require("./common/PanelOnramp");
43
43
  const PanelOnrampPayment_1 = require("./common/PanelOnrampPayment");
44
44
  const PointsDetailPanel_1 = require("./common/PointsDetailPanel");
45
+ const PureTransferView_1 = require("./common/PureTransferView");
45
46
  const RecipientSelection_1 = require("./common/RecipientSelection");
46
47
  const TabSection_1 = require("./common/TabSection");
47
48
  const AnySpendCustomizationContext_1 = require("./context/AnySpendCustomizationContext");
@@ -61,6 +62,7 @@ var PanelView;
61
62
  PanelView[PanelView["DIRECT_TRANSFER_SUCCESS"] = 10] = "DIRECT_TRANSFER_SUCCESS";
62
63
  PanelView[PanelView["FIAT_KYC"] = 11] = "FIAT_KYC";
63
64
  PanelView[PanelView["FIAT_AUTH"] = 12] = "FIAT_AUTH";
65
+ PanelView[PanelView["PURE_TRANSFER_ADDRESS"] = 13] = "PURE_TRANSFER_ADDRESS";
64
66
  })(PanelView || (exports.PanelView = PanelView = {}));
65
67
  const ANYSPEND_RECIPIENTS_KEY = "anyspend_recipients";
66
68
  function AnySpend(props) {
@@ -453,7 +455,10 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
453
455
  walletAddress,
454
456
  globalAddress,
455
457
  });
456
- const recipientProfile = (0, react_2.useProfile)({ address: effectiveRecipientAddress, fresh: true });
458
+ const recipientProfile = (0, react_2.useProfile)({
459
+ address: effectiveRecipientAddress,
460
+ fresh: true,
461
+ });
457
462
  const recipientName = recipientProfile.data?.name;
458
463
  // Check token balance for crypto payments
459
464
  const effectiveBalanceAddress = senderAddress || connectedEOAWallet?.getAccount()?.address;
@@ -559,12 +564,15 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
559
564
  anyspendQuote.data.currencyOut?.amount &&
560
565
  anyspendQuote.data.currencyOut?.currency?.decimals) {
561
566
  if (isSrcInputDirty) {
562
- // Don't override dstAmount if we have a fixed destinationTokenAmount
563
- if (!destinationTokenAmount) {
564
- const amount = anyspendQuote.data.currencyOut.amount;
565
- const decimals = anyspendQuote.data.currencyOut.currency.decimals;
566
- setDstAmount((0, number_1.formatTokenAmount)(BigInt(amount), decimals, 6, false));
567
- }
567
+ // The user is driving the SOURCE (exact-in): reflect the quote's OUTPUT even
568
+ // when a fixed destinationTokenAmount pre-filled the receive. That lock only
569
+ // governs the INITIAL exact-out state (untouched source → compute the pay for
570
+ // the fixed receive). Once the user edits the pay, keeping the receive pinned
571
+ // shows a value that doesn't match the quote — the URL amount "overrides" the
572
+ // real output, an invalid mismatched swap.
573
+ const amount = anyspendQuote.data.currencyOut.amount;
574
+ const decimals = anyspendQuote.data.currencyOut.currency.decimals;
575
+ setDstAmount((0, number_1.formatTokenAmount)(BigInt(amount), decimals, 6, false));
568
576
  }
569
577
  else {
570
578
  const amount = anyspendQuote.data.currencyIn.amount;
@@ -574,16 +582,13 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
574
582
  }
575
583
  else {
576
584
  if (isSrcInputDirty) {
577
- // Don't reset dstAmount if we have a fixed destinationTokenAmount
578
- if (!destinationTokenAmount) {
579
- setDstAmount("");
580
- }
585
+ setDstAmount("");
581
586
  }
582
587
  else {
583
588
  setSrcAmount("");
584
589
  }
585
590
  }
586
- }, [anyspendQuote, isSrcInputDirty, destinationTokenAmount]);
591
+ }, [anyspendQuote, isSrcInputDirty]);
587
592
  // Call onSuccess when order is executed
588
593
  (0, useOnOrderSuccess_1.useOnOrderSuccess)({ orderData: oat, orderId, onSuccess });
589
594
  // Clear all persisted selection state once an order is submitted — next open starts fresh
@@ -654,11 +659,26 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
654
659
  // For fiat tab, check srcAmountOnRamp; for crypto tab, check activeInputAmountInWei
655
660
  const hasAmount = activeTab === "fiat" ? srcAmountOnRamp && parseFloat(srcAmountOnRamp) > 0 : activeInputAmountInWei !== "0";
656
661
  if (!hasAmount)
657
- return { text: "Enter an amount", disable: true, error: false, loading: false };
662
+ return {
663
+ text: "Enter an amount",
664
+ disable: true,
665
+ error: false,
666
+ loading: false,
667
+ };
658
668
  if (isSameChainSameToken && !allowDirectTransfer)
659
- return { text: "Select a different token or chain", disable: true, error: false, loading: false };
669
+ return {
670
+ text: "Select a different token or chain",
671
+ disable: true,
672
+ error: false,
673
+ loading: false,
674
+ };
660
675
  if (isLoadingAnyspendQuote && !isSameChainSameToken)
661
- return { text: "Loading quote...", disable: true, error: false, loading: true };
676
+ return {
677
+ text: "Loading quote...",
678
+ disable: true,
679
+ error: false,
680
+ loading: true,
681
+ };
662
682
  if (isCreatingOrder || isCreatingOnrampOrder || isSwitchingOrExecuting)
663
683
  return {
664
684
  text: isSwitchingOrExecuting ? "Transferring..." : "Creating order...",
@@ -667,14 +687,29 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
667
687
  loading: true,
668
688
  };
669
689
  if ((!anyspendQuote || !anyspendQuote.success) && !(isSameChainSameToken && allowDirectTransfer))
670
- return { text: "No quote found", disable: true, error: false, loading: false };
690
+ return {
691
+ text: "No quote found",
692
+ disable: true,
693
+ error: false,
694
+ loading: false,
695
+ };
671
696
  if (activeTab === "fiat") {
672
697
  // For fiat: check recipient first, then payment method
673
698
  if (!effectiveRecipientAddress)
674
- return { text: "Select recipient", disable: false, error: false, loading: false };
699
+ return {
700
+ text: "Select recipient",
701
+ disable: false,
702
+ error: false,
703
+ loading: false,
704
+ };
675
705
  // If no fiat payment method selected, show "Select payment method"
676
706
  if (selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.NONE) {
677
- return { text: "Select payment method", disable: false, error: false, loading: false };
707
+ return {
708
+ text: "Select payment method",
709
+ disable: false,
710
+ error: false,
711
+ loading: false,
712
+ };
678
713
  }
679
714
  // If payment method is selected, show "Continue"
680
715
  return { text: "Continue", disable: false, error: false, loading: false };
@@ -683,19 +718,40 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
683
718
  // For crypto: check payment method first, then recipient
684
719
  // If no payment method selected, show "Choose payment method"
685
720
  if (effectiveCryptoPaymentMethod === CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE) {
686
- return { text: "Choose payment method", disable: false, error: false, loading: false };
721
+ return {
722
+ text: "Choose payment method",
723
+ disable: false,
724
+ error: false,
725
+ loading: false,
726
+ };
687
727
  }
688
728
  // Check recipient after payment method
689
729
  if (!effectiveRecipientAddress)
690
- return { text: "Select recipient", disable: false, error: false, loading: false };
730
+ return {
731
+ text: "Select recipient",
732
+ disable: false,
733
+ error: false,
734
+ loading: false,
735
+ };
691
736
  // If payment method selected, show appropriate action
692
737
  if (effectiveCryptoPaymentMethod === CryptoPaymentMethod_1.CryptoPaymentMethodType.CONNECT_WALLET ||
693
738
  effectiveCryptoPaymentMethod === CryptoPaymentMethod_1.CryptoPaymentMethodType.GLOBAL_WALLET) {
694
739
  const buttonText = isSameChainSameToken && allowDirectTransfer ? "Transfer" : "Swap";
695
- return { text: buttonText, disable: false, error: false, loading: false };
740
+ return {
741
+ text: buttonText,
742
+ disable: false,
743
+ error: false,
744
+ loading: false,
745
+ };
696
746
  }
697
747
  if (effectiveCryptoPaymentMethod === CryptoPaymentMethod_1.CryptoPaymentMethodType.TRANSFER_CRYPTO) {
698
- return { text: "Continue to payment", disable: false, error: false, loading: false };
748
+ const transferText = isSameChainSameToken && allowDirectTransfer ? "Show deposit address" : "Continue to payment";
749
+ return {
750
+ text: transferText,
751
+ disable: false,
752
+ error: false,
753
+ loading: false,
754
+ };
699
755
  }
700
756
  }
701
757
  return { text: "Continue", disable: false, error: false, loading: false };
@@ -787,8 +843,14 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
787
843
  // Handle crypto swap creation
788
844
  const handleCryptoSwap = async (method) => {
789
845
  try {
790
- const isDirectTransfer = isSameChainSameToken && allowDirectTransfer;
846
+ // TRANSFER_CRYPTO is the manual deposit-address flow — no connected wallet to send from.
847
+ const isDirectTransfer = isSameChainSameToken && allowDirectTransfer && method !== CryptoPaymentMethod_1.CryptoPaymentMethodType.TRANSFER_CRYPTO;
791
848
  (0, invariant_1.default)(effectiveRecipientAddress, "Recipient address is not found");
849
+ // Same-token manual deposit → show recipient address + watch, no relayer order, no fee
850
+ if (isSameChainSameToken && allowDirectTransfer && method === CryptoPaymentMethod_1.CryptoPaymentMethodType.TRANSFER_CRYPTO) {
851
+ navigateToPanel(PanelView.PURE_TRANSFER_ADDRESS, "forward");
852
+ return;
853
+ }
792
854
  const srcAmountBigInt = (0, viem_1.parseUnits)(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
793
855
  // Handle direct transfer (same chain/token) - bypass backend, transfer directly
794
856
  if (isDirectTransfer) {
@@ -807,9 +869,6 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
807
869
  }
808
870
  // Regular swap flow - use backend
809
871
  (0, invariant_1.default)(anyspendQuote, "Relay price is not found");
810
- // Debug: Check payment method values
811
- console.log("handleCryptoSwap - method parameter:", method);
812
- console.log("handleCryptoSwap - selectedCryptoPaymentMethod state:", selectedCryptoPaymentMethod);
813
872
  createOrder({
814
873
  recipientAddress: effectiveRecipientAddress,
815
874
  orderType: "swap",
@@ -817,7 +876,11 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
817
876
  dstChain: isBuyMode ? destinationTokenChainId : selectedDstChainId,
818
877
  srcToken: selectedSrcToken,
819
878
  dstToken: isBuyMode
820
- ? { ...selectedDstToken, chainId: destinationTokenChainId, address: destinationTokenAddress }
879
+ ? {
880
+ ...selectedDstToken,
881
+ chainId: destinationTokenChainId,
882
+ address: destinationTokenAddress,
883
+ }
821
884
  : selectedDstToken,
822
885
  srcAmount: srcAmountBigInt.toString(),
823
886
  expectedDstAmount: anyspendQuote?.data?.currencyOut?.amount || "0",
@@ -1134,6 +1197,7 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
1134
1197
  const authView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto w-full max-w-[460px]", children: (0, jsx_runtime_1.jsx)(LoginStep_1.LoginStep, { chain: baseChain, onSuccess: async () => {
1135
1198
  // isAuthenticated will be true at this point — the useEffect below handles navigation
1136
1199
  } }) }));
1200
+ const pureTransferAddressView = ((0, jsx_runtime_1.jsx)(PureTransferView_1.PureTransferView, { mode: mode, recipientAddress: effectiveRecipientAddress ?? "", chainId: selectedSrcChainId, token: selectedSrcToken, displayAmount: srcAmount && srcAmount !== "0" ? `${srcAmount} ${selectedSrcToken.symbol}` : undefined, isActive: activePanel === PanelView.PURE_TRANSFER_ADDRESS, onBack: navigateBack, onClose: () => setB3ModalOpen(false), onTransferDetected: () => onSuccess?.() }));
1137
1201
  // Add tabs to the main component when no order is loaded
1138
1202
  return ((0, jsx_runtime_1.jsx)(react_2.StyleRoot, { children: (0, jsx_runtime_1.jsx)("div", { className: classes?.container ||
1139
1203
  (0, cn_1.cn)("anyspend-container font-inter mx-auto w-full max-w-[460px]", mode === "page" &&
@@ -1169,5 +1233,6 @@ function AnySpendInner({ sourceChainId, destinationTokenAddress, destinationToke
1169
1233
  (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)(mode === "page" && "p-6"), children: directTransferSuccessView }, "direct-transfer-success-view"),
1170
1234
  (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)(mode === "page" && "p-6"), children: kycView }, "fiat-kyc-view"),
1171
1235
  (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)(mode === "page" && "p-6"), children: authView }, "fiat-auth-view"),
1236
+ (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)(mode === "page" && "p-6"), children: pureTransferAddressView }, "pure-transfer-address-view"),
1172
1237
  ] }) }) }));
1173
1238
  }
@@ -254,7 +254,10 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
254
254
  (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] }) })) }), gasPriceData && !isLoadingGas && effectivePaymentType === "crypto" && !isDirectTransfer && ((0, jsx_runtime_1.jsx)(GasIndicator_1.GasIndicator, { gasPrice: gasPriceData, className: classes?.gasIndicator || "mt-2 w-full" })), mainFooter ? mainFooter : null] }));
255
255
  const handleCryptoOrder = async () => {
256
256
  try {
257
- const isDirectTransfer = isSameChainSameToken && allowDirectTransfer;
257
+ // TRANSFER_CRYPTO is the manual deposit-address flow — no connected wallet to send from.
258
+ const isDirectTransfer = isSameChainSameToken &&
259
+ allowDirectTransfer &&
260
+ effectiveCryptoPaymentMethod !== CryptoPaymentMethod_1.CryptoPaymentMethodType.TRANSFER_CRYPTO;
258
261
  if (!isDirectTransfer) {
259
262
  (0, invariant_1.default)(anyspendQuote, "Relay price is not found");
260
263
  }
@@ -0,0 +1,30 @@
1
+ import type { components } from "../../../../anyspend/types/api";
2
+ import type { TransferResult } from "../../hooks/useWatchTransfer";
3
+ export interface PureTransferViewProps {
4
+ mode?: "modal" | "page";
5
+ /** The recipient address where funds will land (the user's own wallet) */
6
+ recipientAddress: string;
7
+ /** Chain ID to watch on */
8
+ chainId: number;
9
+ /** Token the user sends — drives the QR code and balance watcher */
10
+ token: components["schemas"]["Token"];
11
+ /** Human-readable amount to display (display-only; skip row if empty or "0") */
12
+ displayAmount?: string;
13
+ /** Whether this panel is the currently active panel; gates the balance watcher */
14
+ isActive?: boolean;
15
+ /** Callback when back chevron is clicked */
16
+ onBack?: () => void;
17
+ /** Callback when X close button is clicked */
18
+ onClose?: () => void;
19
+ /** Callback when an incoming transfer is detected */
20
+ onTransferDetected?: (result: TransferResult) => void;
21
+ }
22
+ /**
23
+ * A self-contained view that shows the recipient address as a QR code + copy button and
24
+ * watches for an incoming same-chain/same-token transfer via `useWatchTransfer`. When a
25
+ * transfer is detected it renders `TransferResultScreen`.
26
+ *
27
+ * This is the "TRANSFER_CRYPTO" path for same-token AnySpend deposits — no relayer order,
28
+ * no fee; the user simply sends the token directly to their own address.
29
+ */
30
+ export declare function PureTransferView({ mode, recipientAddress, chainId, token, displayAmount, isActive, onBack, onClose, onTransferDetected, }: PureTransferViewProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ "use client";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.PureTransferView = PureTransferView;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const anyspend_1 = require("../../../../anyspend");
7
+ const react_1 = require("../../../../global-account/react");
8
+ const cn_1 = require("../../../../shared/utils/cn");
9
+ const lucide_react_1 = require("lucide-react");
10
+ const qrcode_react_1 = require("qrcode.react");
11
+ const react_2 = require("react");
12
+ const useWatchTransfer_1 = require("../../hooks/useWatchTransfer");
13
+ const WarningText_1 = require("./WarningText");
14
+ const TransferResultScreen_1 = require("./TransferResultScreen");
15
+ /**
16
+ * A self-contained view that shows the recipient address as a QR code + copy button and
17
+ * watches for an incoming same-chain/same-token transfer via `useWatchTransfer`. When a
18
+ * transfer is detected it renders `TransferResultScreen`.
19
+ *
20
+ * This is the "TRANSFER_CRYPTO" path for same-token AnySpend deposits — no relayer order,
21
+ * no fee; the user simply sends the token directly to their own address.
22
+ */
23
+ function PureTransferView({ mode = "modal", recipientAddress, chainId, token, displayAmount, isActive, onBack, onClose, onTransferDetected, }) {
24
+ const [transferResult, setTransferResult] = (0, react_2.useState)(null);
25
+ // Fix 4: reset transferResult when the panel becomes active again
26
+ (0, react_2.useEffect)(() => {
27
+ if (isActive)
28
+ setTransferResult(null);
29
+ }, [isActive]);
30
+ // Fix 3: stabilize the callback so it doesn't re-run the watcher effect every render
31
+ const handleTransferDetected = (0, react_2.useCallback)((result) => {
32
+ setTransferResult(result);
33
+ onTransferDetected?.(result);
34
+ }, [onTransferDetected]);
35
+ const { isWatching } = (0, useWatchTransfer_1.useWatchTransfer)({
36
+ address: recipientAddress,
37
+ chainId,
38
+ tokenAddress: token.address,
39
+ tokenDecimals: token.decimals,
40
+ // Fix 1: also require a non-empty recipient before enabling the watcher
41
+ enabled: !!recipientAddress && !transferResult && isActive,
42
+ onTransferDetected: handleTransferDetected,
43
+ });
44
+ // Fix 2: guard qrValue when recipientAddress is empty
45
+ const qrValue = (0, react_2.useMemo)(() => recipientAddress
46
+ ? (0, anyspend_1.getPaymentUrl)(recipientAddress, undefined, token.address === anyspend_1.ZERO_ADDRESS ? "ETH" : token.address, chainId, token.decimals)
47
+ : "", [recipientAddress, token.address, token.decimals, chainId]);
48
+ const chainName = (0, react_2.useMemo)(() => {
49
+ try {
50
+ return (0, anyspend_1.getChainName)(chainId);
51
+ }
52
+ catch {
53
+ return "the specified chain";
54
+ }
55
+ }, [chainId]);
56
+ // Guard: if no address yet, render nothing
57
+ if (!recipientAddress)
58
+ return null;
59
+ // Once a transfer is detected, hand off to the shared success screen
60
+ if (transferResult) {
61
+ return ((0, jsx_runtime_1.jsx)(TransferResultScreen_1.TransferResultScreen, { mode: mode, transferResult: transferResult, token: token, chainId: chainId, recipientAddress: recipientAddress, onBack: onBack, onClose: onClose }));
62
+ }
63
+ return ((0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("anyspend-container anyspend-pure-transfer font-inter bg-as-surface-primary mx-auto w-full max-w-[460px] p-6"), children: (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-pure-transfer-content flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "anyspend-pure-transfer-header flex items-center justify-between", children: [onBack ? ((0, jsx_runtime_1.jsx)("button", { onClick: onBack, className: "anyspend-pure-transfer-back text-as-secondary hover:text-as-primary", "aria-label": "Go back", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronLeft, { className: "h-5 w-5" }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "w-5" })), (0, jsx_runtime_1.jsxs)("h2", { className: "anyspend-pure-transfer-title text-as-primary text-base font-semibold", children: ["Send ", token.symbol] }), onClose ? ((0, jsx_runtime_1.jsx)("button", { onClick: onClose, className: "anyspend-pure-transfer-close text-as-secondary hover:text-as-primary", "aria-label": "Close", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-5 w-5" }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "w-5" }))] }), displayAmount && ((0, jsx_runtime_1.jsx)("div", { className: "anyspend-pure-transfer-amount-badge border-as-border-secondary bg-as-surface-secondary flex items-center justify-center rounded-xl border px-4 py-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-as-primary text-sm font-medium", children: displayAmount }) })), (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-pure-transfer-qr-content border-as-stroke flex items-start gap-4 rounded-xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "anyspend-pure-transfer-qr-code-container flex flex-col items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "anyspend-pure-transfer-qr-code rounded-lg bg-white p-2", children: (0, jsx_runtime_1.jsx)(qrcode_react_1.QRCodeSVG, { value: qrValue, size: 120, level: "M", marginSize: 0 }) }), (0, jsx_runtime_1.jsxs)("span", { className: "anyspend-pure-transfer-qr-scan-hint text-as-secondary text-xs", children: ["SCAN WITH ", (0, jsx_runtime_1.jsx)("span", { className: "inline-block", children: "\uD83E\uDD8A" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-pure-transfer-address-container flex flex-1 flex-col gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "anyspend-pure-transfer-address-label text-as-secondary text-sm", children: "Deposit address:" }), (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-pure-transfer-address-row flex items-start gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "anyspend-pure-transfer-address text-as-primary break-all font-mono text-sm leading-relaxed", children: recipientAddress }), (0, jsx_runtime_1.jsx)(react_1.CopyToClipboard, { text: recipientAddress, className: "anyspend-pure-transfer-copy-icon text-as-secondary hover:text-as-primary mt-0.5 shrink-0" })] })] })] }), (0, jsx_runtime_1.jsx)(WarningText_1.ChainWarningText, { chainId: chainId }), (0, jsx_runtime_1.jsxs)(WarningText_1.WarningText, { children: ["Only send ", token.symbol, " on ", chainName, ". Other tokens will not be converted."] }), isWatching && ((0, jsx_runtime_1.jsxs)("div", { className: "anyspend-pure-transfer-watching bg-as-brand/10 flex items-center justify-center gap-2 rounded-lg p-3", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-as-brand h-4 w-4 animate-spin" }), (0, jsx_runtime_1.jsx)("span", { className: "text-as-brand text-sm", children: "Watching for incoming transfer..." })] })), (0, jsx_runtime_1.jsx)(react_1.CopyToClipboard, { text: recipientAddress, children: (0, jsx_runtime_1.jsx)("button", { className: "anyspend-pure-transfer-copy-button bg-as-brand hover:bg-as-brand/90 flex w-full items-center justify-center gap-2 rounded-xl py-3.5 font-medium text-white transition-all", children: "Copy deposit address" }) })] }) }));
64
+ }
@@ -26,6 +26,36 @@ let socketClientUrl = null;
26
26
  // REST client instance
27
27
  let restClient = null;
28
28
  let restClientUrl = null;
29
+ // The pinned @b3dotfun/b3-api client's generated usersMethods predates `setBio`,
30
+ // so `users.setBio(...)` throws "setBio is not a function". Re-register the users
31
+ // service with the full list (mirrors users.shared.ts). Remove once the
32
+ // @b3dotfun/b3-api pin includes setBio.
33
+ const USERS_METHODS = [
34
+ "find",
35
+ "get",
36
+ "create",
37
+ "patch",
38
+ "remove",
39
+ "setReferralCode",
40
+ "syncTwProfiles",
41
+ "setAvatar",
42
+ "setBio",
43
+ "registerUsername",
44
+ "getMe",
45
+ ];
46
+ // Re-register on every client the manager builds — the active transport
47
+ // (REST/socket) switches at runtime.
48
+ function ensureUsersCustomMethods(client) {
49
+ try {
50
+ const connection = client.get("connection");
51
+ if (connection?.service) {
52
+ client.use("users", connection.service("users"), { methods: USERS_METHODS });
53
+ }
54
+ }
55
+ catch {
56
+ // Non-fatal: keep whatever methods the generated client already exposes.
57
+ }
58
+ }
29
59
  /**
30
60
  * Creates a socket client
31
61
  */
@@ -34,6 +64,7 @@ function createSocketClient() {
34
64
  if (!socketClient || socketClientUrl !== url) {
35
65
  socketInstance = (0, socket_io_client_1.default)(url, { transports: ["websocket"] });
36
66
  socketClient = (0, b3_api_1.createClient)((0, socketio_client_1.default)(socketInstance), app_shared_1.clientOptions);
67
+ ensureUsersCustomMethods(socketClient);
37
68
  socketClientUrl = url;
38
69
  }
39
70
  return socketClient;
@@ -54,6 +85,7 @@ function createRestClient() {
54
85
  if (!restClient || restClientUrl !== url) {
55
86
  const connection = (0, rest_client_1.default)(url).fetch(resolveFetch());
56
87
  restClient = (0, b3_api_1.createClient)(connection, app_shared_1.clientOptions);
88
+ ensureUsersCustomMethods(restClient);
57
89
  restClientUrl = url;
58
90
  }
59
91
  return restClient;
@@ -20,7 +20,8 @@ export declare enum PanelView {
20
20
  FEE_DETAIL = 9,
21
21
  DIRECT_TRANSFER_SUCCESS = 10,
22
22
  FIAT_KYC = 11,
23
- FIAT_AUTH = 12
23
+ FIAT_AUTH = 12,
24
+ PURE_TRANSFER_ADDRESS = 13
24
25
  }
25
26
  export declare function AnySpend(props: {
26
27
  mode?: "page" | "modal";