@b3dotfun/sdk 0.0.31 → 0.0.32-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +2 -2
  2. package/dist/cjs/anyspend/react/components/common/OrderDetails.d.ts +1 -0
  3. package/dist/cjs/anyspend/react/components/common/OrderDetails.js +7 -3
  4. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
  5. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +47 -17
  6. package/dist/cjs/anyspend/react/hooks/useSigMint.d.ts +1 -1
  7. package/dist/cjs/global-account/react/components/B3Provider/types.d.ts +4 -5
  8. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +53 -1
  9. package/dist/cjs/global-account/react/hooks/useSiwe.js +5 -5
  10. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +2 -2
  11. package/dist/esm/anyspend/react/components/common/OrderDetails.d.ts +1 -0
  12. package/dist/esm/anyspend/react/components/common/OrderDetails.js +7 -3
  13. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
  14. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +49 -19
  15. package/dist/esm/anyspend/react/hooks/useSigMint.d.ts +1 -1
  16. package/dist/esm/global-account/react/components/B3Provider/types.d.ts +4 -5
  17. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +54 -5
  18. package/dist/esm/global-account/react/hooks/useSiwe.js +5 -5
  19. package/dist/types/anyspend/react/components/common/OrderDetails.d.ts +1 -0
  20. package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +4 -1
  21. package/dist/types/anyspend/react/hooks/useSigMint.d.ts +1 -1
  22. package/dist/types/global-account/react/components/B3Provider/types.d.ts +4 -5
  23. package/package.json +2 -2
  24. package/src/anyspend/react/components/AnyspendDepositHype.tsx +2 -1
  25. package/src/anyspend/react/components/common/OrderDetails.tsx +6 -2
  26. package/src/anyspend/react/hooks/useAnyspendFlow.ts +53 -16
  27. package/src/global-account/react/components/B3Provider/B3Provider.native.tsx +2 -2
  28. package/src/global-account/react/components/B3Provider/B3Provider.tsx +2 -2
  29. package/src/global-account/react/components/B3Provider/types.ts +4 -5
  30. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +147 -3
  31. package/src/global-account/react/hooks/useSiwe.tsx +5 -5
@@ -57,6 +57,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
57
57
  sourceTokenAddress,
58
58
  sourceTokenChainId,
59
59
  slippage: SLIPPAGE_PERCENT,
60
+ disableUrlParamManagement: true,
60
61
  });
61
62
  // Button state logic
62
63
  const btnInfo = (0, react_3.useMemo)(() => {
@@ -233,8 +234,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
233
234
  const orderDetailsView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto w-[460px] max-w-full", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex flex-col gap-4", children: oat && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(OrderStatus_1.OrderStatus, { order: oat.data.order, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod }), (0, jsx_runtime_1.jsx)(OrderDetails_1.OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTx: oat.data.relayTx, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: paymentType === "fiat" ? CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE : selectedCryptoPaymentMethod, onBack: () => {
234
235
  setOrderId(undefined);
235
236
  setActivePanel(useAnyspendFlow_1.PanelView.MAIN);
236
- onSuccess?.();
237
- } })] })) }) }));
237
+ }, disableUrlParamManagement: true })] })) }) }));
238
238
  // Loading view
239
239
  const loadingView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto flex w-full flex-col items-center gap-4 p-5", children: (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary", children: "Loading order details..." }) }));
240
240
  // Panel views
@@ -9,6 +9,7 @@ interface OrderDetailsProps {
9
9
  refundTxs: components["schemas"]["RefundTx"][] | null;
10
10
  cryptoPaymentMethod?: CryptoPaymentMethodType;
11
11
  onBack?: () => void;
12
+ disableUrlParamManagement?: boolean;
12
13
  }
13
14
  export declare const OrderDetails: import("react").NamedExoticComponent<OrderDetailsProps>;
14
15
  export declare const OrderDetailsLoadingView: import("react/jsx-runtime").JSX.Element;
@@ -130,7 +130,7 @@ function roundTokenAmount(amount) {
130
130
  const roundedDecimalPart = digits.join("");
131
131
  return `${wholePart}.${roundedDecimalPart}`;
132
132
  }
133
- exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal", order, depositTxs, relayTx, executeTx, refundTxs, cryptoPaymentMethod, onBack, }) {
133
+ exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal", order, depositTxs, relayTx, executeTx, refundTxs, cryptoPaymentMethod, onBack, disableUrlParamManagement = false, }) {
134
134
  const router = (0, hooks_1.useRouter)();
