@b3dotfun/sdk 0.1.69-test.0 → 0.1.70-alpha.1

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 (190) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.d.ts +2 -0
  2. package/dist/cjs/anyspend/react/components/AnySpend.js +12 -4
  3. package/dist/cjs/anyspend/react/components/AnySpendCollectorClubPurchase.d.ts +5 -1
  4. package/dist/cjs/anyspend/react/components/AnySpendCollectorClubPurchase.js +2 -2
  5. package/dist/cjs/anyspend/react/components/AnySpendCustom.d.ts +2 -0
  6. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +7 -3
  7. package/dist/cjs/anyspend/react/components/AnySpendDeposit.d.ts +3 -1
  8. package/dist/cjs/anyspend/react/components/AnySpendDeposit.js +3 -3
  9. package/dist/cjs/anyspend/react/components/AnySpendNFT.d.ts +3 -1
  10. package/dist/cjs/anyspend/react/components/AnySpendNFT.js +2 -2
  11. package/dist/cjs/anyspend/react/components/AnySpendStakeUpside.d.ts +3 -1
  12. package/dist/cjs/anyspend/react/components/AnySpendStakeUpside.js +2 -2
  13. package/dist/cjs/anyspend/react/components/checkout/AnySpendCheckout.js +6 -5
  14. package/dist/cjs/anyspend/react/components/checkout/CartItemRow.d.ts +2 -1
  15. package/dist/cjs/anyspend/react/components/checkout/CartSummary.d.ts +6 -4
  16. package/dist/cjs/anyspend/react/components/checkout/CartSummary.js +13 -11
  17. package/dist/cjs/anyspend/react/components/checkout/CheckoutCartPanel.d.ts +3 -1
  18. package/dist/cjs/anyspend/react/components/checkout/CheckoutCartPanel.js +5 -4
  19. package/dist/cjs/anyspend/react/components/checkout/CheckoutFormPanel.d.ts +3 -1
  20. package/dist/cjs/anyspend/react/components/checkout/CheckoutFormPanel.js +2 -2
  21. package/dist/cjs/anyspend/react/components/checkout/DiscountCodeInput.d.ts +3 -1
  22. package/dist/cjs/anyspend/react/components/checkout/DiscountCodeInput.js +3 -6
  23. package/dist/cjs/anyspend/react/components/checkout/PriceSkeleton.d.ts +5 -0
  24. package/dist/cjs/anyspend/react/components/checkout/PriceSkeleton.js +9 -0
  25. package/dist/cjs/anyspend/react/components/checkout/ShippingSelector.d.ts +3 -1
  26. package/dist/cjs/anyspend/react/components/checkout/ShippingSelector.js +3 -2
  27. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +3 -1
  28. package/dist/cjs/global-account/react/components/B3Provider/B3ConfigProvider.d.ts +5 -1
  29. package/dist/cjs/global-account/react/components/B3Provider/B3ConfigProvider.js +2 -1
  30. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.d.ts +17 -1
  31. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +3 -2
  32. package/dist/cjs/global-account/react/components/B3Provider/BetterAuthClientProvider.d.ts +17 -0
  33. package/dist/cjs/global-account/react/components/B3Provider/BetterAuthClientProvider.js +31 -0
  34. package/dist/cjs/global-account/react/components/B3Provider/BetterAuthProvider.js +6 -5
  35. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.js +4 -2
  36. package/dist/cjs/global-account/react/components/ManageAccount/Header.js +36 -4
  37. package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.js +4 -1
  38. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +6 -0
  39. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +5 -3
  40. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +3 -1
  41. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.js +25 -14
  42. package/dist/cjs/global-account/react/components/SignInWithB3/BetterAuthResetPassword.js +3 -2
  43. package/dist/cjs/global-account/react/components/SignInWithB3/BetterAuthSignIn.d.ts +6 -1
  44. package/dist/cjs/global-account/react/components/SignInWithB3/BetterAuthSignIn.js +15 -5
  45. package/dist/cjs/global-account/react/components/SignInWithB3/BetterAuthVerifyEmail.d.ts +37 -0
  46. package/dist/cjs/global-account/react/components/SignInWithB3/BetterAuthVerifyEmail.js +85 -0
  47. package/dist/cjs/global-account/react/components/SignInWithB3/SignIn.js +14 -4
  48. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Flow.d.ts +1 -1
  49. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +2 -2
  50. package/dist/cjs/global-account/react/components/SignInWithB3/components/PasswordInput.d.ts +10 -0
  51. package/dist/cjs/global-account/react/components/SignInWithB3/components/PasswordInput.js +10 -0
  52. package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.d.ts +3 -1
  53. package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.js +8 -5
  54. package/dist/cjs/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
  55. package/dist/cjs/global-account/react/components/UserAvatar/UserAvatar.js +27 -0
  56. package/dist/cjs/global-account/react/components/index.d.ts +3 -0
  57. package/dist/cjs/global-account/react/components/index.js +10 -3
  58. package/dist/cjs/global-account/react/hooks/useBetterAuth.d.ts +1 -1
  59. package/dist/cjs/global-account/react/hooks/useBetterAuth.js +19 -17
  60. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +4 -0
  61. package/dist/cjs/shared/constants/index.d.ts +1 -0
  62. package/dist/cjs/shared/constants/index.js +2 -1
  63. package/dist/esm/anyspend/react/components/AnySpend.d.ts +2 -0
  64. package/dist/esm/anyspend/react/components/AnySpend.js +12 -4
  65. package/dist/esm/anyspend/react/components/AnySpendCollectorClubPurchase.d.ts +5 -1
  66. package/dist/esm/anyspend/react/components/AnySpendCollectorClubPurchase.js +2 -2
  67. package/dist/esm/anyspend/react/components/AnySpendCustom.d.ts +2 -0
  68. package/dist/esm/anyspend/react/components/AnySpendCustom.js +7 -3
  69. package/dist/esm/anyspend/react/components/AnySpendDeposit.d.ts +3 -1
  70. package/dist/esm/anyspend/react/components/AnySpendDeposit.js +3 -3
  71. package/dist/esm/anyspend/react/components/AnySpendNFT.d.ts +3 -1
  72. package/dist/esm/anyspend/react/components/AnySpendNFT.js +2 -2
  73. package/dist/esm/anyspend/react/components/AnySpendStakeUpside.d.ts +3 -1
  74. package/dist/esm/anyspend/react/components/AnySpendStakeUpside.js +2 -2
  75. package/dist/esm/anyspend/react/components/checkout/AnySpendCheckout.js +6 -5
  76. package/dist/esm/anyspend/react/components/checkout/CartItemRow.d.ts +2 -1
  77. package/dist/esm/anyspend/react/components/checkout/CartSummary.d.ts +6 -4
  78. package/dist/esm/anyspend/react/components/checkout/CartSummary.js +13 -11
  79. package/dist/esm/anyspend/react/components/checkout/CheckoutCartPanel.d.ts +3 -1
  80. package/dist/esm/anyspend/react/components/checkout/CheckoutCartPanel.js +5 -4
  81. package/dist/esm/anyspend/react/components/checkout/CheckoutFormPanel.d.ts +3 -1
  82. package/dist/esm/anyspend/react/components/checkout/CheckoutFormPanel.js +2 -2
  83. package/dist/esm/anyspend/react/components/checkout/DiscountCodeInput.d.ts +3 -1
  84. package/dist/esm/anyspend/react/components/checkout/DiscountCodeInput.js +3 -6
  85. package/dist/esm/anyspend/react/components/checkout/PriceSkeleton.d.ts +5 -0
  86. package/dist/esm/anyspend/react/components/checkout/PriceSkeleton.js +6 -0
  87. package/dist/esm/anyspend/react/components/checkout/ShippingSelector.d.ts +3 -1
  88. package/dist/esm/anyspend/react/components/checkout/ShippingSelector.js +3 -2
  89. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +3 -1
  90. package/dist/esm/global-account/react/components/B3Provider/B3ConfigProvider.d.ts +5 -1
  91. package/dist/esm/global-account/react/components/B3Provider/B3ConfigProvider.js +2 -1
  92. package/dist/esm/global-account/react/components/B3Provider/B3Provider.d.ts +17 -1
  93. package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +3 -2
  94. package/dist/esm/global-account/react/components/B3Provider/BetterAuthClientProvider.d.ts +17 -0
  95. package/dist/esm/global-account/react/components/B3Provider/BetterAuthClientProvider.js +27 -0
  96. package/dist/esm/global-account/react/components/B3Provider/BetterAuthProvider.js +4 -3
  97. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.js +5 -3
  98. package/dist/esm/global-account/react/components/ManageAccount/Header.js +37 -5
  99. package/dist/esm/global-account/react/components/ManageAccount/HomeContent.js +4 -1
  100. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +7 -1
  101. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +6 -4
  102. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +5 -3
  103. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.js +25 -14
  104. package/dist/esm/global-account/react/components/SignInWithB3/BetterAuthResetPassword.js +4 -3
  105. package/dist/esm/global-account/react/components/SignInWithB3/BetterAuthSignIn.d.ts +6 -1
  106. package/dist/esm/global-account/react/components/SignInWithB3/BetterAuthSignIn.js +16 -6
  107. package/dist/esm/global-account/react/components/SignInWithB3/BetterAuthVerifyEmail.d.ts +37 -0
  108. package/dist/esm/global-account/react/components/SignInWithB3/BetterAuthVerifyEmail.js +82 -0
  109. package/dist/esm/global-account/react/components/SignInWithB3/SignIn.js +15 -5
  110. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Flow.d.ts +1 -1
  111. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +2 -2
  112. package/dist/esm/global-account/react/components/SignInWithB3/components/PasswordInput.d.ts +10 -0
  113. package/dist/esm/global-account/react/components/SignInWithB3/components/PasswordInput.js +7 -0
  114. package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.d.ts +3 -1
  115. package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.js +8 -5
  116. package/dist/esm/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
  117. package/dist/esm/global-account/react/components/UserAvatar/UserAvatar.js +21 -0
  118. package/dist/esm/global-account/react/components/index.d.ts +3 -0
  119. package/dist/esm/global-account/react/components/index.js +4 -0
  120. package/dist/esm/global-account/react/hooks/useBetterAuth.d.ts +1 -1
  121. package/dist/esm/global-account/react/hooks/useBetterAuth.js +12 -10
  122. package/dist/esm/global-account/react/stores/useModalStore.d.ts +4 -0
  123. package/dist/esm/shared/constants/index.d.ts +1 -0
  124. package/dist/esm/shared/constants/index.js +1 -0
  125. package/dist/styles/index.css +1 -1
  126. package/dist/types/anyspend/react/components/AnySpend.d.ts +2 -0
  127. package/dist/types/anyspend/react/components/AnySpendCollectorClubPurchase.d.ts +5 -1
  128. package/dist/types/anyspend/react/components/AnySpendCustom.d.ts +2 -0
  129. package/dist/types/anyspend/react/components/AnySpendDeposit.d.ts +3 -1
  130. package/dist/types/anyspend/react/components/AnySpendNFT.d.ts +3 -1
  131. package/dist/types/anyspend/react/components/AnySpendStakeUpside.d.ts +3 -1
  132. package/dist/types/anyspend/react/components/checkout/CartItemRow.d.ts +2 -1
  133. package/dist/types/anyspend/react/components/checkout/CartSummary.d.ts +6 -4
  134. package/dist/types/anyspend/react/components/checkout/CheckoutCartPanel.d.ts +3 -1
  135. package/dist/types/anyspend/react/components/checkout/CheckoutFormPanel.d.ts +3 -1
  136. package/dist/types/anyspend/react/components/checkout/DiscountCodeInput.d.ts +3 -1
  137. package/dist/types/anyspend/react/components/checkout/PriceSkeleton.d.ts +5 -0
  138. package/dist/types/anyspend/react/components/checkout/ShippingSelector.d.ts +3 -1
  139. package/dist/types/global-account/react/components/B3Provider/B3ConfigProvider.d.ts +5 -1
  140. package/dist/types/global-account/react/components/B3Provider/B3Provider.d.ts +17 -1
  141. package/dist/types/global-account/react/components/B3Provider/BetterAuthClientProvider.d.ts +17 -0
  142. package/dist/types/global-account/react/components/SignInWithB3/BetterAuthSignIn.d.ts +6 -1
  143. package/dist/types/global-account/react/components/SignInWithB3/BetterAuthVerifyEmail.d.ts +37 -0
  144. package/dist/types/global-account/react/components/SignInWithB3/SignInWithB3Flow.d.ts +1 -1
  145. package/dist/types/global-account/react/components/SignInWithB3/components/PasswordInput.d.ts +10 -0
  146. package/dist/types/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.d.ts +3 -1
  147. package/dist/types/global-account/react/components/UserAvatar/UserAvatar.d.ts +18 -0
  148. package/dist/types/global-account/react/components/index.d.ts +3 -0
  149. package/dist/types/global-account/react/hooks/useBetterAuth.d.ts +1 -1
  150. package/dist/types/global-account/react/stores/useModalStore.d.ts +4 -0
  151. package/dist/types/shared/constants/index.d.ts +1 -0
  152. package/package.json +1 -1
  153. package/src/anyspend/react/components/AnySpend.tsx +24 -12
  154. package/src/anyspend/react/components/AnySpendCollectorClubPurchase.tsx +6 -0
  155. package/src/anyspend/react/components/AnySpendCustom.tsx +12 -2
  156. package/src/anyspend/react/components/AnySpendDeposit.tsx +38 -31
  157. package/src/anyspend/react/components/AnySpendNFT.tsx +4 -0
  158. package/src/anyspend/react/components/AnySpendStakeUpside.tsx +4 -0
  159. package/src/anyspend/react/components/checkout/AnySpendCheckout.tsx +10 -4
  160. package/src/anyspend/react/components/checkout/CartItemRow.tsx +2 -1
  161. package/src/anyspend/react/components/checkout/CartSummary.tsx +24 -20
  162. package/src/anyspend/react/components/checkout/CheckoutCartPanel.tsx +12 -3
  163. package/src/anyspend/react/components/checkout/CheckoutFormPanel.tsx +5 -0
  164. package/src/anyspend/react/components/checkout/DiscountCodeInput.tsx +15 -5
  165. package/src/anyspend/react/components/checkout/PriceSkeleton.tsx +19 -0
  166. package/src/anyspend/react/components/checkout/ShippingSelector.tsx +5 -1
  167. package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +3 -1
  168. package/src/global-account/react/components/B3Provider/B3ConfigProvider.tsx +6 -0
  169. package/src/global-account/react/components/B3Provider/B3Provider.tsx +36 -15
  170. package/src/global-account/react/components/B3Provider/BetterAuthClientProvider.tsx +40 -0
  171. package/src/global-account/react/components/B3Provider/BetterAuthProvider.tsx +4 -3
  172. package/src/global-account/react/components/ManageAccount/BottomNavigation.tsx +18 -14
  173. package/src/global-account/react/components/ManageAccount/Header.tsx +71 -4
  174. package/src/global-account/react/components/ManageAccount/HomeContent.tsx +25 -19
  175. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +13 -0
  176. package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +14 -7
  177. package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +15 -32
  178. package/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +29 -20
  179. package/src/global-account/react/components/SignInWithB3/BetterAuthResetPassword.tsx +6 -7
  180. package/src/global-account/react/components/SignInWithB3/BetterAuthSignIn.tsx +27 -7
  181. package/src/global-account/react/components/SignInWithB3/BetterAuthVerifyEmail.tsx +155 -0
  182. package/src/global-account/react/components/SignInWithB3/SignIn.tsx +42 -13
  183. package/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx +8 -1
  184. package/src/global-account/react/components/SignInWithB3/components/PasswordInput.tsx +62 -0
  185. package/src/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.tsx +13 -6
  186. package/src/global-account/react/components/UserAvatar/UserAvatar.tsx +45 -0
  187. package/src/global-account/react/components/index.ts +9 -0
  188. package/src/global-account/react/hooks/useBetterAuth.ts +12 -10
  189. package/src/global-account/react/stores/useModalStore.ts +4 -0
  190. package/src/shared/constants/index.ts +2 -0
