@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.
- package/dist/cjs/anyspend/react/components/AnySpend.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/AnySpend.js +92 -27
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +4 -1
- package/dist/cjs/anyspend/react/components/common/PureTransferView.d.ts +30 -0
- package/dist/cjs/anyspend/react/components/common/PureTransferView.js +64 -0
- package/dist/cjs/global-account/client-manager.js +32 -0
- package/dist/esm/anyspend/react/components/AnySpend.d.ts +2 -1
- package/dist/esm/anyspend/react/components/AnySpend.js +92 -27
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +4 -1
- package/dist/esm/anyspend/react/components/common/PureTransferView.d.ts +30 -0
- package/dist/esm/anyspend/react/components/common/PureTransferView.js +61 -0
- package/dist/esm/global-account/client-manager.js +32 -0
- package/dist/types/anyspend/react/components/AnySpend.d.ts +2 -1
- package/dist/types/anyspend/react/components/common/PureTransferView.d.ts +30 -0
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpend.tsx +119 -29
- package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +5 -1
- package/src/anyspend/react/components/common/PureTransferView.tsx +212 -0
- package/src/global-account/client-manager.ts +33 -0
|
@@ -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)({
|
|
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
|
-
//
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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
|
-
|
|
578
|
-
if (!destinationTokenAmount) {
|
|
579
|
-
setDstAmount("");
|
|
580
|
-
}
|
|
585
|
+
setDstAmount("");
|
|
581
586
|
}
|
|
582
587
|
else {
|
|
583
588
|
setSrcAmount("");
|
|
584
589
|
}
|
|
585
590
|
}
|
|
586
|
-
}, [anyspendQuote, isSrcInputDirty
|
|
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 {
|
|
662
|
+
return {
|
|
663
|
+
text: "Enter an amount",
|
|
664
|
+
disable: true,
|
|
665
|
+
error: false,
|
|
666
|
+
loading: false,
|
|
667
|
+
};
|
|
658
668
|
if (isSameChainSameToken && !allowDirectTransfer)
|
|
659
|
-
return {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
? {
|
|
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
|
-
|
|
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;
|