135
135
  const searchParams = (0, hooks_1.useSearchParams)();
136
136
  // Read crypto payment method from URL parameters
@@ -196,12 +196,16 @@ exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal",
196
196
  };
197
197
  // When waitingForDeposit is true, we show a message to the user to wait for the deposit to be processed.
198
198
  const setWaitingForDeposit = (0, react_5.useCallback)(() => {
199
+ if (disableUrlParamManagement)
200
+ return;
199
201
  const params = new URLSearchParams(searchParams.toString());
200
202
  params.set("waitingForDeposit", "true");
201
203
  router.push(`?${params}`);
202
- }, [router, searchParams]);
204
+ }, [router, searchParams, disableUrlParamManagement]);
203
205
  // Clean up URL parameters before closing modal or navigating back
204
206
  const cleanupUrlParams = (0, react_5.useCallback)(() => {
207
+ if (disableUrlParamManagement)
208
+ return;
205
209
  const params = new URLSearchParams(searchParams.toString());
206
210
  params.delete("waitingForDeposit");
207
211
  params.delete("orderId");
@@ -210,7 +214,7 @@ exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal",
210
214
  if (params.toString() !== searchParams.toString()) {
211
215
  router.push(`?${params}`);
212
216
  }
213
- }, [router, searchParams]);
217
+ }, [router, searchParams, disableUrlParamManagement]);
214
218
  // Helper functions that clean up URL params before executing actions
215
219
  const handleCloseModal = (0, react_5.useCallback)(() => {
216
220
  cleanupUrlParams();
@@ -19,8 +19,9 @@ interface UseAnyspendFlowProps {
19
19
  sourceTokenAddress?: string;
20
20
  sourceTokenChainId?: number;
21
21
  slippage?: number;
22
+ disableUrlParamManagement?: boolean;
22
23
  }
23
- export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, }: UseAnyspendFlowProps): {
24
+ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, disableUrlParamManagement, }: UseAnyspendFlowProps): {
24
25
  activePanel: PanelView;
25
26
  setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
26
27
  orderId: string | undefined;
@@ -75,6 +76,8 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
75
76
  setSelectedRecipientAddress: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
76
77
  recipientName: string | null | undefined;
77
78
  globalAddress: string | undefined;
79
+ hasEnoughBalance: boolean;
80
+ isBalanceLoading: boolean;
78
81
  anyspendQuote: {
79
82
  success: boolean;
80
83
  message: string;
@@ -11,6 +11,7 @@ const react_3 = require("react");
11
11
  const sonner_1 = require("sonner");
12
12
  const viem_1 = require("viem");
13
13
  const chains_1 = require("viem/chains");
14
+ const wagmi_1 = require("wagmi");
14
15
  const CryptoPaymentMethod_1 = require("../components/common/CryptoPaymentMethod");
15
16
  const FiatPaymentMethod_1 = require("../components/common/FiatPaymentMethod");
16
17
  var PanelView;
@@ -22,7 +23,7 @@ var PanelView;
22
23
  PanelView[PanelView["ORDER_DETAILS"] = 4] = "ORDER_DETAILS";
23
24
  PanelView[PanelView["LOADING"] = 5] = "LOADING";
24
25
  })(PanelView || (exports.PanelView = PanelView = {}));
25
- function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, }) {
26
+ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, disableUrlParamManagement = false, }) {
26
27
  const searchParams = (0, react_2.useSearchParamsSSR)();
27
28
  const router = (0, react_2.useRouter)();
28
29
  // Panel and order state
@@ -42,6 +43,7 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
42
43
  const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = (0, react_3.useState)(FiatPaymentMethod_1.FiatPaymentMethod.NONE);
43
44
  // Recipient state
44
45
  const { address: globalAddress } = (0, react_2.useAccountWallet)();
46
+ const { address: wagmiAddress } = (0, wagmi_1.useAccount)();
45
47
  const [selectedRecipientAddress, setSelectedRecipientAddress] = (0, react_3.useState)(recipientAddress);
46
48
  const recipientProfile = (0, react_2.useProfile)({ address: selectedRecipientAddress, fresh: true });
47
49
  const recipientName = recipientProfile.data?.name;
@@ -51,11 +53,34 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
51
53
  setSelectedRecipientAddress(globalAddress);
52
54
  }
53
55
  }, [selectedRecipientAddress, globalAddress]);
