From 4d1637a3915553d00111e99a030cd700448abbd1 Mon Sep 17 00:00:00 2001 From: Gio Martinez Date: Tue, 30 Dec 2025 14:37:26 +0700 Subject: [PATCH] [B3-2868] Fix apps crashing, revert some recent refactoring --- .../src/components/ExampleAuthInfo.tsx | 4 +- apps/global-accounts/src/pages/Debug.tsx | 4 +- apps/global-accounts/src/pages/Demos.tsx | 4 +- docs/cn/sdk/global-account/hooks.mdx | 2 +- docs/es/sdk/global-account/hooks.mdx | 2 +- docs/id/sdk/global-account/hooks.mdx | 2 +- docs/ko/sdk/global-account/hooks.mdx | 2 +- docs/pt-BR/sdk/global-account/hooks.mdx | 2 +- docs/sdk/global-account/hooks.mdx | 2 +- .../anyspend/react/components/AnySpend.tsx | 4 +- .../react/components/common/OrderDetails.tsx | 4 +- .../components/common/PaymentStripeWeb2.tsx | 4 +- .../hooks/useAnyspendCreateOnrampOrder.ts | 4 +- .../react/hooks/useAnyspendCreateOrder.ts | 4 +- .../react/hooks/useCreateDepositFirstOrder.ts | 4 +- .../hooks/useValidatedClientReferenceId.ts | 4 +- .../components/AvatarEditor/AvatarEditor.tsx | 4 +- .../react/components/B3DynamicModal.tsx | 4 +- .../B3Provider/AuthenticationProvider.tsx | 19 --- .../B3Provider/B3ConfigProvider.tsx | 84 ------------- .../B3Provider/B3Provider.native.tsx | 71 +++++++---- .../components/B3Provider/B3Provider.tsx | 114 +++++++++++++++-- .../react/components/B3Provider/types.ts | 50 ++++++++ .../react/components/B3Provider/useB3.ts | 16 ++- .../components/B3Provider/useB3Account.ts | 8 +- .../components/B3Provider/useB3Config.ts | 35 +++++- .../ManageAccount/ProfileSection.tsx | 6 +- .../ManageAccount/SettingsProfileCard.tsx | 4 +- .../ManageAccount/channels/DiscordChannel.tsx | 4 +- .../ManageAccount/channels/EmailChannel.tsx | 4 +- .../ManageAccount/channels/PhoneChannel.tsx | 4 +- .../channels/TelegramChannel.tsx | 4 +- .../RequestPermissions/RequestPermissions.tsx | 4 +- .../react/components/SignInWithB3/SignIn.tsx | 4 +- .../SignInWithB3/SignInWithB3Flow.tsx | 4 +- .../SignInWithB3/SignInWithB3Privy.tsx | 4 +- .../SignInWithB3/steps/LoginStep.tsx | 4 +- .../SignInWithB3/steps/LoginStepCustom.tsx | 4 +- .../react/components/StyleRoot.tsx | 4 +- .../components/custom/ManageAccountButton.tsx | 5 +- .../global-account/react/components/index.ts | 3 +- .../src/global-account/react/hooks/index.ts | 2 +- .../src/global-account/react/hooks/useAuth.ts | 6 +- .../react/hooks/useAuthentication.ts | 2 +- .../global-account/react/hooks/useClient.ts | 4 +- .../react/hooks/useHandleConnectWithPrivy.tsx | 4 +- .../react/hooks/useNotifications.ts | 4 +- .../react/hooks/useTokenBalance.tsx | 15 ++- .../react/hooks/useTurnkeyAuth.ts | 4 +- .../src/global-account/react/hooks/useUser.ts | 20 --- .../react/hooks/useUserQuery.ts | 115 ++++++++---------- .../src/global-account/react/index.native.ts | 2 + .../global-account/react/stores/userStore.ts | 41 ------- 53 files changed, 381 insertions(+), 357 deletions(-) delete mode 100644 packages/sdk/src/global-account/react/components/B3Provider/AuthenticationProvider.tsx delete mode 100644 packages/sdk/src/global-account/react/components/B3Provider/B3ConfigProvider.tsx create mode 100644 packages/sdk/src/global-account/react/components/B3Provider/types.ts delete mode 100644 packages/sdk/src/global-account/react/hooks/useUser.ts delete mode 100644 packages/sdk/src/global-account/react/stores/userStore.ts diff --git a/apps/global-accounts/src/components/ExampleAuthInfo.tsx b/apps/global-accounts/src/components/ExampleAuthInfo.tsx index 68184476f..b6724b7a1 100644 --- a/apps/global-accounts/src/components/ExampleAuthInfo.tsx +++ b/apps/global-accounts/src/components/ExampleAuthInfo.tsx @@ -1,7 +1,7 @@ -import { useUser } from "@b3dotfun/sdk/global-account/react"; +import { useUserQuery } from "@b3dotfun/sdk/global-account/react/hooks/useUserQuery"; export function ExampleAuthInfo() { - const { user } = useUser(); + const { user } = useUserQuery(); console.log("@@user", user); return ( diff --git a/apps/global-accounts/src/pages/Debug.tsx b/apps/global-accounts/src/pages/Debug.tsx index a26692c39..cfabad5af 100644 --- a/apps/global-accounts/src/pages/Debug.tsx +++ b/apps/global-accounts/src/pages/Debug.tsx @@ -1,5 +1,5 @@ import { getExplorerTxUrl } from "@b3dotfun/sdk/anyspend"; -import { MintButton, SendERC20Button, SendETHButton, useUser } from "@b3dotfun/sdk/global-account/react"; +import { MintButton, SendERC20Button, SendETHButton, useUserQuery } from "@b3dotfun/sdk/global-account/react"; import { useB3Account } from "@b3dotfun/sdk/global-account/react/components/B3Provider/useB3Account"; import { thirdwebB3Mainnet } from "@b3dotfun/sdk/shared/constants/chains/b3Chain"; import { b3MainnetThirdWeb, getThirdwebChain } from "@b3dotfun/sdk/shared/constants/chains/supported"; @@ -27,7 +27,7 @@ const ethereum = getThirdwebChain(1); export function Debug() { const account = useB3Account(); - const { user } = useUser(); + const { user } = useUserQuery(); const activeAccount = useActiveAccount(); const profiles = useProfiles({ client }); const { mutate: unlinkProfile, isPending: isUnlinkPending } = useUnlinkProfile(); diff --git a/apps/global-accounts/src/pages/Demos.tsx b/apps/global-accounts/src/pages/Demos.tsx index 2aff6de0b..b8d8b0154 100644 --- a/apps/global-accounts/src/pages/Demos.tsx +++ b/apps/global-accounts/src/pages/Demos.tsx @@ -1,10 +1,10 @@ -import { SignInWithB3, useAuthStore, useUser } from "@b3dotfun/sdk/global-account/react"; +import { SignInWithB3, useAuthStore, useUserQuery } from "@b3dotfun/sdk/global-account/react"; import { useB3Account } from "@b3dotfun/sdk/global-account/react/components/B3Provider/useB3Account"; import { useEffect, useState } from "react"; import { b3Chain } from "../constants/b3Chain"; export function Demos() { - const { user } = useUser(); + const { user } = useUserQuery(); const account = useB3Account(); const { isAuthenticating } = useAuthStore(); const [authMessage, setAuthMessage] = useState(""); diff --git a/docs/cn/sdk/global-account/hooks.mdx b/docs/cn/sdk/global-account/hooks.mdx index 3a6b91c59..b20266a98 100644 --- a/docs/cn/sdk/global-account/hooks.mdx +++ b/docs/cn/sdk/global-account/hooks.mdx @@ -355,7 +355,7 @@ function ConfigComponent() { partnerId, // 您的合作伙伴 ID features, // 可用功能 updateConfig // 更新配置 - } = useB3Config(); + } = useB3(); return (
diff --git a/docs/es/sdk/global-account/hooks.mdx b/docs/es/sdk/global-account/hooks.mdx index 8d240747e..b6fdd6961 100644 --- a/docs/es/sdk/global-account/hooks.mdx +++ b/docs/es/sdk/global-account/hooks.mdx @@ -355,7 +355,7 @@ function ConfigComponent() { partnerId, // Tu ID de socio features, // Características disponibles updateConfig // Actualizar configuración - } = useB3Config(); + } = useB3(); return (
diff --git a/docs/id/sdk/global-account/hooks.mdx b/docs/id/sdk/global-account/hooks.mdx index d0c2bb88a..57bd9ec4b 100644 --- a/docs/id/sdk/global-account/hooks.mdx +++ b/docs/id/sdk/global-account/hooks.mdx @@ -355,7 +355,7 @@ function ConfigComponent() { partnerId, // ID partner Anda features, // Fitur yang tersedia updateConfig // Perbarui konfigurasi - } = useB3Config(); + } = useB3(); return (
diff --git a/docs/ko/sdk/global-account/hooks.mdx b/docs/ko/sdk/global-account/hooks.mdx index eaa9ddc35..6ea363cf1 100644 --- a/docs/ko/sdk/global-account/hooks.mdx +++ b/docs/ko/sdk/global-account/hooks.mdx @@ -355,7 +355,7 @@ function ConfigComponent() { partnerId, // 파트너 ID features, // 사용 가능한 기능 updateConfig // 설정 업데이트 - } = useB3Config(); + } = useB3(); return (
diff --git a/docs/pt-BR/sdk/global-account/hooks.mdx b/docs/pt-BR/sdk/global-account/hooks.mdx index fe2a25eb1..b1879268a 100644 --- a/docs/pt-BR/sdk/global-account/hooks.mdx +++ b/docs/pt-BR/sdk/global-account/hooks.mdx @@ -355,7 +355,7 @@ function ConfigComponent() { partnerId, // Seu ID de parceiro features, // Recursos disponíveis updateConfig // Atualizar configuração - } = useB3Config(); + } = useB3(); return (
diff --git a/docs/sdk/global-account/hooks.mdx b/docs/sdk/global-account/hooks.mdx index cc5e52883..2134732d3 100644 --- a/docs/sdk/global-account/hooks.mdx +++ b/docs/sdk/global-account/hooks.mdx @@ -354,7 +354,7 @@ function ConfigComponent() { partnerId, // Your partner ID features, // Available features updateConfig // Update configuration - } = useB3Config(); + } = useB3(); return (
diff --git a/packages/sdk/src/anyspend/react/components/AnySpend.tsx b/packages/sdk/src/anyspend/react/components/AnySpend.tsx index 38b4b7470..0eaeaf7f6 100644 --- a/packages/sdk/src/anyspend/react/components/AnySpend.tsx +++ b/packages/sdk/src/anyspend/react/components/AnySpend.tsx @@ -25,7 +25,7 @@ import { toast, TransitionPanel, useAccountWallet, - useB3Config, + useB3, useModalStore, useProfile, useRouter, @@ -165,7 +165,7 @@ function AnySpendInner({ const searchParams = useSearchParamsSSR(); const router = useRouter(); - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType); // Determine if we're in "buy mode" based on whether destination token props are provided diff --git a/packages/sdk/src/anyspend/react/components/common/OrderDetails.tsx b/packages/sdk/src/anyspend/react/components/common/OrderDetails.tsx index 97c0fbb14..fd13f5e30 100644 --- a/packages/sdk/src/anyspend/react/components/common/OrderDetails.tsx +++ b/packages/sdk/src/anyspend/react/components/common/OrderDetails.tsx @@ -21,7 +21,7 @@ import { TextLoop, TextShimmer, useAccountWallet, - useB3Config, + useB3, useModalStore, useProfile, useUnifiedChainSwitchAndExecute, @@ -228,7 +228,7 @@ export const OrderDetails = memo(function OrderDetails({ const searchParams = useSearchParams(); // Get theme from B3Provider context - const { theme } = useB3Config(); + const { theme } = useB3(); const colorMode = theme || "light"; // Read crypto payment method from URL parameters diff --git a/packages/sdk/src/anyspend/react/components/common/PaymentStripeWeb2.tsx b/packages/sdk/src/anyspend/react/components/common/PaymentStripeWeb2.tsx index 0efb02c33..b2d46bc9d 100644 --- a/packages/sdk/src/anyspend/react/components/common/PaymentStripeWeb2.tsx +++ b/packages/sdk/src/anyspend/react/components/common/PaymentStripeWeb2.tsx @@ -1,6 +1,6 @@ import { OrderDetailsCollapsible, useStripeClientSecret } from "@b3dotfun/sdk/anyspend/react"; import { components } from "@b3dotfun/sdk/anyspend/types/api"; -import { ShinyButton, useB3Config, useModalStore, useProfile } from "@b3dotfun/sdk/global-account/react"; +import { ShinyButton, useB3, useModalStore, useProfile } from "@b3dotfun/sdk/global-account/react"; import { formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number"; import { formatStripeAmount, getStripePromise } from "@b3dotfun/sdk/shared/utils/payment.utils"; import { AddressElement, Elements, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js"; @@ -18,7 +18,7 @@ interface PaymentStripeWeb2Props { } export default function PaymentStripeWeb2({ order, stripePaymentIntentId, onPaymentSuccess }: PaymentStripeWeb2Props) { - const { theme, stripePublishableKey } = useB3Config(); + const { theme, stripePublishableKey } = useB3(); const fingerprintConfig = getFingerprintConfig(); const { clientSecret, isLoadingStripeClientSecret, stripeClientSecretError } = diff --git a/packages/sdk/src/anyspend/react/hooks/useAnyspendCreateOnrampOrder.ts b/packages/sdk/src/anyspend/react/hooks/useAnyspendCreateOnrampOrder.ts index 51ea0f325..1a1951465 100644 --- a/packages/sdk/src/anyspend/react/hooks/useAnyspendCreateOnrampOrder.ts +++ b/packages/sdk/src/anyspend/react/hooks/useAnyspendCreateOnrampOrder.ts @@ -3,7 +3,7 @@ import { anyspendService } from "@b3dotfun/sdk/anyspend/services/anyspend"; import { components } from "@b3dotfun/sdk/anyspend/types/api"; import { VisitorData } from "@b3dotfun/sdk/anyspend/types/fingerprint"; import { buildMetadata, buildPayload, normalizeAddress } from "@b3dotfun/sdk/anyspend/utils"; -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { useVisitorData } from "@fingerprintjs/fingerprintjs-pro-react"; import { useMutation } from "@tanstack/react-query"; import { useMemo } from "react"; @@ -36,7 +36,7 @@ export type UseAnyspendCreateOnrampOrderProps = { */ export function useAnyspendCreateOnrampOrder({ onSuccess, onError }: UseAnyspendCreateOnrampOrderProps = {}) { // Get B3 context values - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); // Get validated client reference ID from B3 context const createValidatedClientReferenceId = useValidatedClientReferenceId(); diff --git a/packages/sdk/src/anyspend/react/hooks/useAnyspendCreateOrder.ts b/packages/sdk/src/anyspend/react/hooks/useAnyspendCreateOrder.ts index 7c1614c63..b6bf82492 100644 --- a/packages/sdk/src/anyspend/react/hooks/useAnyspendCreateOrder.ts +++ b/packages/sdk/src/anyspend/react/hooks/useAnyspendCreateOrder.ts @@ -2,7 +2,7 @@ import { anyspendService } from "@b3dotfun/sdk/anyspend/services/anyspend"; import { components } from "@b3dotfun/sdk/anyspend/types/api"; import { VisitorData } from "@b3dotfun/sdk/anyspend/types/fingerprint"; import { buildMetadata, buildPayload, normalizeAddress } from "@b3dotfun/sdk/anyspend/utils"; -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { useVisitorData } from "@fingerprintjs/fingerprintjs-pro-react"; import { useMutation } from "@tanstack/react-query"; import { useMemo } from "react"; @@ -36,7 +36,7 @@ export type UseAnyspendCreateOrderProps = { */ export function useAnyspendCreateOrder({ onSuccess, onError }: UseAnyspendCreateOrderProps = {}) { // Get B3 context values - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); // Get validated client reference ID from B3 context const createValidatedClientReferenceId = useValidatedClientReferenceId(); diff --git a/packages/sdk/src/anyspend/react/hooks/useCreateDepositFirstOrder.ts b/packages/sdk/src/anyspend/react/hooks/useCreateDepositFirstOrder.ts index 73091c6e5..07a22a06d 100644 --- a/packages/sdk/src/anyspend/react/hooks/useCreateDepositFirstOrder.ts +++ b/packages/sdk/src/anyspend/react/hooks/useCreateDepositFirstOrder.ts @@ -2,7 +2,7 @@ import { anyspendService } from "@b3dotfun/sdk/anyspend/services/anyspend"; import { components } from "@b3dotfun/sdk/anyspend/types/api"; import { VisitorData } from "@b3dotfun/sdk/anyspend/types/fingerprint"; import { normalizeAddress } from "@b3dotfun/sdk/anyspend/utils"; -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { useVisitorData } from "@fingerprintjs/fingerprintjs-pro-react"; import { useMutation } from "@tanstack/react-query"; import { useMemo } from "react"; @@ -29,7 +29,7 @@ export type UseCreateDepositFirstOrderProps = { * This order type doesn't require srcAmount - the user deposits tokens after the order is created. */ export function useCreateDepositFirstOrder({ onSuccess, onError }: UseCreateDepositFirstOrderProps = {}) { - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const { data: fpData } = useVisitorData({ extendedResult: true }, { immediate: true }); const visitorData: VisitorData | undefined = fpData && { diff --git a/packages/sdk/src/anyspend/react/hooks/useValidatedClientReferenceId.ts b/packages/sdk/src/anyspend/react/hooks/useValidatedClientReferenceId.ts index bb7c542dc..1e684e45d 100644 --- a/packages/sdk/src/anyspend/react/hooks/useValidatedClientReferenceId.ts +++ b/packages/sdk/src/anyspend/react/hooks/useValidatedClientReferenceId.ts @@ -1,5 +1,5 @@ import { Validators } from "@b3dotfun/sdk/anyspend/utils/validation"; -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { useCallback } from "react"; import { CreateOnrampOrderParams } from "./useAnyspendCreateOnrampOrder"; import { CreateOrderParams } from "./useAnyspendCreateOrder"; @@ -9,7 +9,7 @@ import { CreateOrderParams } from "./useAnyspendCreateOrder"; * Gets the createClientReferenceId function from B3 context and validates the result */ export function useValidatedClientReferenceId() { - const { createClientReferenceId } = useB3Config(); + const { createClientReferenceId } = useB3(); const createValidatedClientReferenceId = useCallback( async (params: CreateOrderParams | CreateOnrampOrderParams) => { diff --git a/packages/sdk/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx b/packages/sdk/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx index 7b44ac798..9c4713a69 100644 --- a/packages/sdk/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +++ b/packages/sdk/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx @@ -6,7 +6,7 @@ import { IPFSMediaRenderer, toast, useAuthentication, - useB3Config, + useB3, useProfile, } from "@b3dotfun/sdk/global-account/react"; import { validateImageUrl } from "@b3dotfun/sdk/global-account/react/utils/profileDisplay"; @@ -57,7 +57,7 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) { const [zoom, setZoom] = useState(1); const [croppedAreaPixels, setCroppedAreaPixels] = useState(null); const fileInputRef = useRef(null); - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const { user, setUser } = useAuthentication(partnerId); const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType); const contentType = useModalStore(state => state.contentType); diff --git a/packages/sdk/src/global-account/react/components/B3DynamicModal.tsx b/packages/sdk/src/global-account/react/components/B3DynamicModal.tsx index f68510585..460cf85ea 100644 --- a/packages/sdk/src/global-account/react/components/B3DynamicModal.tsx +++ b/packages/sdk/src/global-account/react/components/B3DynamicModal.tsx @@ -14,7 +14,7 @@ import { AnySpendDepositHype } from "@b3dotfun/sdk/anyspend/react/components/Any import { AnySpendDepositUpside } from "@b3dotfun/sdk/anyspend/react/components/AnySpendDepositUpside"; import { AnySpendStakeUpside } from "@b3dotfun/sdk/anyspend/react/components/AnySpendStakeUpside"; import { AnySpendStakeUpsideExactIn } from "@b3dotfun/sdk/anyspend/react/components/AnySpendStakeUpsideExactIn"; -import { useB3Config, useIsMobile, useModalStore } from "@b3dotfun/sdk/global-account/react"; +import { useB3, useIsMobile, useModalStore } from "@b3dotfun/sdk/global-account/react"; import { cn } from "@b3dotfun/sdk/shared/utils/cn"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { AnimatePresence, motion } from "framer-motion"; @@ -39,7 +39,7 @@ export function B3DynamicModal() { const setB3ModalOpen = useModalStore(state => state.setB3ModalOpen); const contentType = useModalStore(state => state.contentType); const navigateBack = useModalStore(state => state.navigateBack); - const { theme } = useB3Config(); + const { theme } = useB3(); const isMobile = useIsMobile(); const { toasts, removeToast } = useToastContext(); diff --git a/packages/sdk/src/global-account/react/components/B3Provider/AuthenticationProvider.tsx b/packages/sdk/src/global-account/react/components/B3Provider/AuthenticationProvider.tsx deleted file mode 100644 index d24003bb8..000000000 --- a/packages/sdk/src/global-account/react/components/B3Provider/AuthenticationProvider.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useAuthentication } from "../../hooks"; -import { useAutoSelectWallet } from "../../hooks/useAutoSelectWallet"; - -const AuthenticationProvider = ({ - partnerId, - automaticallySetFirstEoa, -}: { - partnerId: string; - automaticallySetFirstEoa: boolean; -}) => { - useAuthentication(partnerId); - useAutoSelectWallet({ - enabled: automaticallySetFirstEoa, - }); - - return null; -}; - -export default AuthenticationProvider; diff --git a/packages/sdk/src/global-account/react/components/B3Provider/B3ConfigProvider.tsx b/packages/sdk/src/global-account/react/components/B3Provider/B3ConfigProvider.tsx deleted file mode 100644 index 47a780464..000000000 --- a/packages/sdk/src/global-account/react/components/B3Provider/B3ConfigProvider.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { CreateOnrampOrderParams } from "@b3dotfun/sdk/anyspend/react/hooks/useAnyspendCreateOnrampOrder"; -import { CreateOrderParams } from "@b3dotfun/sdk/anyspend/react/hooks/useAnyspendCreateOrder"; -import { PermissionsConfig } from "@b3dotfun/sdk/global-account/types/permissions"; -import { createContext, useContext } from "react"; -import { Account } from "thirdweb/wallets"; -import { ClientType } from "../../../client-manager"; - -/** - * Default permissions configuration for B3 provider - */ -const DEFAULT_PERMISSIONS: PermissionsConfig = { - approvedTargets: ["0xa8e42121e318e3D3BeD7f5969AF6D360045317DD"], - nativeTokenLimitPerTransaction: 0.1, - startDate: new Date(), - endDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), // 1 year from now -}; - -export interface B3ConfigContextType { - accountOverride?: Account; - automaticallySetFirstEoa: boolean; - environment: "development" | "production"; - defaultPermissions: PermissionsConfig; - theme: "light" | "dark"; - clientType: ClientType; - partnerId: string; - stripePublishableKey?: string; - createClientReferenceId?: (params: CreateOrderParams | CreateOnrampOrderParams) => Promise; - enableTurnkey: boolean; -} - -const B3ConfigContext = createContext(null); - -export function B3ConfigProvider({ - children, - accountOverride, - environment = "development", - defaultPermissions = DEFAULT_PERMISSIONS, - automaticallySetFirstEoa = false, - theme = "light", - clientType = "rest", - partnerId, - stripePublishableKey, - createClientReferenceId, - enableTurnkey = false, -}: { - children: React.ReactNode; - accountOverride?: Account; - environment?: "development" | "production"; - defaultPermissions?: PermissionsConfig; - automaticallySetFirstEoa?: boolean; - theme?: "light" | "dark"; - clientType?: ClientType; - partnerId: string; - stripePublishableKey?: string; - createClientReferenceId?: (params: CreateOrderParams | CreateOnrampOrderParams) => Promise; - enableTurnkey?: boolean; -}) { - return ( - - {children} - - ); -} - -export function useB3Config(): B3ConfigContextType { - const context = useContext(B3ConfigContext); - if (!context) { - throw new Error("useB3Config must be used within a B3ConfigProvider"); - } - return context; -} diff --git a/packages/sdk/src/global-account/react/components/B3Provider/B3Provider.native.tsx b/packages/sdk/src/global-account/react/components/B3Provider/B3Provider.native.tsx index 9d01cbecc..f9642f636 100644 --- a/packages/sdk/src/global-account/react/components/B3Provider/B3Provider.native.tsx +++ b/packages/sdk/src/global-account/react/components/B3Provider/B3Provider.native.tsx @@ -1,73 +1,78 @@ import { PermissionsConfig } from "@b3dotfun/sdk/global-account/types/permissions"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { ThirdwebProvider } from "thirdweb/react"; +import { ThirdwebProvider, useActiveAccount } from "thirdweb/react"; import { Account, Wallet } from "thirdweb/wallets"; import { ClientType } from "../../../client-manager"; import { WagmiProvider } from "wagmi"; import { createWagmiConfig } from "../../utils/createWagmiConfig"; -import AuthenticationProvider from "./AuthenticationProvider"; -import { B3ConfigProvider } from "./B3ConfigProvider"; import { LocalSDKProvider } from "./LocalSDKProvider"; +import { B3Context, B3ContextType } from "./types"; + +/** + * Default permissions configuration for B3 provider + */ +const DEFAULT_PERMISSIONS = { + approvedTargets: ["0xa8e42121e318e3D3BeD7f5969AF6D360045317DD"], // Example contract + nativeTokenLimitPerTransaction: 0.1, // in ETH + startDate: new Date(), + endDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), // 1 year from now +}; // Create queryClient instance const queryClient = new QueryClient(); /** - * Main B3Provider component + * Main B3Provider component for React Native */ export function B3Provider({ - theme = "light", + theme, children, accountOverride, environment, - clientType = "socket", + clientType, partnerId, rpcUrls, onConnect, - defaultPermissions, }: { theme: "light" | "dark"; children: React.ReactNode; accountOverride?: Account; - environment?: "development" | "production"; + environment: B3ContextType["environment"]; clientType?: ClientType; partnerId: string; rpcUrls?: Record; onConnect?: (wallet: Wallet, b3Jwt: string) => void | Promise; - defaultPermissions?: PermissionsConfig; }) { return ( - {/* */} {children} - {/* */} - + ); } /** - * Inner provider component for native + * Inner provider component that provides the actual B3Context */ export function InnerProvider({ children, accountOverride, environment, - defaultPermissions, + defaultPermissions = DEFAULT_PERMISSIONS, theme = "light", clientType = "socket", partnerId, @@ -75,29 +80,43 @@ export function InnerProvider({ }: { children: React.ReactNode; accountOverride?: Account; - environment?: "development" | "production"; + environment: B3ContextType["environment"]; defaultPermissions?: PermissionsConfig; theme: "light" | "dark"; clientType?: ClientType; partnerId: string; rpcUrls?: Record; }) { + const activeAccount = useActiveAccount(); + //const { user, setUser, refetchUser } = useAuthentication(partnerId); const wagmiConfig = createWagmiConfig({ partnerId, rpcUrls }); + // Use given accountOverride or activeAccount from thirdweb + const effectiveAccount = accountOverride || activeAccount; + return ( - {}, + wallet: undefined, + //user, + //setUser, + initialized: true, + ready: !!effectiveAccount, + environment, + defaultPermissions, + theme, + clientType, + partnerId, + //refetchUser, + }} > {children} - + ); diff --git a/packages/sdk/src/global-account/react/components/B3Provider/B3Provider.tsx b/packages/sdk/src/global-account/react/components/B3Provider/B3Provider.tsx index 9fcb74f0e..bb33f3dfa 100644 --- a/packages/sdk/src/global-account/react/components/B3Provider/B3Provider.tsx +++ b/packages/sdk/src/global-account/react/components/B3Provider/B3Provider.tsx @@ -1,21 +1,36 @@ import { CreateOnrampOrderParams } from "@b3dotfun/sdk/anyspend/react/hooks/useAnyspendCreateOnrampOrder"; import { CreateOrderParams } from "@b3dotfun/sdk/anyspend/react/hooks/useAnyspendCreateOrder"; -import { RelayKitProviderWrapper, TooltipProvider } from "@b3dotfun/sdk/global-account/react"; +import { + RelayKitProviderWrapper, + TooltipProvider, + useAuthentication, + useAuthStore, +} from "@b3dotfun/sdk/global-account/react"; +import { useAutoSelectWallet } from "@b3dotfun/sdk/global-account/react/hooks/useAutoSelectWallet"; import { createWagmiConfig } from "@b3dotfun/sdk/global-account/react/utils/createWagmiConfig"; import { PermissionsConfig } from "@b3dotfun/sdk/global-account/types/permissions"; import { loadGA4Script } from "@b3dotfun/sdk/global-account/utils/analytics"; import "@relayprotocol/relay-kit-ui/styles.css"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useEffect, useMemo } from "react"; -import { ThirdwebProvider } from "thirdweb/react"; +import { ThirdwebProvider, useActiveAccount } from "thirdweb/react"; import { Account, Wallet } from "thirdweb/wallets"; import { CreateConnectorFn, WagmiProvider } from "wagmi"; import { ClientType, setClientType } from "../../../client-manager"; import { StyleRoot } from "../StyleRoot"; import { setToastContext, ToastProvider, useToastContext } from "../Toast/index"; -import AuthenticationProvider from "./AuthenticationProvider"; -import { B3ConfigProvider } from "./B3ConfigProvider"; import { LocalSDKProvider } from "./LocalSDKProvider"; +import { B3Context, B3ContextType } from "./types"; + +/** + * Default permissions configuration for B3 provider + */ +const DEFAULT_PERMISSIONS = { + approvedTargets: ["0xa8e42121e318e3D3BeD7f5969AF6D360045317DD"], // Example contract + nativeTokenLimitPerTransaction: 0.1, // in ETH + startDate: new Date(), + endDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), // 1 year from now +}; // Create queryClient instance const queryClient = new QueryClient(); @@ -41,12 +56,11 @@ export function B3Provider({ overrideDefaultConnectors = false, createClientReferenceId, enableTurnkey = false, - defaultPermissions, }: { theme: "light" | "dark"; children: React.ReactNode; accountOverride?: Account; - environment?: "development" | "production"; + environment: B3ContextType["environment"]; automaticallySetFirstEoa?: boolean; simDuneApiKey?: string; toaster?: { @@ -63,7 +77,6 @@ export function B3Provider({ overrideDefaultConnectors?: boolean; createClientReferenceId?: (params: CreateOrderParams | CreateOnrampOrderParams) => Promise; enableTurnkey?: boolean; - defaultPermissions?: PermissionsConfig; }) { // Initialize Google Analytics on mount useEffect(() => { @@ -87,17 +100,16 @@ export function B3Provider({ - @@ -105,8 +117,7 @@ export function B3Provider({ {/* For the modal https://github.com/b3-fun/b3/blob/main/packages/sdk/src/global-account/react/components/ui/dialog.tsx#L46 */} - - + @@ -116,6 +127,85 @@ export function B3Provider({ ); } +/** + * Inner provider component that provides the actual B3Context + */ +export function InnerProvider({ + children, + accountOverride, + environment, + defaultPermissions = DEFAULT_PERMISSIONS, + automaticallySetFirstEoa, + theme = "light", + clientType = "socket", + partnerId, + stripePublishableKey, + createClientReferenceId, + enableTurnkey, +}: { + children: React.ReactNode; + accountOverride?: Account; + environment: B3ContextType["environment"]; + defaultPermissions?: PermissionsConfig; + automaticallySetFirstEoa: boolean; + theme: "light" | "dark"; + clientType?: ClientType; + partnerId: string; + stripePublishableKey?: string; + createClientReferenceId?: (params: CreateOrderParams | CreateOnrampOrderParams) => Promise; + enableTurnkey?: boolean; +}) { + const activeAccount = useActiveAccount(); + const isAuthenticated = useAuthStore(state => state.isAuthenticated); + //const isConnected = useAuthStore(state => state.isConnected); + //const justCompletedLogin = useAuthStore(state => state.justCompletedLogin); + + // Note: This fixes a bug where useAuthentication is no longer rendered on every page, as of this PR https://github.com/b3-fun/b3/pull/385/files#diff-3ef996931b8fc8e49021ba1b42ddaa97535214681610dc5fdacf63542e261af7 + // The above PR removes useAuthentication from the overall B3Provider. useAuthentication should be everywhere the provider is, since it sets the overall auth state + // By just calling it manually, we fix that issue + // As a follow up, we should fix the SDK directly + useAuthentication(partnerId); + + // Use given accountOverride or activeAccount from thirdweb + // WOJ: why if isAuthenticated is false, we don't use activeAccount, which should be undefined? + // skip isAuthenticated check ? + const effectiveAccount = isAuthenticated ? accountOverride || activeAccount : undefined; + + // Wrapper to set active wallet via thirdweb + // Note: `wallet` in context is deprecated - use useActiveWallet() from thirdweb/react instead + + // Auto-select first EOA wallet when enabled + useAutoSelectWallet({ + enabled: automaticallySetFirstEoa, + }); + + return ( + + {children} + + ); +} + /** * Component to connect the toast context to the global toast API */ diff --git a/packages/sdk/src/global-account/react/components/B3Provider/types.ts b/packages/sdk/src/global-account/react/components/B3Provider/types.ts new file mode 100644 index 000000000..86e66b414 --- /dev/null +++ b/packages/sdk/src/global-account/react/components/B3Provider/types.ts @@ -0,0 +1,50 @@ +import { CreateOnrampOrderParams } from "@b3dotfun/sdk/anyspend/react/hooks/useAnyspendCreateOnrampOrder"; +import { CreateOrderParams } from "@b3dotfun/sdk/anyspend/react/hooks/useAnyspendCreateOrder"; +import { PermissionsConfig } from "@b3dotfun/sdk/global-account/types/permissions"; +import { createContext } from "react"; +import { Account, Wallet } from "thirdweb/wallets"; +import { ClientType } from "../../../client-manager"; + +/** + * Context type for B3Provider + */ +export interface B3ContextType { + account?: Account; + automaticallySetFirstEoa: boolean; + //user?: Users; + //setWallet: (wallet: Wallet) => void; + wallet?: Wallet; + //setUser: (user?: Users) => void; + //refetchUser: () => Promise; + initialized: boolean; + ready: boolean; + environment?: "development" | "production"; + defaultPermissions?: PermissionsConfig; + theme: "light" | "dark"; + clientType: ClientType; + partnerId: string; + stripePublishableKey?: string; + createClientReferenceId?: (params: CreateOrderParams | CreateOnrampOrderParams) => Promise; + enableTurnkey?: boolean; +} + +/** + * Context for B3 provider + */ +export const B3Context = createContext({ + account: undefined, + automaticallySetFirstEoa: false, + //user: undefined, + //setWallet: () => {}, + wallet: undefined, + //setUser: () => {}, + //refetchUser: async () => {}, + initialized: false, + ready: false, + environment: "development", + theme: "light", + clientType: "rest", + partnerId: "", + createClientReferenceId: undefined, + enableTurnkey: false, +}); diff --git a/packages/sdk/src/global-account/react/components/B3Provider/useB3.ts b/packages/sdk/src/global-account/react/components/B3Provider/useB3.ts index cbd105a60..6adb5bb4f 100644 --- a/packages/sdk/src/global-account/react/components/B3Provider/useB3.ts +++ b/packages/sdk/src/global-account/react/components/B3Provider/useB3.ts @@ -1,9 +1,17 @@ -import { useB3Config } from "./useB3Config"; +import { useContext, useMemo } from "react"; +import { B3Context } from "./types"; /** - * Hook to access the B3 configuration - * @deprecated This is just an alias for useB3Config. Use useB3Config directly instead. + * Hook to access the B3 context + * @throws Error if used outside a B3Provider */ export function useB3() { - return useB3Config(); + const context = useContext(B3Context); + + if (!context.initialized) { + throw new Error("useB3 must be used within a B3Provider"); + } + + // Return a stable reference + return useMemo(() => context, [context]); } diff --git a/packages/sdk/src/global-account/react/components/B3Provider/useB3Account.ts b/packages/sdk/src/global-account/react/components/B3Provider/useB3Account.ts index 4fe0bd03f..fb4a6c29e 100644 --- a/packages/sdk/src/global-account/react/components/B3Provider/useB3Account.ts +++ b/packages/sdk/src/global-account/react/components/B3Provider/useB3Account.ts @@ -1,11 +1,7 @@ import { useActiveAccount } from "thirdweb/react"; -import { useAuthStore } from "../../stores/useAuthStore"; // Wrapper around useActiveAccount export const useB3Account = () => { - const isAuthenticated = useAuthStore(state => state.isAuthenticated); - const activeAccount = useActiveAccount(); - const effectiveAccount = isAuthenticated ? activeAccount : undefined; - - return effectiveAccount; + const account = useActiveAccount(); + return account; }; diff --git a/packages/sdk/src/global-account/react/components/B3Provider/useB3Config.ts b/packages/sdk/src/global-account/react/components/B3Provider/useB3Config.ts index aab59089f..3a7597ca6 100644 --- a/packages/sdk/src/global-account/react/components/B3Provider/useB3Config.ts +++ b/packages/sdk/src/global-account/react/components/B3Provider/useB3Config.ts @@ -1 +1,34 @@ -export { useB3Config } from "./B3ConfigProvider"; +import { useContext, useMemo } from "react"; +import { B3Context } from "./types"; + +export const useB3Config = () => { + const context = useContext(B3Context); + + if (!context) { + throw new Error("useB3 must be used within a B3Provider"); + } + + const { + automaticallySetFirstEoa, + environment, + theme, + clientType, + partnerId, + createClientReferenceId, + enableTurnkey, + } = context; + + // Return a stable reference + return useMemo( + () => ({ + automaticallySetFirstEoa, + environment, + theme, + clientType, + partnerId, + createClientReferenceId, + enableTurnkey, + }), + [automaticallySetFirstEoa, environment, theme, clientType, partnerId, createClientReferenceId, enableTurnkey], + ); +}; diff --git a/packages/sdk/src/global-account/react/components/ManageAccount/ProfileSection.tsx b/packages/sdk/src/global-account/react/components/ManageAccount/ProfileSection.tsx index 43f250ae9..caae40d60 100644 --- a/packages/sdk/src/global-account/react/components/ManageAccount/ProfileSection.tsx +++ b/packages/sdk/src/global-account/react/components/ManageAccount/ProfileSection.tsx @@ -1,9 +1,10 @@ import { useAccountWallet, + useAuthentication, + useB3, useModalStore, useProfile, useSimBalance, - useUser, } from "@b3dotfun/sdk/global-account/react"; import { formatUsername } from "@b3dotfun/sdk/shared/utils"; import { formatDisplayNumber } from "@b3dotfun/sdk/shared/utils/number"; @@ -21,7 +22,8 @@ const ProfileSection = () => { address: eoaAddress || account?.address, fresh: true, }); - const { user } = useUser(); + const { partnerId } = useB3(); + const { user } = useAuthentication(partnerId); const setB3ModalOpen = useModalStore(state => state.setB3ModalOpen); const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType); const navigateBack = useModalStore(state => state.navigateBack); diff --git a/packages/sdk/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx b/packages/sdk/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx index bc2ea1f2f..86e3fd3a7 100644 --- a/packages/sdk/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +++ b/packages/sdk/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx @@ -1,6 +1,6 @@ import { ens_normalize } from "@adraffy/ens-normalize"; import app from "@b3dotfun/sdk/global-account/app"; -import { toast, useAuthentication, useB3Config, useModalStore, useProfile } from "@b3dotfun/sdk/global-account/react"; +import { toast, useAuthentication, useB3, useModalStore, useProfile } from "@b3dotfun/sdk/global-account/react"; import { formatUsername } from "@b3dotfun/sdk/shared/utils"; import { Check, Loader2, Pencil, X } from "lucide-react"; import { useEffect, useRef, useState } from "react"; @@ -17,7 +17,7 @@ const SettingsProfileCard = () => { address: eoaAddress || account?.address, fresh: true, }); - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const { user, setUser } = useAuthentication(partnerId); const setB3ModalOpen = useModalStore(state => state.setB3ModalOpen); const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType); diff --git a/packages/sdk/src/global-account/react/components/ManageAccount/channels/DiscordChannel.tsx b/packages/sdk/src/global-account/react/components/ManageAccount/channels/DiscordChannel.tsx index 027908402..e5b64a2cf 100644 --- a/packages/sdk/src/global-account/react/components/ManageAccount/channels/DiscordChannel.tsx +++ b/packages/sdk/src/global-account/react/components/ManageAccount/channels/DiscordChannel.tsx @@ -1,4 +1,4 @@ -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { useState } from "react"; import { notificationsAPI } from "../../../utils/notificationsAPI"; @@ -26,7 +26,7 @@ export const DiscordChannel = ({ onConnectionChange, onToggle, }: DiscordChannelProps) => { - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const [discordId, setDiscordId] = useState(""); const [isConnecting, setIsConnecting] = useState(false); diff --git a/packages/sdk/src/global-account/react/components/ManageAccount/channels/EmailChannel.tsx b/packages/sdk/src/global-account/react/components/ManageAccount/channels/EmailChannel.tsx index 322539a5a..a357164ec 100644 --- a/packages/sdk/src/global-account/react/components/ManageAccount/channels/EmailChannel.tsx +++ b/packages/sdk/src/global-account/react/components/ManageAccount/channels/EmailChannel.tsx @@ -1,4 +1,4 @@ -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { useState } from "react"; import { notificationsAPI } from "../../../utils/notificationsAPI"; @@ -31,7 +31,7 @@ export const EmailChannel = ({ onConnectionChange, onToggle, }: EmailChannelProps) => { - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const [email, setEmail] = useState(""); const [emailError, setEmailError] = useState(null); diff --git a/packages/sdk/src/global-account/react/components/ManageAccount/channels/PhoneChannel.tsx b/packages/sdk/src/global-account/react/components/ManageAccount/channels/PhoneChannel.tsx index 10832b445..01a4a240d 100644 --- a/packages/sdk/src/global-account/react/components/ManageAccount/channels/PhoneChannel.tsx +++ b/packages/sdk/src/global-account/react/components/ManageAccount/channels/PhoneChannel.tsx @@ -1,4 +1,4 @@ -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { useState } from "react"; import { notificationsAPI } from "../../../utils/notificationsAPI"; @@ -32,7 +32,7 @@ export const PhoneChannel = ({ onConnectionChange, onToggle, }: PhoneChannelProps) => { - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const [phoneNumber, setPhoneNumber] = useState(""); const [isConnectingSMS, setIsConnectingSMS] = useState(false); diff --git a/packages/sdk/src/global-account/react/components/ManageAccount/channels/TelegramChannel.tsx b/packages/sdk/src/global-account/react/components/ManageAccount/channels/TelegramChannel.tsx index 6a1e1cf29..2cc302f8b 100644 --- a/packages/sdk/src/global-account/react/components/ManageAccount/channels/TelegramChannel.tsx +++ b/packages/sdk/src/global-account/react/components/ManageAccount/channels/TelegramChannel.tsx @@ -1,4 +1,4 @@ -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { useState } from "react"; import { notificationsAPI } from "../../../utils/notificationsAPI"; @@ -26,7 +26,7 @@ export const TelegramChannel = ({ onConnectionChange, onToggle, }: TelegramChannelProps) => { - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const [isConnecting, setIsConnecting] = useState(false); const [status, setStatus] = useState<"idle" | "pending" | "connected">("idle"); diff --git a/packages/sdk/src/global-account/react/components/RequestPermissions/RequestPermissions.tsx b/packages/sdk/src/global-account/react/components/RequestPermissions/RequestPermissions.tsx index 1a1e43827..c3e09675a 100644 --- a/packages/sdk/src/global-account/react/components/RequestPermissions/RequestPermissions.tsx +++ b/packages/sdk/src/global-account/react/components/RequestPermissions/RequestPermissions.tsx @@ -3,7 +3,7 @@ import { PermissionItem, RequestPermissionsModalProps, useAddTWSessionKey, - useB3Config, + useB3, useGetAllTWSigners, } from "@b3dotfun/sdk/global-account/react"; import { PermissionsConfig } from "@b3dotfun/sdk/global-account/types/permissions"; @@ -30,7 +30,7 @@ export function RequestPermissions({ }: RequestPermissionsModalProps) { const [isApproving, setIsApproving] = useState(false); const account = useActiveAccount(); - const { defaultPermissions } = useB3Config(); + const { defaultPermissions } = useB3(); const DEFAULT_PERMISSIONS = useMemo( () => permissions ?? (defaultPermissions as PermissionsConfig), [defaultPermissions, permissions], diff --git a/packages/sdk/src/global-account/react/components/SignInWithB3/SignIn.tsx b/packages/sdk/src/global-account/react/components/SignInWithB3/SignIn.tsx index 14d82798b..d3936ba29 100644 --- a/packages/sdk/src/global-account/react/components/SignInWithB3/SignIn.tsx +++ b/packages/sdk/src/global-account/react/components/SignInWithB3/SignIn.tsx @@ -5,7 +5,7 @@ import { StyleRoot, useAccountWallet, useAuthentication, - useB3Config, + useB3, useIsMobile, } from "@b3dotfun/sdk/global-account/react"; import Icon from "@b3dotfun/sdk/global-account/react/components/custom/Icon"; @@ -30,7 +30,7 @@ type SignInWithB3Props = Omit export function SignIn(props: SignInWithB3Props) { const { className } = props; - const { automaticallySetFirstEoa, partnerId } = useB3Config(); + const { automaticallySetFirstEoa, partnerId } = useB3(); const { address: globalAddress, ensName, diff --git a/packages/sdk/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx b/packages/sdk/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx index aba471b02..71d695f60 100644 --- a/packages/sdk/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx +++ b/packages/sdk/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx @@ -3,7 +3,7 @@ import { SignInWithB3ModalProps, useAuthentication, useAuthStore, - useB3Config, + useB3, useGetAllTWSigners, useModalStore, } from "@b3dotfun/sdk/global-account/react"; @@ -35,7 +35,7 @@ export function SignInWithB3Flow({ source = "signInWithB3Button", signersEnabled = false, }: SignInWithB3ModalProps) { - const { automaticallySetFirstEoa, enableTurnkey } = useB3Config(); + const { automaticallySetFirstEoa, enableTurnkey } = useB3(); const { user, refetchUser, logout } = useAuthentication(partnerId); // FIXME Logout before login to ensure a clean state diff --git a/packages/sdk/src/global-account/react/components/SignInWithB3/SignInWithB3Privy.tsx b/packages/sdk/src/global-account/react/components/SignInWithB3/SignInWithB3Privy.tsx index 0fa38a8f2..fd5c78606 100644 --- a/packages/sdk/src/global-account/react/components/SignInWithB3/SignInWithB3Privy.tsx +++ b/packages/sdk/src/global-account/react/components/SignInWithB3/SignInWithB3Privy.tsx @@ -2,7 +2,7 @@ import { Loading, useAuthentication, useAuthStore, - useB3Config, + useB3, useHandleConnectWithPrivy, } from "@b3dotfun/sdk/global-account/react"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; @@ -19,7 +19,7 @@ interface SignInWithB3PrivyProps { } export function SignInWithB3Privy({ onSuccess, onError, chain }: SignInWithB3PrivyProps) { - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const { isLoading, connectTw, fullToken } = useHandleConnectWithPrivy(chain, onSuccess); const setIsAuthenticating = useAuthStore(state => state.setIsAuthenticating); const setIsAuthenticated = useAuthStore(state => state.setIsAuthenticated); diff --git a/packages/sdk/src/global-account/react/components/SignInWithB3/steps/LoginStep.tsx b/packages/sdk/src/global-account/react/components/SignInWithB3/steps/LoginStep.tsx index 0b290302a..a54f0f260 100644 --- a/packages/sdk/src/global-account/react/components/SignInWithB3/steps/LoginStep.tsx +++ b/packages/sdk/src/global-account/react/components/SignInWithB3/steps/LoginStep.tsx @@ -1,4 +1,4 @@ -import { useAuthentication, useB3Config, useQueryB3 } from "@b3dotfun/sdk/global-account/react"; +import { useAuthentication, useB3, useQueryB3 } from "@b3dotfun/sdk/global-account/react"; import { ecosystemWalletId } from "@b3dotfun/sdk/shared/constants"; import { client } from "@b3dotfun/sdk/shared/utils/thirdweb"; import { Chain } from "thirdweb"; @@ -50,7 +50,7 @@ export function LoginStepContainer({ children, partnerId }: LoginStepContainerPr } export function LoginStep({ onSuccess, chain }: LoginStepProps) { - const { partnerId, theme } = useB3Config(); + const { partnerId, theme } = useB3(); const wallet = ecosystemWallet(ecosystemWalletId, { partnerId: partnerId, }); diff --git a/packages/sdk/src/global-account/react/components/SignInWithB3/steps/LoginStepCustom.tsx b/packages/sdk/src/global-account/react/components/SignInWithB3/steps/LoginStepCustom.tsx index 4db3f1b99..36e670915 100644 --- a/packages/sdk/src/global-account/react/components/SignInWithB3/steps/LoginStepCustom.tsx +++ b/packages/sdk/src/global-account/react/components/SignInWithB3/steps/LoginStepCustom.tsx @@ -7,7 +7,7 @@ import { LoginStepContainer, useAuthentication, useAuthStore, - useB3Config, + useB3, useConnect, WalletRow, } from "@b3dotfun/sdk/global-account/react"; @@ -37,7 +37,7 @@ export function LoginStepCustom({ maxInitialWallets = 2, automaticallySetFirstEoa, }: LoginStepCustomProps) { - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const [isLoading, setIsLoading] = useState(false); const [showAllWallets, setShowAllWallets] = useState(false); const { connect } = useConnect(partnerId, chain); diff --git a/packages/sdk/src/global-account/react/components/StyleRoot.tsx b/packages/sdk/src/global-account/react/components/StyleRoot.tsx index f0eb0bd40..0ff5ce20c 100644 --- a/packages/sdk/src/global-account/react/components/StyleRoot.tsx +++ b/packages/sdk/src/global-account/react/components/StyleRoot.tsx @@ -1,8 +1,8 @@ import { PropsWithChildren } from "react"; -import { useB3Config } from "./B3Provider/useB3Config"; +import { useB3 } from "./B3Provider/useB3"; export function StyleRoot({ children, id }: PropsWithChildren<{ id?: string }>) { - const { theme } = useB3Config(); + const { theme } = useB3(); return (
diff --git a/packages/sdk/src/global-account/react/components/custom/ManageAccountButton.tsx b/packages/sdk/src/global-account/react/components/custom/ManageAccountButton.tsx index b68c9d301..87b2029d7 100644 --- a/packages/sdk/src/global-account/react/components/custom/ManageAccountButton.tsx +++ b/packages/sdk/src/global-account/react/components/custom/ManageAccountButton.tsx @@ -1,10 +1,11 @@ -import { Button, StyleRoot, useModalStore, useUser } from "@b3dotfun/sdk/global-account/react"; +import { Button, StyleRoot, useAuthentication, useB3, useModalStore } from "@b3dotfun/sdk/global-account/react"; import { cn } from "@b3dotfun/sdk/shared/utils"; import { SignInWithB3Props } from "../SignInWithB3/SignInWithB3"; export function ManageAccountButton(props: SignInWithB3Props & { className?: string }) { + const { partnerId } = useB3(); const { setB3ModalOpen, setB3ModalContentType } = useModalStore(); - const { isConnected } = useUser(); + const { isConnected } = useAuthentication(partnerId); const handleClickManageAccount = () => { setB3ModalContentType({ diff --git a/packages/sdk/src/global-account/react/components/index.ts b/packages/sdk/src/global-account/react/components/index.ts index 80b92c7dc..4dc0c2c80 100644 --- a/packages/sdk/src/global-account/react/components/index.ts +++ b/packages/sdk/src/global-account/react/components/index.ts @@ -1,8 +1,9 @@ // TODO woj: Barrel file for all components, this might be reason of bundle size issues // Core Components export { B3DynamicModal } from "./B3DynamicModal"; -export { B3Provider } from "./B3Provider/B3Provider"; +export { B3Provider, InnerProvider } from "./B3Provider/B3Provider"; export { RelayKitProviderWrapper } from "./B3Provider/RelayKitProviderWrapper"; +export { B3Context, type B3ContextType } from "./B3Provider/types"; export { useB3 } from "./B3Provider/useB3"; export { useB3Account } from "./B3Provider/useB3Account"; export { useB3Config } from "./B3Provider/useB3Config"; diff --git a/packages/sdk/src/global-account/react/hooks/index.ts b/packages/sdk/src/global-account/react/hooks/index.ts index 25c7b105e..e5d61f061 100644 --- a/packages/sdk/src/global-account/react/hooks/index.ts +++ b/packages/sdk/src/global-account/react/hooks/index.ts @@ -53,4 +53,4 @@ export { useTokensFromAddress } from "./useTokensFromAddress"; export { useTurnkeyAuth } from "./useTurnkeyAuth"; export { useUnifiedChainSwitchAndExecute } from "./useUnifiedChainSwitchAndExecute"; export { useURLParams } from "./useURLParams"; -export { useUser } from "./useUser"; +export { useUserQuery } from "./useUserQuery"; diff --git a/packages/sdk/src/global-account/react/hooks/useAuth.ts b/packages/sdk/src/global-account/react/hooks/useAuth.ts index 49b8c64a9..2cd574a69 100644 --- a/packages/sdk/src/global-account/react/hooks/useAuth.ts +++ b/packages/sdk/src/global-account/react/hooks/useAuth.ts @@ -1,6 +1,6 @@ import app from "@b3dotfun/sdk/global-account/app"; import { authenticateWithB3JWT } from "@b3dotfun/sdk/global-account/bsmnt"; -import { useAuthStore, useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useAuthStore, useB3 } from "@b3dotfun/sdk/global-account/react"; import { ecosystemWalletId } from "@b3dotfun/sdk/shared/constants"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { client } from "@b3dotfun/sdk/shared/utils/thirdweb"; @@ -47,7 +47,7 @@ export function useAuth() { const hasStartedConnecting = useAuthStore(state => state.hasStartedConnecting); const useAutoConnectLoadingPrevious = useRef(false); const referralCode = useSearchParam("referralCode"); - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const wagmiConfig = createWagmiConfig({ partnerId }); const { connect } = useConnect(); const activeWagmiAccount = useAccount(); @@ -330,7 +330,7 @@ export function useAuth() { setIsAuthenticated(false); setIsConnected(false); - setUser(); + setUser(undefined); callback?.(); }, [activeWallet, disconnect, wallets, setIsAuthenticated, setUser, setIsConnected], diff --git a/packages/sdk/src/global-account/react/hooks/useAuthentication.ts b/packages/sdk/src/global-account/react/hooks/useAuthentication.ts index 46cb5ce36..9eda755cd 100644 --- a/packages/sdk/src/global-account/react/hooks/useAuthentication.ts +++ b/packages/sdk/src/global-account/react/hooks/useAuthentication.ts @@ -179,7 +179,7 @@ export function useAuthentication(partnerId: string) { setIsAuthenticated(false); setIsConnected(false); - setUser(); + setUser(undefined); callback?.(); }, [activeWallet, disconnect, wallets, setIsAuthenticated, setUser, setIsConnected], diff --git a/packages/sdk/src/global-account/react/hooks/useClient.ts b/packages/sdk/src/global-account/react/hooks/useClient.ts index 3f3a87f27..02d59617c 100644 --- a/packages/sdk/src/global-account/react/hooks/useClient.ts +++ b/packages/sdk/src/global-account/react/hooks/useClient.ts @@ -1,4 +1,4 @@ -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { useCallback } from "react"; import { ClientType, @@ -13,7 +13,7 @@ import { * Hook to access the current FeathersJS client and client management utilities */ export function useClient() { - const { clientType } = useB3Config(); + const { clientType } = useB3(); const getCurrentClient = useCallback(() => { return getClient(); diff --git a/packages/sdk/src/global-account/react/hooks/useHandleConnectWithPrivy.tsx b/packages/sdk/src/global-account/react/hooks/useHandleConnectWithPrivy.tsx index 39acd1281..a2acfaa1d 100644 --- a/packages/sdk/src/global-account/react/hooks/useHandleConnectWithPrivy.tsx +++ b/packages/sdk/src/global-account/react/hooks/useHandleConnectWithPrivy.tsx @@ -1,4 +1,4 @@ -import { useB3Config, useConnect } from "@b3dotfun/sdk/global-account/react"; +import { useB3, useConnect } from "@b3dotfun/sdk/global-account/react"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { useIdentityToken, usePrivy } from "@privy-io/react-auth"; import { useCallback, useRef, useState } from "react"; @@ -11,7 +11,7 @@ const debug = debugB3React("@@b3:useHandleConnectWithPrivy"); * Currently, this is for the basement-privy strategy */ export function useHandleConnectWithPrivy(chain?: Chain, onSuccess?: (account: Account) => void) { - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); if (!chain) { throw new Error("Chain is required"); } diff --git a/packages/sdk/src/global-account/react/hooks/useNotifications.ts b/packages/sdk/src/global-account/react/hooks/useNotifications.ts index 9ba00024e..bc8bc2ca5 100644 --- a/packages/sdk/src/global-account/react/hooks/useNotifications.ts +++ b/packages/sdk/src/global-account/react/hooks/useNotifications.ts @@ -1,4 +1,4 @@ -import { useB3Config } from "@b3dotfun/sdk/global-account/react"; +import { useB3 } from "@b3dotfun/sdk/global-account/react"; import { getAuthToken } from "@b3dotfun/sdk/shared/utils/auth-token"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { useCallback, useEffect, useState } from "react"; @@ -56,7 +56,7 @@ export interface UseNotificationsReturn { */ export function useNotifications(): UseNotificationsReturn { const { user } = useUserQuery(); - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const [userData, setUserData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); diff --git a/packages/sdk/src/global-account/react/hooks/useTokenBalance.tsx b/packages/sdk/src/global-account/react/hooks/useTokenBalance.tsx index c6bf53583..073a263c1 100644 --- a/packages/sdk/src/global-account/react/hooks/useTokenBalance.tsx +++ b/packages/sdk/src/global-account/react/hooks/useTokenBalance.tsx @@ -1,12 +1,12 @@ "use client"; import { isNativeToken } from "@b3dotfun/sdk/anyspend"; -import { components } from "@b3dotfun/sdk/anyspend/types/api"; -import { useAccountWallet, useAuthStore } from "@b3dotfun/sdk/global-account/react"; +import { useB3, useAccountWallet } from "@b3dotfun/sdk/global-account/react"; import { formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number"; import { getERC20Balances, getNativeTokenBalance } from "@b3dotfun/sdk/shared/utils/thirdweb-insights"; import { useQuery } from "@tanstack/react-query"; import { useEffect } from "react"; +import { components } from "@b3dotfun/sdk/anyspend/types/api"; interface UseTokenBalanceProps { token: components["schemas"]["Token"]; @@ -20,8 +20,7 @@ export interface TokenBalanceResult { } export function useTokenBalance({ token, address }: UseTokenBalanceProps): TokenBalanceResult { - const isAuthenticated = useAuthStore(state => state.isAuthenticated); - + const { ready } = useB3(); const account = useAccountWallet(); const effectiveAddress = address || account?.address; @@ -61,7 +60,7 @@ export function useTokenBalance({ token, address }: UseTokenBalanceProps): Token } return { formatted: "0", raw: null }; }, - enabled: isAuthenticated && !!effectiveAddress, + enabled: ready && !!effectiveAddress, staleTime: 30000, gcTime: 5 * 60 * 1000, retry: 2, @@ -70,13 +69,13 @@ export function useTokenBalance({ token, address }: UseTokenBalanceProps): Token // Force a refetch when the wallet or token changes useEffect(() => { - if (isAuthenticated && effectiveAddress) { + if (ready && effectiveAddress) { refetch(); } - }, [isAuthenticated, effectiveAddress, token.address, token.chainId, token.symbol, refetch]); + }, [ready, effectiveAddress, token.address, token.chainId, token.symbol, refetch]); // Determine if we're actually loading - const isActuallyLoading = !isAuthenticated || !effectiveAddress || isLoading || (isFetching && !tokenBalance); + const isActuallyLoading = !ready || !effectiveAddress || isLoading || (isFetching && !tokenBalance); return { rawBalance: tokenBalance?.raw || BigInt(0), diff --git a/packages/sdk/src/global-account/react/hooks/useTurnkeyAuth.ts b/packages/sdk/src/global-account/react/hooks/useTurnkeyAuth.ts index 7981d5156..e778b7a4d 100644 --- a/packages/sdk/src/global-account/react/hooks/useTurnkeyAuth.ts +++ b/packages/sdk/src/global-account/react/hooks/useTurnkeyAuth.ts @@ -2,7 +2,7 @@ import { TurnkeyAuthInitResponse } from "@b3dotfun/b3-api"; import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { useCallback, useState } from "react"; import app from "../../app"; -import { useB3Config } from "../components"; +import { useB3 } from "../components"; import { useAuthStore } from "../stores"; import { useAuth } from "./useAuth"; @@ -33,7 +33,7 @@ export function useTurnkeyAuth(): UseTurnkeyAuthReturn { const [error, setError] = useState(null); const setIsAuthenticating = useAuthStore(state => state.setIsAuthenticating); const setIsAuthenticated = useAuthStore(state => state.setIsAuthenticated); - const { partnerId } = useB3Config(); + const { partnerId } = useB3(); const { authenticate } = useAuth(); /** diff --git a/packages/sdk/src/global-account/react/hooks/useUser.ts b/packages/sdk/src/global-account/react/hooks/useUser.ts deleted file mode 100644 index 85785e5de..000000000 --- a/packages/sdk/src/global-account/react/hooks/useUser.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useAuthStore } from "@b3dotfun/sdk/global-account/react"; -import { useUserStore } from "../stores/userStore"; - -/** - * Preferred Hook to get the user data - */ -export function useUser() { - const user = useUserStore(state => state.user); - - const isConnecting = useAuthStore(state => state.isConnecting); - const isConnected = useAuthStore(state => state.isConnected); - const isAuthenticating = useAuthStore(state => state.isAuthenticating); - - return { - user, - isConnecting, - isConnected, - isAuthenticating, - }; -} diff --git a/packages/sdk/src/global-account/react/hooks/useUserQuery.ts b/packages/sdk/src/global-account/react/hooks/useUserQuery.ts index 0c5fda41e..e0d33efc8 100644 --- a/packages/sdk/src/global-account/react/hooks/useUserQuery.ts +++ b/packages/sdk/src/global-account/react/hooks/useUserQuery.ts @@ -1,84 +1,71 @@ import { Users } from "@b3dotfun/b3-api"; +import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; import { useEffect } from "react"; -import { useUserStore } from "../stores/userStore"; +import { create } from "zustand"; +import { persist } from "zustand/middleware"; + +const debug = debugB3React("useUserQuery"); const USER_QUERY_KEY = ["b3-user"]; +interface UserStore { + user: Users | null; + setUser: (user: Users | undefined) => void; + clearUser: () => void; +} + +/** + * Zustand store for managing user state + * Persists user data to localStorage + */ +const useUserStore = create()( + persist( + set => ({ + user: null, + setUser: (newUser: Users | undefined) => { + const userToSave = newUser ?? null; + set({ user: userToSave }); + debug("User updated", userToSave); + }, + clearUser: () => { + set({ user: null }); + debug("User cleared"); + }, + }), + { + name: "b3-user", + onRehydrateStorage: () => (_, error) => { + if (error) { + console.warn("Failed to rehydrate user store:", error); + } + }, + }, + ), +); + /** * NOTE: THIS IS ONLY MEANT FOR INTERNAL USE, from useOnConnect * - * Custom hook to manage user state with Zustand - * This allows for invalidation and refetching of user data + * Hook to query and manage user data + * Provides user state and methods to update it + * Uses Zustand store with persistence to localStorage */ export function useUserQuery() { const user = useUserStore(state => state.user); - const setUserStore = useUserStore(state => state.setUser); - const clearUserStore = useUserStore(state => state.clearUser); + const setUser = useUserStore(state => state.setUser); + const clearUser = useUserStore(state => state.clearUser); - // Listen for storage events from other tabs/windows useEffect(() => { - const handleStorageChange = (e: StorageEvent) => { - if (e.key === "b3-user") { - // Sync with changes from other tabs/windows - const stored = e.newValue; - if (stored) { - try { - const parsed = JSON.parse(stored); - // Zustand persist format: { state: { user: ... }, version: ... } - const userData = parsed?.state?.user ?? parsed?.user ?? null; - useUserStore.setState({ user: userData }); - } catch (error) { - console.warn("Failed to parse user from storage event:", error); - } - } else { - useUserStore.setState({ user: null }); - } - } - }; - - window.addEventListener("storage", handleStorageChange); - return () => { - window.removeEventListener("storage", handleStorageChange); - }; - }, []); - - // Helper function to set user (maintains backward compatibility) - const setUser = (newUser?: Users) => { - setUserStore(newUser); - }; - - // Helper function to invalidate and refetch user - const refetchUser = async () => { - // Re-read from localStorage and update store - // Zustand persist stores data as { state: { user: ... }, version: ... } - const stored = localStorage.getItem("b3-user"); - if (stored) { - try { - const parsed = JSON.parse(stored); - // Zustand persist format: { state: { user: ... }, version: ... } - const userData = parsed?.state?.user ?? parsed?.user ?? null; - useUserStore.setState({ user: userData }); - return userData ?? undefined; - } catch (error) { - console.warn("Failed to refetch user from localStorage:", error); - // Fallback to current store state - return useUserStore.getState().user ?? undefined; - } + if (user) { + debug("User loaded from store", user); } - useUserStore.setState({ user: null }); - return undefined; - }; - - // Helper function to clear user - const clearUser = () => { - clearUserStore(); - }; + }, [user]); return { - user: user ?? undefined, + user, setUser, - refetchUser, clearUser, - queryKey: USER_QUERY_KEY, }; } + +export { USER_QUERY_KEY }; diff --git a/packages/sdk/src/global-account/react/index.native.ts b/packages/sdk/src/global-account/react/index.native.ts index c5f40490c..9957fe3d9 100644 --- a/packages/sdk/src/global-account/react/index.native.ts +++ b/packages/sdk/src/global-account/react/index.native.ts @@ -6,6 +6,8 @@ export { B3Provider } from "./components/B3Provider/B3Provider.native"; +export { B3Context, type B3ContextType } from "./components/B3Provider/types"; +export { useB3 } from "./components/B3Provider/useB3"; export { useAccountWallet } from "./hooks/useAccountWallet"; export { useAuthentication } from "./hooks/useAuthentication"; export { useProfile } from "./hooks/useProfile"; diff --git a/packages/sdk/src/global-account/react/stores/userStore.ts b/packages/sdk/src/global-account/react/stores/userStore.ts deleted file mode 100644 index 9b2384da1..000000000 --- a/packages/sdk/src/global-account/react/stores/userStore.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Users } from "@b3dotfun/b3-api"; -import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug"; -import { create } from "zustand"; -import { persist } from "zustand/middleware"; - -const debug = debugB3React("useUserQuery"); - -interface UserStore { - user: Users | null; - setUser: (user: Users | undefined) => void; - clearUser: () => void; -} - -/** - * Zustand store for managing user state - * Persists user data to localStorage - */ -export const useUserStore = create()( - persist( - set => ({ - user: null, - setUser: (newUser: Users | undefined) => { - const userToSave = newUser ?? null; - set({ user: userToSave }); - debug("User updated", userToSave); - }, - clearUser: () => { - set({ user: null }); - debug("User cleared"); - }, - }), - { - name: "b3-user", - onRehydrateStorage: () => (_, error) => { - if (error) { - console.warn("Failed to rehydrate user store:", error); - } - }, - }, - ), -);