@b3dotfun/sdk 0.1.70-alpha.15 → 0.1.70-alpha.17
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 +81 -16
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +4 -1
- package/dist/cjs/anyspend/react/components/AnySpendDeposit.js +16 -2
- package/dist/cjs/anyspend/react/components/QRDeposit.d.ts +9 -1
- package/dist/cjs/anyspend/react/components/QRDeposit.js +3 -3
- 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 +81 -16
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +4 -1
- package/dist/esm/anyspend/react/components/AnySpendDeposit.js +16 -2
- package/dist/esm/anyspend/react/components/QRDeposit.d.ts +9 -1
- package/dist/esm/anyspend/react/components/QRDeposit.js +4 -4
- 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/QRDeposit.d.ts +9 -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 +108 -18
- package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +5 -1
- package/src/anyspend/react/components/AnySpendDeposit.tsx +18 -1
- package/src/anyspend/react/components/QRDeposit.tsx +55 -4
- package/src/anyspend/react/components/__tests__/QRDeposit.test.tsx +39 -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;
|
|
@@ -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
|
}
|
|
@@ -5,6 +5,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
5
5
|
const anyspend_1 = require("../../../anyspend");
|
|
6
6
|
const react_1 = require("../../../global-account/react");
|
|
7
7
|
const cn_1 = require("../../../shared/utils/cn");
|
|
8
|
+
const number_1 = require("../../../shared/utils/number");
|
|
8
9
|
const react_2 = require("@web3icons/react");
|
|
9
10
|
const lucide_react_1 = require("lucide-react");
|
|
10
11
|
const react_3 = require("react");
|
|
@@ -228,7 +229,9 @@ function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, paymentT
|
|
|
228
229
|
"anyspend-deposit-option-button anyspend-deposit-crypto-button border-border-primary hover:border-as-brand hover:bg-as-surface-secondary flex w-full items-center justify-between rounded-xl border p-4 text-left shadow-sm transition-all", children: [(0, jsx_runtime_1.jsx)("div", { className: depositClasses?.optionContent || "anyspend-deposit-option-content", children: (0, jsx_runtime_1.jsxs)("div", { className: depositClasses?.optionInfo || "anyspend-deposit-option-info", children: [(0, jsx_runtime_1.jsx)("span", { className: depositClasses?.optionTitle || "anyspend-deposit-option-title text-as-primary font-medium", children: "Deposit Crypto" }), (0, jsx_runtime_1.jsx)("p", { className: depositClasses?.optionDescription ||
|
|
229
230
|
"anyspend-deposit-option-description text-as-secondary text-xs", children: "Swap from any token on any chain" })] }) }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: depositClasses?.optionChevron || "anyspend-deposit-option-chevron text-as-secondary h-5 w-5" })] }), (0, jsx_runtime_1.jsxs)("div", { className: depositClasses?.divider || "anyspend-deposit-divider flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: depositClasses?.dividerLine || "bg-as-stroke h-px flex-1" }), (0, jsx_runtime_1.jsx)("span", { className: depositClasses?.dividerText || "anyspend-deposit-divider-text text-as-secondary text-sm", children: "More options" }), (0, jsx_runtime_1.jsx)("div", { className: depositClasses?.dividerLine || "bg-as-stroke h-px flex-1" })] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleSelectQrDeposit, className: depositClasses?.qrButton ||
|
|
230
231
|
"anyspend-deposit-option-button anyspend-deposit-qr-button border-border-primary hover:border-as-brand hover:bg-as-surface-secondary flex w-full items-center justify-between rounded-xl border p-4 text-left shadow-sm transition-all", children: [(0, jsx_runtime_1.jsxs)("div", { className: depositClasses?.optionContent || "anyspend-deposit-option-content flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)(QrCodeIcon_1.QrCodeIcon, { className: depositClasses?.optionIcon || "anyspend-deposit-option-icon h-10 w-10" }), (0, jsx_runtime_1.jsxs)("div", { className: depositClasses?.optionInfo || "anyspend-deposit-option-info", children: [(0, jsx_runtime_1.jsx)("span", { className: depositClasses?.optionTitle || "anyspend-deposit-option-title text-as-primary font-medium", children: "Deposit with QR Code" }), (0, jsx_runtime_1.jsx)("p", { className: depositClasses?.optionDescription ||
|
|
231
|
-
"anyspend-deposit-option-description text-as-secondary text-xs", children:
|
|
232
|
+
"anyspend-deposit-option-description text-as-secondary text-xs", children: pureTransferOnly
|
|
233
|
+
? "Send tokens directly to deposit address"
|
|
234
|
+
: "Send any token — we'll convert it for you" })] })] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: depositClasses?.optionChevron || "anyspend-deposit-option-chevron text-as-secondary h-5 w-5" })] }), showFiatOption && ((0, jsx_runtime_1.jsxs)("button", { onClick: handleSelectFiat, className: depositClasses?.fiatButton ||
|
|
232
235
|
"anyspend-deposit-option-button anyspend-deposit-fiat-button border-border-primary hover:border-as-brand hover:bg-as-surface-secondary flex w-full items-center justify-between rounded-xl border p-4 text-left transition-all", children: [(0, jsx_runtime_1.jsxs)("div", { className: depositClasses?.optionContent || "anyspend-deposit-option-content flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)(CreditCardIcon_1.CreditCardIcon, { className: depositClasses?.optionIcon || "anyspend-deposit-option-icon h-10 w-10" }), (0, jsx_runtime_1.jsxs)("div", { className: depositClasses?.optionInfo || "anyspend-deposit-option-info", children: [(0, jsx_runtime_1.jsx)("span", { className: depositClasses?.optionTitle || "anyspend-deposit-option-title text-as-primary font-medium", children: "Fund with Fiat" }), (0, jsx_runtime_1.jsx)("p", { className: depositClasses?.optionDescription ||
|
|
233
236
|
"anyspend-deposit-option-description text-as-secondary text-xs", children: "Pay with card or bank transfer" })] })] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: depositClasses?.optionChevron || "anyspend-deposit-option-chevron text-as-secondary h-5 w-5" })] }))] }), (0, jsx_runtime_1.jsx)(WarningText_1.ChainWarningText, { chainId: destinationTokenChainId, classes: classes?.chainWarningText || { root: "mt-2" } })] })] }));
|
|
234
237
|
}
|
|
@@ -245,10 +248,21 @@ function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, paymentT
|
|
|
245
248
|
// `KNOWN_FUNDING_TOKENS` key — so `hasKnownDestination` is always true and this
|
|
246
249
|
// branch never fires for them. The guard is defensive for FUTURE callers that pass
|
|
247
250
|
// an unknown token together with `pureTransferOnly=true`.
|
|
251
|
+
// Only surface the fixed destination amount on the QR path when its decimals are trustworthy
|
|
252
|
+
// (a known funding token or a resolved API lookup) — otherwise `destinationToken.decimals`
|
|
253
|
+
// is the generic 18 fallback and formatting a 6-decimal token's wei against it would be off by
|
|
254
|
+
// 10^12. When unresolved we still show the destination token/chain, just without an amount.
|
|
255
|
+
const destinationDecimalsResolved = hasKnownDestination || !!destinationTokenData;
|
|
256
|
+
const destinationAmountDisplay = destinationTokenAmount &&
|
|
257
|
+
/^\d+$/.test(destinationTokenAmount) &&
|
|
258
|
+
BigInt(destinationTokenAmount) > 0n &&
|
|
259
|
+
destinationDecimalsResolved
|
|
260
|
+
? (0, number_1.formatTokenAmount)(BigInt(destinationTokenAmount), destinationToken.decimals, 6, false)
|
|
261
|
+
: undefined;
|
|
248
262
|
if (pureTransferOnly && !hasKnownDestination && !destinationTokenData && isDestinationTokenLoading) {
|
|
249
263
|
return ((0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("anyspend-deposit anyspend-deposit-qr-loading font-inter bg-as-surface-primary mx-auto w-full max-w-[460px] p-6", mode === "page" && "border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-deposit-qr-loading-content flex flex-col items-center justify-center gap-4 py-12", children: [(0, jsx_runtime_1.jsx)(react_1.Skeleton, { className: "h-8 w-8 rounded-full" }), (0, jsx_runtime_1.jsx)(react_1.Skeleton, { className: "h-4 w-40" })] }) }));
|
|
250
264
|
}
|
|
251
|
-
return ((0, jsx_runtime_1.jsx)(QRDeposit_1.QRDeposit, { mode: mode, recipientAddress: recipientAddress, destinationToken: destinationToken, destinationChainId: destinationTokenChainId, pureTransferOnly: pureTransferOnly, depositContractConfig: depositContractConfig, onBack: handleBack, onClose: onClose ?? handleBack, onSuccess: handleQRDepositSuccess, classes: classes?.qrDeposit }));
|
|
265
|
+
return ((0, jsx_runtime_1.jsx)(QRDeposit_1.QRDeposit, { mode: mode, recipientAddress: recipientAddress, destinationToken: destinationToken, destinationChainId: destinationTokenChainId, destinationAmountDisplay: destinationAmountDisplay, pureTransferOnly: pureTransferOnly, depositContractConfig: depositContractConfig, onBack: handleBack, onClose: onClose ?? handleBack, onSuccess: handleQRDepositSuccess, classes: classes?.qrDeposit }));
|
|
252
266
|
}
|
|
253
267
|
// Deposit view
|
|
254
268
|
return ((0, jsx_runtime_1.jsxs)("div", { className: depositClasses?.form || "anyspend-deposit anyspend-deposit-form relative", children: [shouldShowChainSelection && ((0, jsx_runtime_1.jsxs)("button", { onClick: handleBack, className: depositClasses?.backButton ||
|
|
@@ -14,6 +14,14 @@ export interface QRDepositProps {
|
|
|
14
14
|
destinationToken: components["schemas"]["Token"];
|
|
15
15
|
/** The destination chain ID */
|
|
16
16
|
destinationChainId: number;
|
|
17
|
+
/**
|
|
18
|
+
* Human-formatted destination amount (e.g. "9.365547"), shown as an APPROXIMATE
|
|
19
|
+
* target in swap mode only. The QR deposit path accepts an arbitrary sent amount,
|
|
20
|
+
* so this is never a guaranteed receive figure — the UI frames it as "any amount
|
|
21
|
+
* works". Omitted when no fixed amount is set or the destination decimals are
|
|
22
|
+
* unresolved (to avoid a mis-scaled number). Ignored in pure-transfer mode.
|
|
23
|
+
*/
|
|
24
|
+
destinationAmountDisplay?: string;
|
|
17
25
|
/**
|
|
18
26
|
* When true, the deposit is a PURE TRANSFER: the destination token/chain mirror
|
|
19
27
|
* the user's currently selected source token/chain, so the exact token the user
|
|
@@ -54,4 +62,4 @@ export interface QRDepositProps {
|
|
|
54
62
|
* onSuccess={(txHash) => console.log("Deposit complete:", txHash)}
|
|
55
63
|
* />
|
|
56
64
|
*/
|
|
57
|
-
export declare function QRDeposit({ mode, recipientAddress, sourceToken: sourceTokenProp, sourceChainId: sourceChainIdProp, destinationToken, destinationChainId, pureTransferOnly, creatorAddress, depositContractConfig, onBack, onClose, onOrderCreated, onSuccess, classes, }: QRDepositProps): import("react/jsx-runtime").JSX.Element;
|
|
65
|
+
export declare function QRDeposit({ mode, recipientAddress, sourceToken: sourceTokenProp, sourceChainId: sourceChainIdProp, destinationToken, destinationChainId, destinationAmountDisplay, pureTransferOnly, creatorAddress, depositContractConfig, onBack, onClose, onOrderCreated, onSuccess, classes, }: QRDepositProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -42,7 +42,7 @@ const DEFAULT_ETH_ON_BASE = {
|
|
|
42
42
|
* onSuccess={(txHash) => console.log("Deposit complete:", txHash)}
|
|
43
43
|
* />
|
|
44
44
|
*/
|
|
45
|
-
function QRDeposit({ mode = "modal", recipientAddress, sourceToken: sourceTokenProp, sourceChainId: sourceChainIdProp, destinationToken, destinationChainId, pureTransferOnly = false, creatorAddress, depositContractConfig, onBack, onClose, onOrderCreated, onSuccess, classes, }) {
|
|
45
|
+
function QRDeposit({ mode = "modal", recipientAddress, sourceToken: sourceTokenProp, sourceChainId: sourceChainIdProp, destinationToken, destinationChainId, destinationAmountDisplay, pureTransferOnly = false, creatorAddress, depositContractConfig, onBack, onClose, onOrderCreated, onSuccess, classes, }) {
|
|
46
46
|
const [copied, setCopied] = (0, react_2.useState)(false);
|
|
47
47
|
const [orderId, setOrderId] = (0, react_2.useState)();
|
|
48
48
|
const [globalAddress, setGlobalAddress] = (0, react_2.useState)();
|
|
@@ -174,8 +174,8 @@ function QRDeposit({ mode = "modal", recipientAddress, sourceToken: sourceTokenP
|
|
|
174
174
|
}
|
|
175
175
|
return ((0, jsx_runtime_1.jsx)("div", { className: classes?.container ||
|
|
176
176
|
(0, cn_1.cn)("anyspend-container anyspend-qr-deposit font-inter bg-as-surface-primary mx-auto w-full max-w-[460px] p-6", mode === "page" && "border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: (0, jsx_runtime_1.jsxs)("div", { className: classes?.content || "anyspend-qr-deposit-content flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: classes?.header || "anyspend-qr-header flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("button", { onClick: handleBack, className: classes?.backButton || "anyspend-qr-back-button text-as-secondary hover:text-as-primary", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }), (0, jsx_runtime_1.jsx)("h2", { className: classes?.title || "anyspend-qr-title text-as-primary text-base font-semibold", children: "Deposit" }), onClose ? ((0, jsx_runtime_1.jsx)("button", { onClick: handleClose, className: classes?.closeButton || "anyspend-qr-close-button text-as-secondary hover:text-as-primary", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "w-5" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.tokenSelectorContainer || "anyspend-qr-token-selector flex flex-col gap-1.5", children: [(0, jsx_runtime_1.jsx)("label", { className: classes?.tokenSelectorLabel || "anyspend-qr-token-label text-as-secondary text-sm", children: "Send" }), (0, jsx_runtime_1.jsx)(relay_kit_ui_1.TokenSelector, { chainIdsFilter: (0, anyspend_1.getAvailableChainIds)("from"), context: "from", fromChainWalletVMSupported: true, isValidAddress: true, lockedChainIds: (0, anyspend_1.getAvailableChainIds)("from"), multiWalletSupportEnabled: true, onAnalyticEvent: undefined, setToken: handleTokenSelect, supportedWalletVMs: ["evm"], token: undefined, trigger: (0, jsx_runtime_1.jsxs)(react_1.Button, { variant: "outline", role: "combobox", className: classes?.tokenSelectorTrigger ||
|
|
177
|
-
"anyspend-qr-token-trigger border-as-stroke bg-as-surface-secondary flex h-auto w-full items-center justify-between gap-2 rounded-xl border px-3 py-2.5", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [sourceToken.metadata?.logoURI ? ((0, jsx_runtime_1.jsx)(ChainTokenIcon_1.ChainTokenIcon, { chainUrl: anyspend_1.ALL_CHAINS[sourceChainId]?.logoUrl, tokenUrl: sourceToken.metadata.logoURI, className: "h-8 min-h-8 w-8 min-w-8" })) : ((0, jsx_runtime_1.jsx)("div", { className: "h-8 w-8 rounded-full bg-gray-700" })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-primary font-semibold", children: sourceToken.symbol }), (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary/70 text-xs", children: anyspend_1.ALL_CHAINS[sourceChainId]?.name ?? "Unknown" })] })] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-70" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.qrContent || "anyspend-qr-content border-as-stroke flex items-start gap-4 rounded-xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: classes?.qrCodeContainer || "anyspend-qr-code-container flex flex-col items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: classes?.qrCode || "anyspend-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: classes?.qrScanHint || "anyspend-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: classes?.addressContainer || "anyspend-qr-address-container flex flex-1 flex-col gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: classes?.addressLabel || "anyspend-qr-address-label text-as-secondary text-sm", children: "Deposit address:" }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.addressRow || "anyspend-qr-address-row flex items-start gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: classes?.address || "anyspend-qr-address text-as-primary break-all font-mono text-sm leading-relaxed", children: displayAddress }), (0, jsx_runtime_1.jsx)("button", { onClick: handleCopyAddress, className: classes?.addressCopyIcon ||
|
|
178
|
-
"anyspend-qr-copy-icon text-as-secondary hover:text-as-primary mt-0.5 shrink-0", children: copied ? (0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "h-4 w-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { className: "h-4 w-4" }) })] })] })] }), (0, jsx_runtime_1.jsx)(WarningText_1.ChainWarningText, { chainId: effectiveDestinationChainId }), (0, jsx_runtime_1.jsxs)(WarningText_1.WarningText, { children: ["Only send ", sourceToken.symbol, " on ", anyspend_1.ALL_CHAINS[sourceChainId]?.name ?? "the specified chain", ". Other tokens will not be converted."] }), isPureTransfer && isWatchingTransfer && ((0, jsx_runtime_1.jsxs)("div", { className: classes?.watchingIndicator ||
|
|
177
|
+
"anyspend-qr-token-trigger border-as-stroke bg-as-surface-secondary flex h-auto w-full items-center justify-between gap-2 rounded-xl border px-3 py-2.5", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [sourceToken.metadata?.logoURI ? ((0, jsx_runtime_1.jsx)(ChainTokenIcon_1.ChainTokenIcon, { chainUrl: anyspend_1.ALL_CHAINS[sourceChainId]?.logoUrl, tokenUrl: sourceToken.metadata.logoURI, className: "h-8 min-h-8 w-8 min-w-8" })) : ((0, jsx_runtime_1.jsx)("div", { className: "h-8 w-8 rounded-full bg-gray-700" })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-primary font-semibold", children: sourceToken.symbol }), (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary/70 text-xs", children: anyspend_1.ALL_CHAINS[sourceChainId]?.name ?? "Unknown" })] })] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-70" })] }) })] }), !isPureTransfer && ((0, jsx_runtime_1.jsxs)("div", { className: "anyspend-qr-receive flex flex-col gap-1.5", children: [(0, jsx_runtime_1.jsx)("label", { className: "anyspend-qr-receive-label text-as-secondary text-sm", children: "Receive" }), (0, jsx_runtime_1.jsxs)("div", { className: "anyspend-qr-receive-row border-as-stroke bg-as-surface-secondary flex w-full items-center gap-2 rounded-xl border px-3 py-2.5", children: [effectiveDestinationToken.metadata?.logoURI ? ((0, jsx_runtime_1.jsx)(ChainTokenIcon_1.ChainTokenIcon, { chainUrl: anyspend_1.ALL_CHAINS[effectiveDestinationChainId]?.logoUrl, tokenUrl: effectiveDestinationToken.metadata.logoURI, className: "h-8 min-h-8 w-8 min-w-8" })) : ((0, jsx_runtime_1.jsx)("div", { className: "h-8 w-8 rounded-full bg-gray-700" })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-primary font-semibold", children: effectiveDestinationToken.symbol || "Token" }), (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary/70 text-xs", children: anyspend_1.ALL_CHAINS[effectiveDestinationChainId]?.name ?? "Unknown" })] })] })] })), (0, jsx_runtime_1.jsxs)("div", { className: classes?.qrContent || "anyspend-qr-content border-as-stroke flex items-start gap-4 rounded-xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: classes?.qrCodeContainer || "anyspend-qr-code-container flex flex-col items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: classes?.qrCode || "anyspend-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: classes?.qrScanHint || "anyspend-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: classes?.addressContainer || "anyspend-qr-address-container flex flex-1 flex-col gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: classes?.addressLabel || "anyspend-qr-address-label text-as-secondary text-sm", children: "Deposit address:" }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.addressRow || "anyspend-qr-address-row flex items-start gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: classes?.address || "anyspend-qr-address text-as-primary break-all font-mono text-sm leading-relaxed", children: displayAddress }), (0, jsx_runtime_1.jsx)("button", { onClick: handleCopyAddress, className: classes?.addressCopyIcon ||
|
|
178
|
+
"anyspend-qr-copy-icon text-as-secondary hover:text-as-primary mt-0.5 shrink-0", children: copied ? (0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "h-4 w-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { className: "h-4 w-4" }) })] })] })] }), (0, jsx_runtime_1.jsx)(WarningText_1.ChainWarningText, { chainId: effectiveDestinationChainId }), isPureTransfer ? ((0, jsx_runtime_1.jsxs)(WarningText_1.WarningText, { children: ["Only send ", sourceToken.symbol, " on ", anyspend_1.ALL_CHAINS[sourceChainId]?.name ?? "the specified chain", ". Other tokens will not be converted."] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(WarningText_1.WarningText, { children: ["Only send ", sourceToken.symbol, " on ", anyspend_1.ALL_CHAINS[sourceChainId]?.name ?? "the specified chain", " to this address \u2014 it will be converted to ", effectiveDestinationToken.symbol || "the destination token", " on", " ", anyspend_1.ALL_CHAINS[effectiveDestinationChainId]?.name ?? "the destination chain", "."] }), destinationAmountDisplay && ((0, jsx_runtime_1.jsxs)("p", { className: "anyspend-qr-amount-hint text-as-secondary text-xs", children: ["Target \u2248 ", destinationAmountDisplay, " ", effectiveDestinationToken.symbol || "tokens", ". Any amount of", " ", sourceToken.symbol || "tokens", " works \u2014 you'll receive whatever your deposit converts to."] }))] })), isPureTransfer && isWatchingTransfer && ((0, jsx_runtime_1.jsxs)("div", { className: classes?.watchingIndicator ||
|
|
179
179
|
"anyspend-qr-watching flex items-center justify-center gap-2 rounded-lg bg-blue-500/10 p-3", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin text-blue-500" }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-blue-500", children: "Watching for incoming transfer..." })] })), (0, jsx_runtime_1.jsx)("button", { onClick: handleCopyAddress, className: classes?.copyButton ||
|
|
180
180
|
"anyspend-qr-copy-button flex w-full items-center justify-center gap-2 rounded-xl bg-blue-500 py-3.5 font-medium text-white transition-all hover:bg-blue-600", children: "Copy deposit address" })] }) }));
|
|
181
181
|
}
|
|
@@ -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;
|