56
+ // Check token balance for crypto payments
57
+ const { rawBalance, isLoading: isBalanceLoading } = (0, react_2.useTokenBalance)({
58
+ token: selectedSrcToken,
59
+ address: wagmiAddress,
60
+ });
61
+ // Check if user has enough balance
62
+ const hasEnoughBalance = (0, react_3.useMemo)(() => {
63
+ if (!rawBalance || isBalanceLoading || paymentType !== "crypto")
64
+ return false;
65
+ try {
66
+ const requiredAmount = (0, viem_1.parseUnits)(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
67
+ return rawBalance >= requiredAmount;
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }, [rawBalance, srcAmount, selectedSrcToken.decimals, isBalanceLoading, paymentType]);
73
+ // Auto-set crypto payment method based on balance
54
74
  (0, react_3.useEffect)(() => {
55
- if (paymentType === "crypto") {
56
- setSelectedCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.CONNECT_WALLET);
75
+ if (paymentType === "crypto" && !isBalanceLoading) {
76
+ if (hasEnoughBalance) {
77
+ setSelectedCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.CONNECT_WALLET);
78
+ }
79
+ else {
80
+ setSelectedCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.TRANSFER_CRYPTO);
81
+ }
57
82
  }
58
- }, [paymentType]);
83
+ }, [paymentType, hasEnoughBalance, isBalanceLoading]);
59
84
  // Fetch specific token when sourceTokenAddress and sourceTokenChainId are provided
60
85
  (0, react_3.useEffect)(() => {
61
86
  const fetchSourceToken = async () => {
@@ -114,14 +139,14 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
114
139
  }, [anyspendQuote, slippage]);
115
140
  // Update useEffect for URL parameter to not override loadOrder
116
141
  (0, react_3.useEffect)(() => {
117
- if (loadOrder)
118
- return; // Skip if we have a loadOrder
142
+ if (loadOrder || disableUrlParamManagement)
143
+ return; // Skip if we have a loadOrder or URL param management is disabled
119
144
  const orderIdParam = searchParams.get("orderId");
120
145
  if (orderIdParam) {
121
146
  setOrderId(orderIdParam);
122
147
  setActivePanel(PanelView.ORDER_DETAILS);
123
148
  }
124
- }, [searchParams, loadOrder]);
149
+ }, [searchParams, loadOrder, disableUrlParamManagement]);
125
150
  // Order creation hooks