@@ -30,6 +30,7 @@ export function AnySpendStakeUpside({
30
30
  slots,
31
31
  content,
32
32
  theme,
33
+ showFiatOption = true,
33
34
  }: {
34
35
  loadOrder?: string;
35
36
  mode?: "modal" | "page";
@@ -44,6 +45,8 @@ export function AnySpendStakeUpside({
44
45
  slots?: AnySpendSlots;
45
46
  content?: AnySpendContent;
46
47
  theme?: AnySpendTheme;
48
+ /** Whether to show the "Pay with fiat" tab. Defaults to true. */
49
+ showFiatOption?: boolean;
47
50
  }) {
48
51
  const header = () => (
49
52
  <>
@@ -90,6 +93,7 @@ export function AnySpendStakeUpside({
90
93
  onSuccess={onSuccess}
91
94
  showRecipient={true}
92
95
  activeTab={activeTab}
96
+ showFiatOption={showFiatOption}
93
97
  senderAddress={senderAddress}
94
98
  slots={slots}
95
99
  content={content}
@@ -295,10 +295,14 @@ export function AnySpendCheckout({
295
295
  variablePricingAmount,
296
296
  ]);
297
297
 
298
- // Get destination token metadata
299
- const { data: tokenData } = useTokenData(destinationTokenChainId, destinationTokenAddress);
300
- const tokenSymbol = tokenData?.symbol || "";
301
- const tokenDecimals = tokenData?.decimals || 18;
298
+ // Get destination token metadata. While loading, skip price-dependent UI
299
+ // since the 18-decimal fallback is wrong for non-18 tokens (e.g. USDC).
300
+ const { data: tokenData, isLoading: isTokenDataLoading } = useTokenData(
301
+ destinationTokenChainId,
302
+ destinationTokenAddress,
303
+ );
304
+ const tokenSymbol = tokenData?.symbol ?? "";
305
+ const tokenDecimals = tokenData?.decimals ?? 18;
302
306
 
303
307
  // Resolve USD equivalent for non-stablecoin tokens (shown in cart summary)
304
308
  const isStablecoin = useMemo(() => {
@@ -412,6 +416,7 @@ export function AnySpendCheckout({
412
416
  validateDiscount={validateDiscount}
413
417
  tokenSymbol={tokenSymbol}
414
418
  tokenDecimals={tokenDecimals}
419
+ pricesLoading={isTokenDataLoading}
415
420
  classes={classes}
416
421
  formData={formData}
417
422
  onFormDataChange={handleFormDataChange}
@@ -456,6 +461,7 @@ export function AnySpendCheckout({
456
461
  totalAmount={computedTotal}
457
462
  tokenSymbol={tokenSymbol}
458
463
  tokenDecimals={tokenDecimals}
464
+ pricesLoading={isTokenDataLoading}
459
465
  organizationName={organizationName}
460
466
  organizationLogo={organizationLogo}
461
467
  classes={classes}
@@ -1,11 +1,12 @@
1
1
  "use client";
2
2
 
3
3
  import { cn } from "@b3dotfun/sdk/shared/utils/cn";
4
+ import type { ReactNode } from "react";
4
5
  import type { CheckoutItem, AnySpendCheckoutClasses } from "./AnySpendCheckout";
5
6
 
6
7
  interface CartItemRowProps {
7
8
  item: CheckoutItem;
8
- formattedPrice: string;
9
+ formattedPrice: ReactNode;
9
10
  classes?: AnySpendCheckoutClasses;
10
11
  }
11
12
 
@@ -2,13 +2,12 @@
2
2
 
3
3
  import { cn } from "@b3dotfun/sdk/shared/utils/cn";
4
4
  import { formatTokenAmount, safeBigInt } from "@b3dotfun/sdk/shared/utils/number";
5
- import { useMemo } from "react";
6
- import type { AnySpendCheckoutClasses } from "./AnySpendCheckout";
7
- import type { CheckoutSummaryLine } from "./AnySpendCheckout";
5
+ import { useMemo, type ReactNode } from "react";
6
+ import type { AnySpendCheckoutClasses, CheckoutSummaryLine } from "./AnySpendCheckout";
8
7
 
9
8
  interface CartSummaryProps {
10
9
  /** Formatted total (final amount after all adjustments) */
11
- total: string;
10
+ total: ReactNode;
12
11
  tokenSymbol?: string;
13
12
  classes?: AnySpendCheckoutClasses;
14
13
  /** Formatted subtotal (sum of items only — shown when adjustments exist) */
@@ -20,6 +19,8 @@ interface CartSummaryProps {
20
19
  summaryLines?: CheckoutSummaryLine[];
21
20
  /** Formatted USD equivalent (e.g. "$5.56") — shown for non-stablecoin tokens */
22
21
  usdEquivalent?: string | null;
22
+ /** When true, hide adjustment rows and USD equivalent (caller passes a skeleton as `total`). */
23
+ pricesLoading?: boolean;
23
24
  }
24
25
 
25
26
  export function CartSummary({
@@ -33,35 +34,38 @@ export function CartSummary({
33
34
  discount,
34
35
  summaryLines,
35
36
  usdEquivalent,
37
+ pricesLoading = false,
36
38
  }: CartSummaryProps) {
37
- const hasAdjustments =
38
- !!shipping?.amount || !!tax?.amount || !!discount?.amount || (summaryLines && summaryLines.length > 0);
39
-
40
39
  const formattedShipping = useMemo(
41
- () => (shipping?.amount ? formatTokenAmount(safeBigInt(shipping.amount), tokenDecimals) : null),
42
- [shipping?.amount, tokenDecimals],
40
+ () => (!pricesLoading && shipping?.amount ? formatTokenAmount(safeBigInt(shipping.amount), tokenDecimals) : null),
41
+ [pricesLoading, shipping?.amount, tokenDecimals],
43
42
  );
44
43
 
45
44
  const formattedTax = useMemo(
46
- () => (tax?.amount ? formatTokenAmount(safeBigInt(tax.amount), tokenDecimals) : null),
47
- [tax?.amount, tokenDecimals],
45
+ () => (!pricesLoading && tax?.amount ? formatTokenAmount(safeBigInt(tax.amount), tokenDecimals) : null),
46
+ [pricesLoading, tax?.amount, tokenDecimals],
48
47
  );
49
48
 
50
49
  const formattedDiscount = useMemo(
51
- () => (discount?.amount ? formatTokenAmount(safeBigInt(discount.amount), tokenDecimals) : null),
52
- [discount?.amount, tokenDecimals],
50
+ () => (!pricesLoading && discount?.amount ? formatTokenAmount(safeBigInt(discount.amount), tokenDecimals) : null),
51
+ [pricesLoading, discount?.amount, tokenDecimals],
53
52
  );
54
53
 
55
54
  const formattedSummaryLines = useMemo(
56
55
  () =>
57
- summaryLines?.map(line => ({
58
- ...line,
59
- formattedAmount: formatTokenAmount(safeBigInt(line.amount), tokenDecimals),
60
- isNegative: safeBigInt(line.amount) < BigInt(0),
61
- })),
62
- [summaryLines, tokenDecimals],
56
+ pricesLoading
57
+ ? undefined
58
+ : summaryLines?.map(line => ({
59
+ ...line,
60
+ formattedAmount: formatTokenAmount(safeBigInt(line.amount), tokenDecimals),
61
+ isNegative: safeBigInt(line.amount) < BigInt(0),
62
+ })),
63
+ [pricesLoading, summaryLines, tokenDecimals],
63
64
  );
64
65
 
66
+ const hasAdjustments =
67
+ !!formattedShipping || !!formattedTax || !!formattedDiscount || !!formattedSummaryLines?.length;
68
+
65
69
  return (
66
70
  <div className={cn("border-t border-gray-200 pt-3 dark:border-neutral-700", classes?.cartSummary)}>
67
71
  {/* Subtotal — only shown when adjustments exist */}
@@ -147,7 +151,7 @@ export function CartSummary({
147
151
  {total} {tokenSymbol}
148
152
  </span>
149
153
  </div>
150
- {usdEquivalent && (
154
+ {!pricesLoading && usdEquivalent && (
151
155
  <div className="flex justify-end">
152
156
  <span className="text-xs text-gray-400 dark:text-gray-500">~{usdEquivalent} USD</span>
153
157
  </div>
@@ -7,12 +7,15 @@ import type { CheckoutItem, CheckoutSummaryLine, AnySpendCheckoutClasses } from
7
7
  import { CartItemRow } from "./CartItemRow";
8
8
  import { CartSummary } from "./CartSummary";
9
9
  import { PoweredByBranding } from "./PoweredByBranding";
10
+ import { PriceSkeleton } from "./PriceSkeleton";
10
11
 
11
12
  interface CheckoutCartPanelProps {
12
13
  items: CheckoutItem[];
13
14
  totalAmount: string;
14
15
  tokenSymbol?: string;
15
16
  tokenDecimals?: number;
17
+ /** True while token decimals/symbol are still loading — prevents rendering mis-decimalized prices. */
18
+ pricesLoading?: boolean;
16
19
  organizationName?: string;
17
20
  organizationLogo?: string;
18
21
  classes?: AnySpendCheckoutClasses;
@@ -31,6 +34,7 @@ export function CheckoutCartPanel({
31
34
  totalAmount,
32
35
  tokenSymbol = "",
33
36
  tokenDecimals = 18,
37
+ pricesLoading = false,
34
38
  organizationName,
35
39
  organizationLogo,
36
40
  classes,
@@ -56,7 +60,7 @@ export function CheckoutCartPanel({
56
60
  }, [items, tokenDecimals]);
57
61
 
58
62
  return (
59
- <div className={cn("anyspend-cart-panel flex flex-col", classes?.cartPanel)}>
63
+ <div className={cn("anyspend-cart-panel flex flex-col", classes?.cartPanel)} aria-busy={pricesLoading || undefined}>
60
64
  <h2
61
65
  className={cn(
62
66
  "anyspend-cart-title mb-4 text-lg font-semibold text-gray-900 dark:text-gray-100",
@@ -69,14 +73,18 @@ export function CheckoutCartPanel({
69
73
  <div className="anyspend-cart-items divide-y divide-gray-100 dark:divide-gray-800">
70
74
  {items.map((item, index) => {
71
75
  const itemTotal = safeBigInt(item.amount) * BigInt(item.quantity);
72
- const formattedPrice = `${formatTokenAmount(itemTotal, tokenDecimals)} ${tokenSymbol}`;
76
+ const formattedPrice: ReactNode = pricesLoading ? (
77
+ <PriceSkeleton />
78
+ ) : (
79
+ `${formatTokenAmount(itemTotal, tokenDecimals)} ${tokenSymbol}`
80
+ );
73
81
 
74
82
  return <CartItemRow key={item.id || index} item={item} formattedPrice={formattedPrice} classes={classes} />;
75
83
  })}
76
84
  </div>
77
85
 
78
86
  <CartSummary
79
- total={formattedTotal}
87
+ total={pricesLoading ? <PriceSkeleton className="w-20" /> : formattedTotal}
80
88
  tokenSymbol={tokenSymbol}
81
89
  classes={classes}
82
90
  subtotal={formattedSubtotal}
@@ -86,6 +94,7 @@ export function CheckoutCartPanel({
86
94
  discount={discount}
87
95
  summaryLines={summaryLines}
88
96
  usdEquivalent={usdEquivalent}
97
+ pricesLoading={pricesLoading}
89
98
  />
90
99
 
91
100
  {footer === undefined ? (
@@ -31,6 +31,8 @@ interface CheckoutFormPanelProps {
31
31
  /** Token info for display */
32
32
  tokenSymbol?: string;
33
33
  tokenDecimals?: number;
34
+ /** True while token decimals/symbol are still loading — prevents rendering mis-decimalized prices. */
35
+ pricesLoading?: boolean;
34
36
  /** CSS class overrides */
35
37
  classes?: AnySpendCheckoutClasses;
36
38
  /** Current form data (lifted state) */
@@ -62,6 +64,7 @@ export function CheckoutFormPanel({
62
64
  validateDiscount,
63
65
  tokenSymbol,
64
66
  tokenDecimals,
67
+ pricesLoading = false,
65
68
  classes,
66
69
  formData,
67
70
  onFormDataChange,
@@ -144,6 +147,7 @@ export function CheckoutFormPanel({
144
147
  onSelect={onShippingChange}
145
148
  tokenSymbol={tokenSymbol}
146
149
  tokenDecimals={tokenDecimals}
150
+ pricesLoading={pricesLoading}
147
151
  />
148
152
  )}
149
153
  {enableDiscountCode && validateDiscount && (
@@ -153,6 +157,7 @@ export function CheckoutFormPanel({
153
157
  onRemove={onDiscountRemoved}
154
158
  tokenSymbol={tokenSymbol}
155
159
  tokenDecimals={tokenDecimals}
160
+ pricesLoading={pricesLoading}
156
161
  />
157
162
  )}
158
163
  </>
@@ -5,6 +5,7 @@ import { formatTokenAmount, safeBigInt } from "@b3dotfun/sdk/shared/utils/number
5
5
  import { X, Loader2, Check } from "lucide-react";
6
6
  import { useState, useCallback } from "react";
7
7
  import type { DiscountResult } from "../../../types/forms";
8
+ import { PriceSkeleton } from "./PriceSkeleton";
8
9
 
9
10
  interface DiscountCodeInputProps {
10
11
  onApply: (code: string) => Promise<DiscountResult>;
@@ -13,6 +14,8 @@ interface DiscountCodeInputProps {
13
14
  loading?: boolean;
14
15
  tokenSymbol?: string;
15
16
  tokenDecimals?: number;
17
+ /** True while token decimals/symbol are still loading — renders applied amount as skeleton. */
18
+ pricesLoading?: boolean;
16
19
  className?: string;
17
20
  }
18
21
 
@@ -29,6 +32,7 @@ export function DiscountCodeInput({
29
32
  loading = false,
30
33
  tokenSymbol = "",
31
34
  tokenDecimals = 6,
35
+ pricesLoading = false,
32
36
  className,
33
37
  }: DiscountCodeInputProps) {
34
38
  const [code, setCode] = useState("");
@@ -67,11 +71,17 @@ export function DiscountCodeInput({
67
71
  <div className="flex items-center gap-2">
68
72
  <Check className="h-4 w-4 text-green-600 dark:text-green-400" />
69
73
  <span className="anyspend-discount-value text-sm font-medium text-green-700 dark:text-green-300">
70
- {appliedDiscount.discount_type === "percentage"
71
- ? `${appliedDiscount.discount_value}% off`
72
- : appliedDiscount.discount_amount
73
- ? `-${formatAmount(appliedDiscount.discount_amount, tokenDecimals, tokenSymbol)}`
74
- : "Discount applied"}
74
+ {appliedDiscount.discount_type === "percentage" ? (
75
+ `${appliedDiscount.discount_value}% off`
76
+ ) : appliedDiscount.discount_amount ? (
77
+ pricesLoading ? (
78
+ <PriceSkeleton />
79
+ ) : (
80
+ `-${formatAmount(appliedDiscount.discount_amount, tokenDecimals, tokenSymbol)}`
81
+ )
82
+ ) : (
83
+ "Discount applied"
84
+ )}
75
85
  </span>
76
86
  </div>
77
87
  <button
@@ -0,0 +1,19 @@
1
+ "use client";
2
+
3
+ import { cn } from "@b3dotfun/sdk/shared/utils/cn";
4
+
5
+ interface PriceSkeletonProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function PriceSkeleton({ className }: PriceSkeletonProps) {
10
+ return (
11
+ <span
12
+ className={cn(
13
+ "animate-pulse-fade bg-b3-react-background inline-block h-4 w-16 rounded-md align-middle",
14
+ className,
15
+ )}
16
+ aria-hidden="true"
17
+ />
18
+ );
19
+ }
@@ -3,6 +3,7 @@
3
3
  import { cn } from "@b3dotfun/sdk/shared/utils/cn";
4
4
  import { formatTokenAmount, safeBigInt } from "@b3dotfun/sdk/shared/utils/number";
5
5
  import type { ShippingOption } from "../../../types/forms";
6
+ import { PriceSkeleton } from "./PriceSkeleton";
6
7
 
7
8
  interface ShippingSelectorProps {
8
9
  options: ShippingOption[];
@@ -10,6 +11,8 @@ interface ShippingSelectorProps {
10
11
  onSelect: (option: ShippingOption) => void;
11
12
  tokenSymbol?: string;
12
13
  tokenDecimals?: number;
14
+ /** True while token decimals/symbol are still loading — renders price as skeleton. */
15
+ pricesLoading?: boolean;
13
16
  className?: string;
14
17
  }
15
18
 
@@ -25,6 +28,7 @@ export function ShippingSelector({
25
28
  onSelect,
26
29
  tokenSymbol = "",
27
30
  tokenDecimals = 6,
31
+ pricesLoading = false,
28
32
  className,
29
33
  }: ShippingSelectorProps) {
30
34
  if (options.length === 0) return null;
@@ -63,7 +67,7 @@ export function ShippingSelector({
63
67
  </div>
64
68
  </div>
65
69
  <div className="anyspend-shipping-option-price text-sm font-medium text-gray-900 dark:text-gray-100">
66
- {formatAmount(option.amount, tokenDecimals, tokenSymbol)}
70
+ {pricesLoading ? <PriceSkeleton /> : formatAmount(option.amount, tokenDecimals, tokenSymbol)}
67
71
  </div>
68
72
  </label>
69
73
  ))}
@@ -62,6 +62,8 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
62
62
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
63
63
  const contentType = useModalStore(state => state.contentType);
64
64
 
65
+ const { authStrategy } = useB3Config();
66
+ const isBetterAuth = authStrategy === "better-auth";
65
67
  const account = useActiveAccount();
66
68
  const { data: profile, refetch: refreshProfile } = useProfile({
67
69
  address: account?.address,
@@ -162,7 +164,7 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
162
164
  };
163
165
 
164
166
  const handleSaveChanges = async () => {
165
- if (!account?.address) {
167
+ if (!isBetterAuth && !account?.address) {
166
168
  toast.error("No account connected");
167
169
  return;
168
170
  }
@@ -28,6 +28,8 @@ export interface B3ConfigContextType {
28
28
  stripePublishableKey?: string;
29
29
  createClientReferenceId?: (params: CreateOrderParams | CreateOnrampOrderParams) => Promise<string>;
30
30
  authStrategy: AuthStrategy;
31
+ /** Override the API base URL for all auth operations (Better Auth client, Feathers JWT exchange). */
32
+ apiUrl?: string;
31
33
  }
32
34
 
33
35
  const B3ConfigContext = createContext<B3ConfigContextType | null>(null);
@@ -44,6 +46,7 @@ export function B3ConfigProvider({
44
46
  stripePublishableKey,
45
47
  createClientReferenceId,
46
48
  authStrategy = "thirdweb",
49
+ apiUrl,
47
50
  }: {
48
51
  children: React.ReactNode;
49
52
  accountOverride?: Account;
@@ -56,6 +59,8 @@ export function B3ConfigProvider({
56
59
  stripePublishableKey?: string;
57
60
  createClientReferenceId?: (params: CreateOrderParams | CreateOnrampOrderParams) => Promise<string>;
58
61
  authStrategy?: AuthStrategy;
62
+ /** Override the API base URL for all auth operations (Better Auth client, Feathers JWT exchange). */
63
+ apiUrl?: string;
59
64
  }) {
60
65
  return (
61
66
  <B3ConfigContext.Provider
@@ -70,6 +75,7 @@ export function B3ConfigProvider({
70
75
  stripePublishableKey,
71
76
  createClientReferenceId,
72
77
  authStrategy,
78
+ apiUrl,
73
79
  }}
74
80
  >
75
81
  {children}
@@ -16,6 +16,7 @@ import { StyleRoot } from "../StyleRoot";
16
16
  import { setToastContext, ToastProvider, useToastContext } from "../Toast/index";
17
17
  import AuthenticationProvider from "./AuthenticationProvider";
18
18
  import { B3ConfigProvider } from "./B3ConfigProvider";
19
+ import { BetterAuthClientProvider } from "./BetterAuthClientProvider";
19
20
  import BetterAuthProvider from "./BetterAuthProvider";
20
21
  import { LocalSDKProvider } from "./LocalSDKProvider";
21
22
 
@@ -45,6 +46,7 @@ export function B3Provider({
45
46
  disableBSMNTAuthentication = false,
46
47
  queryClient,
47
48
  authStrategy = "thirdweb",
49
+ apiUrl,
48
50
  }: {
49
51
  theme: "light" | "dark";
50
52
  children: React.ReactNode;
@@ -74,6 +76,22 @@ export function B3Provider({
74
76
  queryClient?: QueryClient;
75
77
  /** Auth strategy: "thirdweb" (default, ecosystem wallet) or "better-auth" (email/password via Better Auth) */
76
78
  authStrategy?: AuthStrategy;
79
+ /**
80
+ * Override the API base URL for Better Auth operations.
81
+ *
82
+ * When set, the Better Auth client (signIn, signUp, signOut, getSession) will
83
+ * target this URL instead of the default `B3_API_URL` / `NEXT_PUBLIC_B3_API`.
84
+ *
85
+ * Useful for local development where the frontend runs on localhost:3003 and
86
+ * the b3-api runs on localhost:3031 — keeps the entire OAuth flow local so
87
+ * sessions, cookies, and token exchange all hit the same server.
88
+ *
89
+ * @example
90
+ * ```tsx
91
+ * <B3Provider apiUrl="http://localhost:3031" ... />
92
+ * ```
93
+ */
94
+ apiUrl?: string;
77
95
  }) {
78
96
  // Initialize Google Analytics on mount
79
97
  useEffect(() => {
@@ -110,22 +128,25 @@ export function B3Provider({
110
128
  createClientReferenceId={createClientReferenceId}
111
129
  defaultPermissions={defaultPermissions}
112
130
  authStrategy={authStrategy}
131
+ apiUrl={apiUrl}
113
132
  >
114
- <ToastContextConnector />
115
- <RelayKitProviderWrapper simDuneApiKey={simDuneApiKey}>
116
- {children}
117
- {/* For the modal https://github.com/b3-fun/b3/blob/main/packages/sdk/src/global-account/react/components/ui/dialog.tsx#L46 */}
118
- <StyleRoot id="b3-root" />
119
- </RelayKitProviderWrapper>
120
- {authStrategy === "better-auth" ? (
121
- <BetterAuthProvider partnerId={partnerId} />
122
- ) : (
123
- <AuthenticationProvider
124
- partnerId={partnerId}
125
- automaticallySetFirstEoa={!!automaticallySetFirstEoa}
126
- defaultEoaProvider={defaultEoaProvider}
127
- />
128
- )}
133
+ <BetterAuthClientProvider apiUrl={apiUrl}>
134
+ <ToastContextConnector />
135
+ <RelayKitProviderWrapper simDuneApiKey={simDuneApiKey}>
136
+ {children}
137
+ {/* For the modal https://github.com/b3-fun/b3/blob/main/packages/sdk/src/global-account/react/components/ui/dialog.tsx#L46 */}
138
+ <StyleRoot id="b3-root" />
139
+ </RelayKitProviderWrapper>
140
+ {authStrategy === "better-auth" ? (
141
+ <BetterAuthProvider partnerId={partnerId} />
142
+ ) : (
143
+ <AuthenticationProvider
144
+ partnerId={partnerId}
145
+ automaticallySetFirstEoa={!!automaticallySetFirstEoa}
146
+ defaultEoaProvider={defaultEoaProvider}
147
+ />
148
+ )}
149
+ </BetterAuthClientProvider>
129
150
  </B3ConfigProvider>
130
151
  </LocalSDKProvider>
131
152
  </ToastProvider>
@@ -0,0 +1,40 @@
1
+ import { createContext, useContext, useMemo } from "react";
2
+ import {
3
+ betterAuthClient,
4
+ createB3BetterAuthClient,
5
+ type B3BetterAuthClient,
6
+ } from "../../../better-auth-client";
7
+
8
+ const BetterAuthClientContext = createContext<B3BetterAuthClient>(betterAuthClient);
9
+
10
+ /**
11
+ * Provides a Better Auth client instance to the subtree.
12
+ *
13
+ * When `apiUrl` is supplied, a custom client targeting that URL is created
14
+ * (e.g. `http://localhost:3031` for local development). Otherwise, the
15
+ * default singleton (which uses `B3_API_URL` / `NEXT_PUBLIC_B3_API`) is used.
16
+ */
17
+ export function BetterAuthClientProvider({
18
+ children,
19
+ apiUrl,
20
+ }: {
21
+ children: React.ReactNode;
22
+ apiUrl?: string;
23
+ }) {
24
+ const client = useMemo(() => {
25
+ if (apiUrl) {
26
+ return createB3BetterAuthClient(apiUrl);
27
+ }
28
+ return betterAuthClient;
29
+ }, [apiUrl]);
30
+
31
+ return <BetterAuthClientContext.Provider value={client}>{children}</BetterAuthClientContext.Provider>;
32
+ }
33
+
34
+ /**
35
+ * Returns the Better Auth client from the nearest `BetterAuthClientProvider`.
36
+ * Falls back to the default singleton if no provider is present.
37
+ */
38
+ export function useBetterAuthClient(): B3BetterAuthClient {
39
+ return useContext(BetterAuthClientContext);
40
+ }
@@ -4,8 +4,8 @@ import { B3_AUTH_COOKIE_NAME } from "@b3dotfun/sdk/shared/constants";
4
4
  import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
5
5
  import Cookies from "js-cookie";
6
6
  import { useEffect, useRef } from "react";
7
- import { betterAuthClient } from "../../../better-auth-client";
8
7
  import { useUserQuery } from "../../hooks/useUserQuery";
8
+ import { useBetterAuthClient } from "./BetterAuthClientProvider";
9
9
 
10
10
  const debug = debugB3React("BetterAuthProvider");
11
11
 
@@ -22,6 +22,7 @@ const debug = debugB3React("BetterAuthProvider");
22
22
  * useAuth, SignIn component, etc.) automatically clears the Better Auth session.
23
23
  */
24
24
  const BetterAuthProvider = ({ partnerId }: { partnerId: string }) => {
25
+ const betterAuthClient = useBetterAuthClient();
25
26
  const setIsAuthenticated = useAuthStore(state => state.setIsAuthenticated);
26
27
  const setIsAuthenticating = useAuthStore(state => state.setIsAuthenticating);
27
28
  const setIsConnected = useAuthStore(state => state.setIsConnected);
@@ -54,7 +55,7 @@ const BetterAuthProvider = ({ partnerId }: { partnerId: string }) => {
54
55
  (app as any).logout = originalLogout;
55
56
  hasPatched.current = false;
56
57
  };
57
- }, []);
58
+ }, [betterAuthClient]);
58
59
 
59
60
  // Session restore on mount
60
61
  useEffect(() => {
@@ -119,7 +120,7 @@ const BetterAuthProvider = ({ partnerId }: { partnerId: string }) => {
119
120
  };
120
121
 
121
122
  restoreSession();
122
- }, [setIsAuthenticated, setIsAuthenticating, setIsConnected, setUser, partnerId]);
123
+ }, [setIsAuthenticated, setIsAuthenticating, setIsConnected, setUser, partnerId, betterAuthClient]);
123
124
 
124
125
  return null;
125
126
  };
@@ -1,4 +1,4 @@
1
- import { TabsListPrimitive, TabTriggerPrimitive, useModalStore } from "@b3dotfun/sdk/global-account/react";
1
+ import { TabsListPrimitive, TabTriggerPrimitive, useB3Config, useModalStore } from "@b3dotfun/sdk/global-account/react";
2
2
 
3
3
  const HomeIcon = () => {
4
4
  return (
@@ -42,6 +42,8 @@ const SettingsIcon = () => {
42
42
 
43
43
  const BottomNavigation = () => {
44
44
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
45
+ const { authStrategy } = useB3Config();
46
+ const isBetterAuth = authStrategy === "better-auth";
45
47
 
46
48
  return (
47
49
  <div className="b3-modal-bottom-navigation sticky bottom-0 left-0 w-full rounded-b-xl border-t border-gray-200 bg-[#FAFAFA]">
@@ -54,19 +56,21 @@ const BottomNavigation = () => {
54
56
  <span className="text-b3-grey font-neue-montreal-semibold text-xs">Home</span>
55
57
  </TabTriggerPrimitive>
56
58
 
57
- <TabTriggerPrimitive
58
- value="swap"
59
- className="data-[state=active]:border-b3-primary-blue group flex flex-initial flex-col items-center gap-1 border-r-0 border-t-0 px-6 pb-2 pt-2.5 text-[#a0a0ab] data-[state=active]:border-t-4 data-[state=active]:text-[#18181B] dark:data-[state=active]:text-white"
60
- onClick={() => {
61
- setB3ModalContentType({
62
- type: "anySpend",
63
- showBackButton: true,
64
- });
65
- }}
66
- >
67
- <SwapIcon />
68
- <span className="text-b3-grey font-neue-montreal-semibold text-xs">Swap</span>
69
- </TabTriggerPrimitive>
59
+ {!isBetterAuth && (
60
+ <TabTriggerPrimitive
61
+ value="swap"
62
+ className="data-[state=active]:border-b3-primary-blue group flex flex-initial flex-col items-center gap-1 border-r-0 border-t-0 px-6 pb-2 pt-2.5 text-[#a0a0ab] data-[state=active]:border-t-4 data-[state=active]:text-[#18181B] dark:data-[state=active]:text-white"
63
+ onClick={() => {
64
+ setB3ModalContentType({
65
+ type: "anySpend",
66
+ showBackButton: true,
67
+ });
68
+ }}
69
+ >
70
+ <SwapIcon />
71
+ <span className="text-b3-grey font-neue-montreal-semibold text-xs">Swap</span>
72
+ </TabTriggerPrimitive>
73
+ )}
70
74
 
71
75
  <TabTriggerPrimitive
72
76
  value="settings"