@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
@@ -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,10 +1,12 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, TabsContentPrimitive, TabsListPrimitive, TabsPrimitive, TabTriggerPrimitive, useAccountAssets, useAuthentication, useGetAllTWSigners, useModalStore, useRemoveSessionKey, } from "../../../../global-account/react/index.js";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import app from "../../../../global-account/app.js";
3
+ import { Button, TabsContentPrimitive, TabsListPrimitive, TabsPrimitive, TabTriggerPrimitive, useAccountAssets, useAuthentication, useB3, useGetAllTWSigners, useModalStore, useQueryB3, useRemoveSessionKey, } from "../../../../global-account/react/index.js";
3
4
  import { SignOutIcon } from "../../../../global-account/react/components/icons/SignOutIcon.js";
4
5
  import { formatNumber } from "../../../../shared/utils/formatNumber.js";
5
6
  import { client } from "../../../../shared/utils/thirdweb.js";
6
- import { BarChart3, Coins, Image, LinkIcon, Loader2, Settings, UnlinkIcon } from "lucide-react";
7
- import { useState } from "react";
7
+ import { BarChart3, Coins, Copy, Image, LinkIcon, Loader2, Pencil, Settings, UnlinkIcon } from "lucide-react";
8
+ import { useRef, useState } from "react";
9
+ import { toast } from "sonner";
8
10
  import { useActiveAccount, useProfiles, useUnlinkProfile } from "thirdweb/react";
9
11
  import { formatUnits } from "viem";
10
12
  import { getProfileDisplayInfo } from "../../utils/profileDisplay.js";
@@ -52,6 +54,45 @@ export function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit
52
54
  const { data: profilesRaw = [], isLoading: isLoadingProfiles } = useProfiles({ client });
53
55
  const { mutate: unlinkProfile, isPending: isUnlinking } = useUnlinkProfile();
54
56
  const { setB3ModalOpen, setB3ModalContentType, isLinking } = useModalStore();
57
+ const { user, setUser } = useB3();
58
+ const [isUpdatingCode, setIsUpdatingCode] = useState(false);
59
+ const [newReferralCode, setNewReferralCode] = useState("");
60
+ const [isEditingCode, setIsEditingCode] = useState(false);
61
+ const referallCodeRef = useRef(null);
62
+ const { data: referrals, isLoading: isLoadingReferrals } = useQueryB3("referrals", "find", { query: { referrerId: user?.userId } }, !!user?.userId);
63
+ // Fetch referred users
64
+ const currentReferralCode = user?.referralCode || user?.userId || "";
65
+ const handleCopyCode = async () => {
66
+ try {
67
+ await navigator.clipboard.writeText(currentReferralCode);
68
+ toast.success("Referral code copied to clipboard!");
69
+ }
70
+ catch (error) {
71
+ toast.error("Failed to copy referral code");
72
+ }
73
+ };
74
+ const handleUpdateReferralCode = async () => {
75
+ if (!newReferralCode)
76
+ return;
77
+ setIsUpdatingCode(true);
78
+ try {
79
+ // @ts-expect-error - setReferralCode is not typed for some reason
80
+ const newUser = await app.service("users").setReferralCode({
81
+ userId: user?.userId,
82
+ referralCode: newReferralCode,
83
+ });
84
+ setUser(newUser);
85
+ toast.success("Referral code updated successfully!");
86
+ setIsEditingCode(false);
87
+ setNewReferralCode("");
88
+ }
89
+ catch (error) {
90
+ toast.error("Failed to update referral code");
91
+ }
92
+ finally {
93
+ setIsUpdatingCode(false);
94
+ }
95
+ };
55
96
  const profiles = profilesRaw
56
97
  .filter((profile) => !["custom_auth_endpoint", "siwe"].includes(profile.type))
57
98
  .map((profile) => ({
@@ -88,7 +129,15 @@ export function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit
88
129
  },
89
130
  });
90
131
  };