126
151
  const { createOrder, isCreatingOrder } = (0, react_1.useAnyspendCreateOrder)({
127
152
  onSuccess: data => {
@@ -130,17 +155,19 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
130
155
  setActivePanel(PanelView.ORDER_DETAILS);
131
156
  onOrderSuccess?.(newOrderId);
132
157
  // Add orderId and payment method to URL for persistence
133
- const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
134
- params.set("orderId", newOrderId);
135
- if (selectedCryptoPaymentMethod !== CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE) {
136
- console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
137
- params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
138
- }
139
- else {
140
- console.log("Payment method is NONE, not setting in URL");
158
+ if (!disableUrlParamManagement) {
159
+ const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
160
+ params.set("orderId", newOrderId);
161
+ if (selectedCryptoPaymentMethod !== CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE) {
162
+ console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
163
+ params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
164
+ }
165
+ else {
166
+ console.log("Payment method is NONE, not setting in URL");
167
+ }
168
+ console.log("Final URL params:", params.toString());
169
+ router.push(`${window.location.pathname}?${params.toString()}`);
141
170
  }
142
- console.log("Final URL params:", params.toString());
143
- router.push(`${window.location.pathname}?${params.toString()}`);
144
171
  },
145
172
  onError: error => {
146
173
  console.error(error);
@@ -196,6 +223,9 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
196
223
  setSelectedRecipientAddress,
197
224
  recipientName,
198
225
  globalAddress,
226
+ // Balance check
227
+ hasEnoughBalance,
228
+ isBalanceLoading,
199
229
  // Quote data
200
230
  anyspendQuote,
201
231
  isLoadingAnyspendQuote,
@@ -72,7 +72,7 @@ export declare const useSigMintCollection: ({ address, chainId }: FindByAddressP
72
72
  description?: string | undefined;
73
73
  createdAt?: string | undefined;
74
74
  updatedAt?: string | undefined;
75
- status?: "DRAFT" | "ACTIVE" | "INACTIVE" | undefined;
75
+ status?: "ACTIVE" | "DRAFT" | "INACTIVE" | undefined;
76
76
  metadata?: {} | undefined;
77
77
  logoURI?: string | undefined;
78
78
  creator?: string | undefined;
@@ -1,17 +1,16 @@
1
- import { Account } from "thirdweb/wallets";
2
- import { User } from "../../../../global-account/types/b3-api.types";
3
- import { Wallet } from "thirdweb/wallets";
1
+ import { Users } from "@b3dotfun/b3-api";
4
2
  import { PermissionsConfig } from "../../../../global-account/types/permissions";
3
+ import { Account, Wallet } from "thirdweb/wallets";
5
4
  /**
6
5
  * Context type for B3Provider
7
6
  */
8
7
  export interface B3ContextType {
9
8
  account?: Account;
10
9
  automaticallySetFirstEoa: boolean;
11
- user?: User;
10
+ user?: Users;
12
11
  setWallet: (wallet: Wallet) => void;
13
12
  wallet?: Wallet;
14
- setUser: (user?: User) => void;
13
+ setUser: (user?: Users) => void;
15
14
  initialized: boolean;
16
15
  ready: boolean;
17
16
  environment?: "development" | "production";
@@ -1,13 +1,18 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.ManageAccount = ManageAccount;
4
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const app_1 = __importDefault(require("../../../../global-account/app"));
5
9
  const react_1 = require("../../../../global-account/react");
6
10
  const SignOutIcon_1 = require("../../../../global-account/react/components/icons/SignOutIcon");
7
11
  const formatNumber_1 = require("../../../../shared/utils/formatNumber");
8
12
  const thirdweb_1 = require("../../../../shared/utils/thirdweb");
9
13
  const lucide_react_1 = require("lucide-react");
10
14
  const react_2 = require("react");
15
+ const sonner_1 = require("sonner");
11
16
  const react_3 = require("thirdweb/react");
12
17
  const viem_1 = require("viem");
13
18
  const profileDisplay_1 = require("../../utils/profileDisplay");
@@ -55,6 +60,45 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
55
60
  const { data: profilesRaw = [], isLoading: isLoadingProfiles } = (0, react_3.useProfiles)({ client: thirdweb_1.client });
56
61
  const { mutate: unlinkProfile, isPending: isUnlinking } = (0, react_3.useUnlinkProfile)();
57
62
  const { setB3ModalOpen, setB3ModalContentType, isLinking } = (0, react_1.useModalStore)();
63
+ const { user, setUser } = (0, react_1.useB3)();
64
+ const [isUpdatingCode, setIsUpdatingCode] = (0, react_2.useState)(false);
65
+ const [newReferralCode, setNewReferralCode] = (0, react_2.useState)("");
66
+ const [isEditingCode, setIsEditingCode] = (0, react_2.useState)(false);
67
+ const referallCodeRef = (0, react_2.useRef)(null);
68
+ const { data: referrals, isLoading: isLoadingReferrals } = (0, react_1.useQueryB3)("referrals", "find", { query: { referrerId: user?.userId } }, !!user?.userId);
69
+ // Fetch referred users
70
+ const currentReferralCode = user?.referralCode || user?.userId || "";
71
+ const handleCopyCode = async () => {
72
+ try {
73
+ await navigator.clipboard.writeText(currentReferralCode);
74
+ sonner_1.toast.success("Referral code copied to clipboard!");
75
+ }
76
+ catch (error) {
77
+ sonner_1.toast.error("Failed to copy referral code");
78
+ }
79
+ };
80
+ const handleUpdateReferralCode = async () => {
81
+ if (!newReferralCode)
82
+ return;
83
+ setIsUpdatingCode(true);
84
+ try {
85
+ // @ts-expect-error - setReferralCode is not typed for some reason
86
+ const newUser = await app_1.default.service("users").setReferralCode({
87
+ userId: user?.userId,
88
+ referralCode: newReferralCode,
89
+ });
90
+ setUser(newUser);
91
+ sonner_1.toast.success("Referral code updated successfully!");
92
+ setIsEditingCode(false);
93
+ setNewReferralCode("");
94
+ }
95
+ catch (error) {
96
+ sonner_1.toast.error("Failed to update referral code");
97
+ }
98
+ finally {
99
+ setIsUpdatingCode(false);
100
+ }
101
+ };
58
102
  const profiles = profilesRaw
59
103
  .filter((profile) => !["custom_auth_endpoint", "siwe"].includes(profile.type))
60
104
  .map((profile) => ({
@@ -91,7 +135,15 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
91
135
  },
92
136
  });
93
137
  };
94
- return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-8", children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), (0, jsx_runtime_1.jsxs)(react_1.Button, { className: "bg-b3-primary-wash hover:bg-b3-primary-wash/70 flex items-center gap-2 rounded-full px-4 py-2", onClick: handleOpenLinkModal, disabled: isLinking, children: [isLinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.LinkIcon, { size: 16, className: "text-b3-primary-blue" })), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center py-8", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: profiles.map(profile => ((0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? ((0, jsx_runtime_1.jsx)("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : ((0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium bg-b3-primary-wash rounded px-2 py-0.5 text-xs", children: profile.type.toUpperCase() })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "ghost", size: "icon", className: "text-b3-grey hover:text-b3-negative", onClick: () => handleUnlink(profile), disabled: unlinkingAccountId === profile.title || isUnlinking, children: unlinkingAccountId === profile.title || isUnlinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Account Preferences" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line rounded-xl p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Dark Mode" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Switch between light and dark theme" })] }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash h-6 w-12 rounded-full" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), (0, jsx_runtime_1.jsx)("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3 apps" })] }), (0, jsx_runtime_1.jsx)("button", { className: "text-b3-grey hover:text-b3-grey/80 hover:bg-b3-line border-b3-line flex size-12 items-center justify-center rounded-full border", onClick: onLogoutEnhanced, children: logoutLoading ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : (0, jsx_runtime_1.jsx)(SignOutIcon_1.SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
138
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-8", children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), (0, jsx_runtime_1.jsxs)(react_1.Button, { className: "bg-b3-primary-wash hover:bg-b3-primary-wash/70 flex items-center gap-2 rounded-full px-4 py-2", onClick: handleOpenLinkModal, disabled: isLinking, children: [isLinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.LinkIcon, { size: 16, className: "text-b3-primary-blue" })), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center py-8", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: profiles.map(profile => ((0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? ((0, jsx_runtime_1.jsx)("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : ((0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium bg-b3-primary-wash rounded px-2 py-0.5 text-xs", children: profile.type.toUpperCase() })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "ghost", size: "icon", className: "text-b3-grey hover:text-b3-negative", onClick: () => handleUnlink(profile), disabled: unlinkingAccountId === profile.title || isUnlinking, children: unlinkingAccountId === profile.title || isUnlinking ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Referrals" }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line rounded-xl p-4", children: [isEditingCode && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Your Referral Code" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Share this code with friends to earn rewards" })] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [!isEditingCode && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Your Referral Code" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Share this code with friends to earn rewards" })] })), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: isEditingCode ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("input", { type: "text", value: newReferralCode, onChange: e => setNewReferralCode(e.target.value), className: "rounded-lg border border-gray-200 bg-white px-3 py-1.5 text-sm", placeholder: "Enter new code", ref: referallCodeRef }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", onClick: handleUpdateReferralCode, disabled: isUpdatingCode || !newReferralCode, children: isUpdatingCode ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin" }) : "Save" }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", variant: "ghost", onClick: () => {
139
+ setIsEditingCode(false);
140
+ setNewReferralCode("");
141
+ }, children: "Cancel" })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "rounded-lg border border-gray-200 bg-white px-3 py-1.5 text-sm", children: currentReferralCode }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "icon", variant: "ghost", onClick: handleCopyCode, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { className: "h-4 w-4" }) }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "icon", variant: "ghost", onClick: () => {
142
+ setIsEditingCode(true);
143
+ setTimeout(() => {
144
+ referallCodeRef.current?.focus();
145
+ }, 100);
146
+ }, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { className: "h-4 w-4" }) })] })) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-line rounded-xl p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold mb-4", children: "Referred Users" }), isLoadingReferrals ? ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center py-4", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-6 w-6 animate-spin text-gray-400" }) })) : referrals?.data?.length ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: referrals.data.map((referral) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between rounded-lg bg-white p-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-sm font-medium", children: referral.referreeId }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm text-gray-500", children: new Date(referral.createdAt).toLocaleDateString() })] }, String(referral._id)))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "py-4 text-center text-gray-500", children: "No referred users yet" }))] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Account Preferences" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line rounded-xl p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Dark Mode" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Switch between light and dark theme" })] }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash h-6 w-12 rounded-full" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), (0, jsx_runtime_1.jsx)("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3 apps" })] }), (0, jsx_runtime_1.jsx)("button", { className: "text-b3-grey hover:text-b3-grey/80 hover:bg-b3-line border-b3-line flex size-12 items-center justify-center rounded-full border", onClick: onLogoutEnhanced, children: logoutLoading ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : (0, jsx_runtime_1.jsx)(SignOutIcon_1.SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
95
147
  };
96
148
  return ((0, jsx_runtime_1.jsx)("div", { className: "b3-manage-account bg-b3-background flex flex-col rounded-xl", children: (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: (0, jsx_runtime_1.jsxs)(react_1.TabsPrimitive, { defaultValue: activeTab, onValueChange: value => {
97
149
  const tab = value;
@@ -9,11 +9,11 @@ const debug_1 = __importDefault(require("../../../shared/utils/debug"));
9
9
  const react_1 = require("react");
10
10
  const useSearchParamsSSR_1 = require("./useSearchParamsSSR");
11
11
  function useSiwe() {
12
- const referrerId = (0, useSearchParamsSSR_1.useSearchParam)("referrerId");
12
+ const referralCode = (0, useSearchParamsSSR_1.useSearchParam)("referralCode");
13
13
  const authenticate = (0, react_1.useCallback)(async (account, partnerId) => {
14
14
  if (!account || !account.signMessage)
15
15
  throw new Error("Account not found");
16
- console.log("@@useAuthenticate:referrerId", referrerId);
16
+ console.log("@@useAuthenticate:referralCode", referralCode);
17
17
  // generate challenge
18
18
  const challenge = await app_1.default.service("global-accounts-challenge").create({
19
19
  address: account.address,
@@ -31,13 +31,13 @@ function useSiwe() {
31
31
  signature,
32
32
  serverSignature: challenge.serverSignature,
33
33
  nonce: challenge.nonce,
34
- // http://localhost:5173/?referrerId=cd8fda06-3840-43d3-8f35-ae9472a13759
35
- referrerId: referrerId,
34
+ // http://localhost:5173/?referralCode=GIO2
35
+ referralCode,
36
36
  partnerId: partnerId,
37
37
  });
38
38
  (0, debug_1.default)("@@useAuthenticate:response", response);
39
39
  return response;
40
- }, [referrerId]);
40
+ }, [referralCode]);
41
41
  return {
42
42
  authenticate,
43
43
  };
@@ -50,6 +50,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
50
50
  sourceTokenAddress,
51
51
  sourceTokenChainId,
52
52
  slippage: SLIPPAGE_PERCENT,
53
+ disableUrlParamManagement: true,
53
54
  });
54
55
  // Button state logic
55
56
  const btnInfo = useMemo(() => {
@@ -226,8 +227,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
226
227
  const orderDetailsView = (_jsx("div", { className: "mx-auto w-[460px] max-w-full", children: _jsx("div", { className: "relative flex flex-col gap-4", children: oat && (_jsxs(_Fragment, { children: [_jsx(OrderStatus, { order: oat.data.order, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod }), _jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTx: oat.data.relayTx, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, cryptoPaymentMethod: paymentType === "fiat" ? CryptoPaymentMethodType.NONE : selectedCryptoPaymentMethod, onBack: () => {
227
228
  setOrderId(undefined);
228
229
  setActivePanel(PanelView.MAIN);
229
- onSuccess?.();
230
- } })] })) }) }));
230
+ }, disableUrlParamManagement: true })] })) }) }));
231
231
  // Loading view