91
- return (_jsxs("div", { className: "space-y-8", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), _jsxs(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 ? (_jsx(Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : (_jsx(LinkIcon, { size: 16, className: "text-b3-primary-blue" })), _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? (_jsx("div", { className: "space-y-4", children: profiles.map(profile => (_jsxs("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? (_jsx("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : (_jsx("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), _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() })] }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), _jsx(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 ? (_jsx(Loader2, { className: "animate-spin" })) : (_jsx(UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : (_jsx("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Account Preferences" }), _jsx("div", { className: "bg-b3-line rounded-xl p-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Dark Mode" }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Switch between light and dark theme" })] }), _jsx("div", { className: "bg-b3-primary-wash h-6 w-12 rounded-full" })] }) })] }), _jsxs("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), _jsx("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3 apps" })] }), _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 ? _jsx(Loader2, { className: "animate-spin" }) : _jsx(SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
132
+ return (_jsxs("div", { className: "space-y-8", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), _jsxs(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 ? (_jsx(Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : (_jsx(LinkIcon, { size: 16, className: "text-b3-primary-blue" })), _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? (_jsx("div", { className: "space-y-4", children: profiles.map(profile => (_jsxs("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? (_jsx("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : (_jsx("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), _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() })] }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), _jsx(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 ? (_jsx(Loader2, { className: "animate-spin" })) : (_jsx(UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : (_jsx("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Referrals" }), _jsxs("div", { className: "bg-b3-line rounded-xl p-4", children: [isEditingCode && (_jsxs("div", { children: [_jsx("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Your Referral Code" }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Share this code with friends to earn rewards" })] })), _jsxs("div", { className: "flex items-center justify-between", children: [!isEditingCode && (_jsxs("div", { children: [_jsx("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Your Referral Code" }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Share this code with friends to earn rewards" })] })), _jsx("div", { className: "flex items-center gap-2", children: isEditingCode ? (_jsxs("div", { className: "flex items-center gap-2", children: [_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 }), _jsx(Button, { size: "sm", onClick: handleUpdateReferralCode, disabled: isUpdatingCode || !newReferralCode, children: isUpdatingCode ? _jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : "Save" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
133
+ setIsEditingCode(false);
134
+ setNewReferralCode("");
135
+ }, children: "Cancel" })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "rounded-lg border border-gray-200 bg-white px-3 py-1.5 text-sm", children: currentReferralCode }), _jsx(Button, { size: "icon", variant: "ghost", onClick: handleCopyCode, children: _jsx(Copy, { className: "h-4 w-4" }) }), _jsx(Button, { size: "icon", variant: "ghost", onClick: () => {
136
+ setIsEditingCode(true);
137
+ setTimeout(() => {
138
+ referallCodeRef.current?.focus();
139
+ }, 100);
140
+ }, children: _jsx(Pencil, { className: "h-4 w-4" }) })] })) })] })] }), _jsxs("div", { className: "bg-b3-line rounded-xl p-4", children: [_jsx("div", { className: "text-b3-grey font-neue-montreal-semibold mb-4", children: "Referred Users" }), isLoadingReferrals ? (_jsx("div", { className: "flex justify-center py-4", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-gray-400" }) })) : referrals?.data?.length ? (_jsx("div", { className: "space-y-3", children: referrals.data.map((referral) => (_jsxs("div", { className: "flex items-center justify-between rounded-lg bg-white p-3", children: [_jsx("div", { className: "text-sm font-medium", children: referral.referreeId }), _jsx("div", { className: "text-sm text-gray-500", children: new Date(referral.createdAt).toLocaleDateString() })] }, String(referral._id)))) })) : (_jsx("div", { className: "py-4 text-center text-gray-500", children: "No referred users yet" }))] })] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Account Preferences" }), _jsx("div", { className: "bg-b3-line rounded-xl p-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Dark Mode" }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Switch between light and dark theme" })] }), _jsx("div", { className: "bg-b3-primary-wash h-6 w-12 rounded-full" })] }) })] }), _jsxs("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), _jsx("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3 apps" })] }), _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 ? _jsx(Loader2, { className: "animate-spin" }) : _jsx(SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
92
141
  };