232
232
  const loadingView = (_jsx("div", { className: "mx-auto flex w-full flex-col items-center gap-4 p-5", children: _jsx("div", { className: "text-as-primary", children: "Loading order details..." }) }));
233
233
  // Panel views
@@ -9,6 +9,7 @@ interface OrderDetailsProps {
9
9
  refundTxs: components["schemas"]["RefundTx"][] | null;
10
10
  cryptoPaymentMethod?: CryptoPaymentMethodType;
11
11
  onBack?: () => void;
12
+ disableUrlParamManagement?: boolean;
12
13
  }
13
14
  export declare const OrderDetails: import("react").NamedExoticComponent<OrderDetailsProps>;
14
15
  export declare const OrderDetailsLoadingView: import("react/jsx-runtime").JSX.Element;
@@ -124,7 +124,7 @@ function roundTokenAmount(amount) {
124
124
  const roundedDecimalPart = digits.join("");
125
125
  return `${wholePart}.${roundedDecimalPart}`;
126
126
  }
127
- export const OrderDetails = memo(function OrderDetails({ mode = "modal", order, depositTxs, relayTx, executeTx, refundTxs, cryptoPaymentMethod, onBack, }) {
127
+ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order, depositTxs, relayTx, executeTx, refundTxs, cryptoPaymentMethod, onBack, disableUrlParamManagement = false, }) {
128
128
  const router = useRouter();
129
129
  const searchParams = useSearchParams();
130
130
  // Read crypto payment method from URL parameters
@@ -190,12 +190,16 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
190
190
  };