93
142
  return (_jsx("div", { className: "b3-manage-account bg-b3-background flex flex-col rounded-xl", children: _jsx("div", { className: "flex-1", children: _jsxs(TabsPrimitive, { defaultValue: activeTab, onValueChange: value => {
94
143
  const tab = value;
@@ -3,11 +3,11 @@ import debug from "../../../shared/utils/debug.js";
3
3
  import { useCallback } from "react";
4
4
  import { useSearchParam } from "./useSearchParamsSSR.js";
5
5
  export function useSiwe() {
6
- const referrerId = useSearchParam("referrerId");
6
+ const referralCode = useSearchParam("referralCode");
7
7
  const authenticate = useCallback(async (account, partnerId) => {
8
8
  if (!account || !account.signMessage)
9
9
  throw new Error("Account not found");
10
- console.log("@@useAuthenticate:referrerId", referrerId);
10
+ console.log("@@useAuthenticate:referralCode", referralCode);
11
11
  // generate challenge
12
12
  const challenge = await app.service("global-accounts-challenge").create({
13
13
  address: account.address,
@@ -25,13 +25,13 @@ export function useSiwe() {
25
25
  signature,
26
26
  serverSignature: challenge.serverSignature,
27
27
  nonce: challenge.nonce,
28
- // http://localhost:5173/?referrerId=cd8fda06-3840-43d3-8f35-ae9472a13759
29
- referrerId: referrerId,
28
+ // http://localhost:5173/?referralCode=GIO2
29
+ referralCode,
30
30
  partnerId: partnerId,
31
31
  });
32
32
  debug("@@useAuthenticate:response", response);
33
33
  return response;
34
- }, [referrerId]);
34
+ }, [referralCode]);
35
35
  return {
36
36
  authenticate,
37
37
  };
@@ -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;
@@ -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;
@@ -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 "@b3dotfun/sdk/global-account/types/b3-api.types";
3
- import { Wallet } from "thirdweb/wallets";
1
+ import { Users } from "@b3dotfun/b3-api";
4
2
  import { PermissionsConfig } from "@b3dotfun/sdk/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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.0.31",
3
+ "version": "0.0.32-alpha.0",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -237,7 +237,7 @@
237
237
  "constants"
238
238
  ],
239
239
  "dependencies": {
240
- "@b3dotfun/b3-api": "0.0.43",
240
+ "@b3dotfun/b3-api": "0.0.45",
241
241
  "@b3dotfun/basement-api": "0.0.11",
242
242
  "@chakra-ui/react": "2.10.7",
243
243
  "@feathersjs/authentication-client": "5.0.33",
@@ -115,6 +115,7 @@ function AnySpendDepositHypeInner({
115
115
  sourceTokenAddress,
116
116
  sourceTokenChainId,
117
117
  slippage: SLIPPAGE_PERCENT,
118
+ disableUrlParamManagement: true,
118
119
  });
119
120
 
120
121
  // Button state logic
@@ -434,8 +435,8 @@ function AnySpendDepositHypeInner({
434
435
  onBack={() => {
435
436
  setOrderId(undefined);
436
437
  setActivePanel(PanelView.MAIN);
437
- onSuccess?.();
438
438
  }}
439
+ disableUrlParamManagement
439
440
  />
440
441
  </>
441
442
  )}
@@ -63,6 +63,7 @@ interface OrderDetailsProps {
63
63
  refundTxs: components["schemas"]["RefundTx"][] | null;
64
64
  cryptoPaymentMethod?: CryptoPaymentMethodType; // Now optional since we read from URL
65
65
  onBack?: () => void;
66
+ disableUrlParamManagement?: boolean; // When true, will not modify URL parameters
66
67
  }
67
68
 
68
69
  // Add this helper function near the top or just above the component
@@ -202,6 +203,7 @@ export const OrderDetails = memo(function OrderDetails({
202
203
  refundTxs,
203
204
  cryptoPaymentMethod,
204
205
  onBack,
206
+ disableUrlParamManagement = false,
205
207
  }: OrderDetailsProps) {
206
208
  const router = useRouter();
207
209
  const searchParams = useSearchParams();
@@ -284,13 +286,15 @@ export const OrderDetails = memo(function OrderDetails({
284
286
 
285
287
  // When waitingForDeposit is true, we show a message to the user to wait for the deposit to be processed.
286
288
  const setWaitingForDeposit = useCallback(() => {
289
+ if (disableUrlParamManagement) return;
287
290
  const params = new URLSearchParams(searchParams.toString());
288
291
  params.set("waitingForDeposit", "true");
289
292
  router.push(`?${params}`);
290
- }, [router, searchParams]);
293
+ }, [router, searchParams, disableUrlParamManagement]);
291
294
 
292
295
  // Clean up URL parameters before closing modal or navigating back
293
296
  const cleanupUrlParams = useCallback(() => {
297
+ if (disableUrlParamManagement) return;
294
298
  const params = new URLSearchParams(searchParams.toString());
295
299
  params.delete("waitingForDeposit");
296
300
  params.delete("orderId");
@@ -300,7 +304,7 @@ export const OrderDetails = memo(function OrderDetails({
300
304
  if (params.toString() !== searchParams.toString()) {
301
305
  router.push(`?${params}`);
302
306
  }
303
- }, [router, searchParams]);
307
+ }, [router, searchParams, disableUrlParamManagement]);
304
308
 
305
309
  // Helper functions that clean up URL params before executing actions
306
310
  const handleCloseModal = useCallback(() => {
@@ -7,12 +7,19 @@ import {
7
7
  useGeoOnrampOptions,
8
8
  } from "@b3dotfun/sdk/anyspend/react";
9
9
  import { anyspendService } from "@b3dotfun/sdk/anyspend/services/anyspend";
10
- import { useAccountWallet, useProfile, useRouter, useSearchParamsSSR } from "@b3dotfun/sdk/global-account/react";
10
+ import {
11
+ useAccountWallet,
12
+ useProfile,
13
+ useRouter,
14
+ useSearchParamsSSR,
15
+ useTokenBalance,
16
+ } from "@b3dotfun/sdk/global-account/react";
11
17
  import { formatTokenAmount, formatUnits } from "@b3dotfun/sdk/shared/utils/number";
12
- import { useEffect, useState } from "react";
18
+ import { useEffect, useMemo, useState } from "react";
13
19
  import { toast } from "sonner";
14
20
  import { parseUnits } from "viem";
15
21
  import { base, mainnet } from "viem/chains";
22
+ import { useAccount } from "wagmi";
16
23
  import { components } from "../../types/api";
17
24
  import { CryptoPaymentMethodType } from "../components/common/CryptoPaymentMethod";
18
25
  import { FiatPaymentMethod } from "../components/common/FiatPaymentMethod";
@@ -36,6 +43,7 @@ interface UseAnyspendFlowProps {
36
43
  sourceTokenAddress?: string;
37
44
  sourceTokenChainId?: number;
38
45
  slippage?: number;
46
+ disableUrlParamManagement?: boolean;
39
47
  }
40
48
 
41
49
  export function useAnyspendFlow({
@@ -48,6 +56,7 @@ export function useAnyspendFlow({
48
56
  sourceTokenAddress,
49
57
  sourceTokenChainId,
50
58
  slippage = 0,
59
+ disableUrlParamManagement = false,
51
60
  }: UseAnyspendFlowProps) {
52
61
  const searchParams = useSearchParamsSSR();
53
62
  const router = useRouter();
@@ -76,6 +85,7 @@ export function useAnyspendFlow({
76
85
 
77
86
  // Recipient state
78
87
  const { address: globalAddress } = useAccountWallet();
88
+ const { address: wagmiAddress } = useAccount();
79
89
  const [selectedRecipientAddress, setSelectedRecipientAddress] = useState<string | undefined>(recipientAddress);
80
90
  const recipientProfile = useProfile({ address: selectedRecipientAddress, fresh: true });
81
91
  const recipientName = recipientProfile.data?.name;
@@ -87,11 +97,33 @@ export function useAnyspendFlow({
87
97
  }
88
98
  }, [selectedRecipientAddress, globalAddress]);
89
99
 
100
+ // Check token balance for crypto payments
101
+ const { rawBalance, isLoading: isBalanceLoading } = useTokenBalance({
102
+ token: selectedSrcToken,
103
+ address: wagmiAddress,
104
+ });
105
+
106
+ // Check if user has enough balance
107
+ const hasEnoughBalance = useMemo(() => {
108
+ if (!rawBalance || isBalanceLoading || paymentType !== "crypto") return false;
109
+ try {
110
+ const requiredAmount = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
111
+ return rawBalance >= requiredAmount;
112
+ } catch {
113
+ return false;
114
+ }
115
+ }, [rawBalance, srcAmount, selectedSrcToken.decimals, isBalanceLoading, paymentType]);
116
+
117
+ // Auto-set crypto payment method based on balance
90
118
  useEffect(() => {
91
- if (paymentType === "crypto") {
92
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
119
+ if (paymentType === "crypto" && !isBalanceLoading) {
120
+ if (hasEnoughBalance) {
121
+ setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
122
+ } else {
123
+ setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.TRANSFER_CRYPTO);
124
+ }
93
125
  }
94
- }, [paymentType]);
126
+ }, [paymentType, hasEnoughBalance, isBalanceLoading]);
95
127
 
96
128
  // Fetch specific token when sourceTokenAddress and sourceTokenChainId are provided
97
129
  useEffect(() => {
@@ -159,14 +191,14 @@ export function useAnyspendFlow({
159
191
 
160
192
  // Update useEffect for URL parameter to not override loadOrder
161
193
  useEffect(() => {
162
- if (loadOrder) return; // Skip if we have a loadOrder
194
+ if (loadOrder || disableUrlParamManagement) return; // Skip if we have a loadOrder or URL param management is disabled
163
195
 
164
196
  const orderIdParam = searchParams.get("orderId");
165
197
  if (orderIdParam) {
166
198
  setOrderId(orderIdParam);
167
199
  setActivePanel(PanelView.ORDER_DETAILS);
168
200
  }
169
- }, [searchParams, loadOrder]);
201
+ }, [searchParams, loadOrder, disableUrlParamManagement]);
170
202
 
171
203
  // Order creation hooks
172
204
  const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
@@ -177,16 +209,18 @@ export function useAnyspendFlow({
177
209
  onOrderSuccess?.(newOrderId);
178
210
 
179
211
  // Add orderId and payment method to URL for persistence
180
- const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
181
- params.set("orderId", newOrderId);
182
- if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
183
- console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
184
- params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
185
- } else {
186
- console.log("Payment method is NONE, not setting in URL");
212
+ if (!disableUrlParamManagement) {
213
+ const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
214
+ params.set("orderId", newOrderId);
215
+ if (selectedCryptoPaymentMethod !== CryptoPaymentMethodType.NONE) {
216
+ console.log("Setting cryptoPaymentMethod in URL:", selectedCryptoPaymentMethod);
217
+ params.set("cryptoPaymentMethod", selectedCryptoPaymentMethod);
218
+ } else {
219
+ console.log("Payment method is NONE, not setting in URL");
220
+ }
221
+ console.log("Final URL params:", params.toString());
222
+ router.push(`${window.location.pathname}?${params.toString()}`);
187
223
  }
188
- console.log("Final URL params:", params.toString());
189
- router.push(`${window.location.pathname}?${params.toString()}`);
190
224
  },
191
225
  onError: error => {
192
226
  console.error(error);
@@ -245,6 +279,9 @@ export function useAnyspendFlow({
245
279
  setSelectedRecipientAddress,
246
280
  recipientName,
247
281
  globalAddress,
282
+ // Balance check
283
+ hasEnoughBalance,
284
+ isBalanceLoading,
248
285
  // Quote data
249
286
  anyspendQuote,
250
287
  isLoadingAnyspendQuote,
@@ -4,7 +4,7 @@ import { useState } from "react";
4
4
  import { ThirdwebProvider, useActiveAccount } from "thirdweb/react";
5
5
  import { Account } from "thirdweb/wallets";
6
6
 
7
- import { User } from "@b3dotfun/sdk/global-account/types/b3-api.types";
7
+ import { Users } from "@b3dotfun/b3-api";
8
8
  import { B3Context, B3ContextType } from "./types";
9
9
 
10
10
  /**
@@ -64,7 +64,7 @@ export function InnerProvider({
64
64
  theme: "light" | "dark";
65
65
  }) {
66
66
  const activeAccount = useActiveAccount();
67
- const [user, setUser] = useState<User | undefined>(undefined);
67
+ const [user, setUser] = useState<Users | undefined>(undefined);
68
68
 
69
69
  // Use given accountOverride or activeAccount from thirdweb
70
70
  const effectiveAccount = accountOverride || activeAccount;
@@ -1,5 +1,4 @@
1
1
  import { RelayKitProviderWrapper, TooltipProvider, useAuthStore } from "@b3dotfun/sdk/global-account/react";
2
- import { User } from "@b3dotfun/sdk/global-account/types/b3-api.types";
3
2
  import { PermissionsConfig } from "@b3dotfun/sdk/global-account/types/permissions";
4
3
  import { loadGA4Script } from "@b3dotfun/sdk/global-account/utils/analytics";
5
4
  import { supportedChains } from "@b3dotfun/sdk/shared/constants/chains/supported";
@@ -18,6 +17,7 @@ import { createConfig, http, WagmiProvider } from "wagmi";
18
17
  import { StyleRoot } from "../StyleRoot";
19
18
  import { B3Context, B3ContextType } from "./types";
20
19
 
20
+ import { Users } from "@b3dotfun/b3-api";
21
21
  import "@reservoir0x/relay-kit-ui/styles.css";
22
22
 
23
23
  /**
@@ -115,7 +115,7 @@ export function InnerProvider({
115
115
  const setActiveWallet = useSetActiveWallet();
116
116
  const isAuthenticated = useAuthStore(state => state.isAuthenticated);
117
117
 
118
- const [user, setUser] = useState<User | undefined>(undefined);
118
+ const [user, setUser] = useState<Users | undefined>(undefined);
119
119
 
120
120
  // Use given accountOverride or activeAccount from thirdweb
121
121
  const effectiveAccount = isAuthenticated ? accountOverride || activeAccount : undefined;
@@ -1,8 +1,7 @@
1
- import { Account } from "thirdweb/wallets";
2
- import { User } from "@b3dotfun/sdk/global-account/types/b3-api.types";
3
- import { Wallet } from "thirdweb/wallets";
1
+ import { Users } from "@b3dotfun/b3-api";
4
2
  import { PermissionsConfig } from "@b3dotfun/sdk/global-account/types/permissions";
5
3
  import { createContext } from "react";
4
+ import { Account, Wallet } from "thirdweb/wallets";
6
5
 
7
6
  /**
8
7
  * Context type for B3Provider
@@ -10,10 +9,10 @@ import { createContext } from "react";
10
9
  export interface B3ContextType {
11
10
  account?: Account;
12
11
  automaticallySetFirstEoa: boolean;
13
- user?: User;
12
+ user?: Users;
14
13
  setWallet: (wallet: Wallet) => void;
15
14
  wallet?: Wallet;
16
- setUser: (user?: User) => void;
15
+ setUser: (user?: Users) => void;
17
16
  initialized: boolean;
18
17
  ready: boolean;
19
18
  environment?: "development" | "production";