191
191
  // When waitingForDeposit is true, we show a message to the user to wait for the deposit to be processed.
192
192
  const setWaitingForDeposit = useCallback(() => {
193
+ if (disableUrlParamManagement)
194
+ return;
193
195
  const params = new URLSearchParams(searchParams.toString());
194
196
  params.set("waitingForDeposit", "true");
195
197
  router.push(`?${params}`);
196
- }, [router, searchParams]);
198
+ }, [router, searchParams, disableUrlParamManagement]);
197
199
  // Clean up URL parameters before closing modal or navigating back
198
200
  const cleanupUrlParams = useCallback(() => {
201
+ if (disableUrlParamManagement)
202
+ return;
199
203
  const params = new URLSearchParams(searchParams.toString());
200
204
  params.delete("waitingForDeposit");
201
205
  params.delete("orderId");
@@ -204,7 +208,7 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
204
208
  if (params.toString() !== searchParams.toString()) {
205
209
  router.push(`?${params}`);
206
210
  }
207
- }, [router, searchParams]);
211
+ }, [router, searchParams, disableUrlParamManagement]);
208
212
  // Helper functions that clean up URL params before executing actions
209
213
  const handleCloseModal = useCallback(() => {
210
214
  cleanupUrlParams();
@@ -19,8 +19,9 @@ interface UseAnyspendFlowProps {
19
19
  sourceTokenAddress?: string;
20
20
  sourceTokenChainId?: number;
21
21
  slippage?: number;
22
+ disableUrlParamManagement?: boolean;
22
23
  }
23
- export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, }: UseAnyspendFlowProps): {
24
+ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, disableUrlParamManagement, }: UseAnyspendFlowProps): {
24
25
  activePanel: PanelView;
25
26
  setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
26
27
  orderId: string | undefined;
@@ -75,6 +76,8 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
75
76
  setSelectedRecipientAddress: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
76
77
  recipientName: string | null | undefined;
77
78
  globalAddress: string | undefined;
79
+ hasEnoughBalance: boolean;
80
+ isBalanceLoading: boolean;
78
81
  anyspendQuote: {
79
82
  success: boolean;
80
83
  message: string;
@@ -1,12 +1,13 @@
1
1
  import { B3_TOKEN, getDefaultToken, USDC_BASE } from "../../../anyspend/index.js";
2
2
  import { useAnyspendCreateOnrampOrder, useAnyspendCreateOrder, useAnyspendOrderAndTransactions, useAnyspendQuote, useGeoOnrampOptions, } from "../../../anyspend/react/index.js";
3
3
  import { anyspendService } from "../../../anyspend/services/anyspend.js";
4
- import { useAccountWallet, useProfile, useRouter, useSearchParamsSSR } from "../../../global-account/react/index.js";
4
+ import { useAccountWallet, useProfile, useRouter, useSearchParamsSSR, useTokenBalance, } from "../../../global-account/react/index.js";
5
5
  import { formatTokenAmount, formatUnits } from "../../../shared/utils/number.js";
6
- import { useEffect, useState } from "react";
6
+ import { useEffect, useMemo, useState } from "react";
7
7
  import { toast } from "sonner";
8
8
  import { parseUnits } from "viem";
9
9
  import { base, mainnet } from "viem/chains";
10
+ import { useAccount } from "wagmi";
10
11
  import { CryptoPaymentMethodType } from "../components/common/CryptoPaymentMethod.js";
11
12
  import { FiatPaymentMethod } from "../components/common/FiatPaymentMethod.js";
12
13
  export var PanelView;
@@ -18,7 +19,7 @@ export var PanelView;
18
19
  PanelView[PanelView["ORDER_DETAILS"] = 4] = "ORDER_DETAILS";
19
20
  PanelView[PanelView["LOADING"] = 5] = "LOADING";
20
21
  })(PanelView || (PanelView = {}));
21
- export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, }) {
22
+ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, disableUrlParamManagement = false, }) {
22
23
  const searchParams = useSearchParamsSSR();
23
24
  const router = useRouter();
24
25
  // Panel and order state
@@ -38,6 +39,7 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
38
39
  const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState(FiatPaymentMethod.NONE);
39
40
  // Recipient state
40
41
  const { address: globalAddress } = useAccountWallet();
42
+ const { address: wagmiAddress } = useAccount();
41
43
  const [selectedRecipientAddress, setSelectedRecipientAddress] = useState(recipientAddress);
42
44
  const recipientProfile = useProfile({ address: selectedRecipientAddress, fresh: true });
43
45
  const recipientName = recipientProfile.data?.name;
@@ -47,11 +49,34 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
47
49
  setSelectedRecipientAddress(globalAddress);
48
50
  }
49
51
  }, [selectedRecipientAddress, globalAddress]);
52
+ // Check token balance for crypto payments
53
+ const { rawBalance, isLoading: isBalanceLoading } = useTokenBalance({
54
+ token: selectedSrcToken,
55
+ address: wagmiAddress,
56
+ });
57
+ // Check if user has enough balance
58
+ const hasEnoughBalance = useMemo(() => {
59
+ if (!rawBalance || isBalanceLoading || paymentType !== "crypto")
60
+ return false;
61
+ try {
62
+ const requiredAmount = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
63
+ return rawBalance >= requiredAmount;
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }, [rawBalance, srcAmount, selectedSrcToken.decimals, isBalanceLoading, paymentType]);
69
+ // Auto-set crypto payment method based on balance
50
70
  useEffect(() => {
51
- if (paymentType === "crypto") {
52
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
71
+ if (paymentType === "crypto" && !isBalanceLoading) {
72
+ if (hasEnoughBalance) {
73
+ setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
74
+ }
75
+ else {
76
+ setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
77
+ }
53
78
  }
54
- }, [paymentType]);
79
+ }, [paymentType, hasEnoughBalance, isBalanceLoading]);
55
80
  // Fetch specific token when sourceTokenAddress and sourceTokenChainId are provided
56
81
  useEffect(() => {
57
82
  const fetchSourceToken = async () => {
@@ -110,14 +135,14 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
110
135
  }, [anyspendQuote, slippage]);
111
136
  // Update useEffect for URL parameter to not override loadOrder
112
137
  useEffect(() => {
113
- if (loadOrder)
114
- return; // Skip if we have a loadOrder
138
+ if (loadOrder || disableUrlParamManagement)
139
+ return; // Skip if we have a loadOrder or URL param management is disabled
115
140
  const orderIdParam = searchParams.get("orderId");
116
141
  if (orderIdParam) {
117
142
  setOrderId(orderIdParam);
118
143
  setActivePanel(PanelView.ORDER_DETAILS);
119
144
  }
120
- }, [searchParams, loadOrder]);
145
+ }, [searchParams, loadOrder, disableUrlParamManagement]);
121
146
  // Order creation hooks
122
147
  const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
123
148
  onSuccess: data => {
@@ -126,17 +151,19 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
126
151
  setActivePanel(PanelView.ORDER_DETAILS);
127
152
  onOrderSuccess?.(newOrderId);
128
153
  // Add orderId and payment method to URL for persistence
129
- const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
130
- params.set("orderId", newOrderId);
131
- if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
132
- console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
133
- params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
134
- }
135
- else {
136
- console.log("Payment method is NONE, not setting in URL");
154
+ if (!disableUrlParamManagement) {
155
+ const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
156
+ params.set("orderId", newOrderId);
157
+ if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
158
+ console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
159
+ params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
160
+ }
161
+ else {
162
+ console.log("Payment method is NONE, not setting in URL");
163
+ }
164
+ console.log("Final URL params:", params.toString());
165
+ router.push(`${window.location.pathname}?${params.toString()}`);
137
166
  }
138
- console.log("Final URL params:", params.toString());
139
- router.push(`${window.location.pathname}?${params.toString()}`);
140
167
  },
141
168
  onError: error => {
142
169
  console.error(error);
@@ -192,6 +219,9 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
192
219
  setSelectedRecipientAddress,
193
220
  recipientName,
194
221
  globalAddress,
222
+ // Balance check
223
+ hasEnoughBalance,
224
+ isBalanceLoading,
195
225
  // Quote data
196
226
  anyspendQuote,
197
227
  isLoadingAnyspendQuote,
@@ -72,7 +72,7 @@ export declare const useSigMintCollection: ({ address, chainId }: FindByAddressP
72
72
  description?: string | undefined;
73
73
  createdAt?: string | undefined;
74
74
  updatedAt?: string | undefined;
75
- status?: "DRAFT" | "ACTIVE" | "INACTIVE" | undefined;
75
+ status?: "ACTIVE" | "DRAFT" | "INACTIVE" | undefined;
76
76
  metadata?: {} | undefined;
77
77
  logoURI?: string | undefined;
78
78
  creator?: string | undefined;