@b3dotfun/sdk 0.1.70-alpha.2 → 0.1.70-alpha.21

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 (355) hide show
  1. package/README.md +3 -3
  2. package/constants/chains/b3Chain.js +3 -1
  3. package/dist/cjs/anyspend/constants/rpc.d.ts +3 -1
  4. package/dist/cjs/anyspend/constants/rpc.js +6 -2
  5. package/dist/cjs/anyspend/react/components/AnySpend.d.ts +9 -1
  6. package/dist/cjs/anyspend/react/components/AnySpend.js +123 -46
  7. package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +8 -10
  8. package/dist/cjs/anyspend/react/components/AnySpendDeposit.d.ts +15 -3
  9. package/dist/cjs/anyspend/react/components/AnySpendDeposit.js +78 -25
  10. package/dist/cjs/anyspend/react/components/AnySpendStakeB3.js +32 -13
  11. package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.js +32 -10
  12. package/dist/cjs/anyspend/react/components/QRDeposit.d.ts +22 -3
  13. package/dist/cjs/anyspend/react/components/QRDeposit.js +25 -16
  14. package/dist/cjs/anyspend/react/components/checkout/CryptoPayPanel.js +18 -11
  15. package/dist/cjs/anyspend/react/components/common/PureTransferView.d.ts +30 -0
  16. package/dist/cjs/anyspend/react/components/common/PureTransferView.js +64 -0
  17. package/dist/cjs/anyspend/react/components/common/TokenBalance.js +4 -5
  18. package/dist/cjs/anyspend/react/hooks/useCreateDepositFirstOrder.d.ts +3 -3
  19. package/dist/cjs/anyspend/react/hooks/useSigMint.d.ts +1 -1
  20. package/dist/cjs/anyspend/utils/address.d.ts +2 -1
  21. package/dist/cjs/anyspend/utils/address.js +12 -9
  22. package/dist/cjs/anyspend/utils/chain.d.ts +84 -1
  23. package/dist/cjs/anyspend/utils/chain.js +73 -3
  24. package/dist/cjs/anyspend/utils/token.d.ts +2 -0
  25. package/dist/cjs/anyspend/utils/token.js +15 -1
  26. package/dist/cjs/app.shared.d.ts +9 -1
  27. package/dist/cjs/app.shared.js +19 -0
  28. package/dist/cjs/global-account/app.native.d.ts +1 -1
  29. package/dist/cjs/global-account/better-auth-client.d.ts +3314 -36
  30. package/dist/cjs/global-account/better-auth-client.js +28 -3
  31. package/dist/cjs/global-account/bsmnt.d.ts +2 -2
  32. package/dist/cjs/global-account/bsmnt.native.d.ts +1 -1
  33. package/dist/cjs/global-account/client-manager.d.ts +7 -5
  34. package/dist/cjs/global-account/client-manager.js +51 -4
  35. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +6 -11
  36. package/dist/cjs/global-account/react/components/B3Provider/B3ConfigProvider.d.ts +11 -0
  37. package/dist/cjs/global-account/react/components/B3Provider/B3ConfigProvider.js +12 -0
  38. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.d.ts +12 -2
  39. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +25 -3
  40. package/dist/cjs/global-account/react/components/B3Provider/BetterAuthProvider.js +45 -4
  41. package/dist/cjs/global-account/react/components/B3Provider/RelayKitProviderWrapper.d.ts +1 -2
  42. package/dist/cjs/global-account/react/components/B3Provider/RelayKitProviderWrapper.js +11 -5
  43. package/dist/cjs/global-account/react/components/ManageAccount/ContentTokens.js +23 -15
  44. package/dist/cjs/global-account/react/components/ManageAccount/NFTContent.js +2 -2
  45. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +8 -6
  46. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.js +1 -1
  47. package/dist/cjs/global-account/react/components/ManageAccount/TokenContent.js +17 -8
  48. package/dist/cjs/global-account/react/components/Send/Send.js +15 -11
  49. package/dist/cjs/global-account/react/components/SignInWithB3/BetterAuthSignIn.js +3 -1
  50. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -5
  51. package/dist/cjs/global-account/react/components/SignInWithB3/components/AuthButton.js +2 -1
  52. package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.js +1 -0
  53. package/dist/cjs/global-account/react/components/SignInWithB3/utils/signInUtils.d.ts +3 -2
  54. package/dist/cjs/global-account/react/components/SignInWithB3/utils/signInUtils.js +3 -3
  55. package/dist/cjs/global-account/react/components/index.d.ts +1 -1
  56. package/dist/cjs/global-account/react/components/index.js +3 -3
  57. package/dist/cjs/global-account/react/hooks/index.d.ts +2 -3
  58. package/dist/cjs/global-account/react/hooks/index.js +7 -10
  59. package/dist/cjs/global-account/react/hooks/useAuth.d.ts +5 -4
  60. package/dist/cjs/global-account/react/hooks/useAuth.js +1 -0
  61. package/dist/cjs/global-account/react/hooks/useAuthentication.d.ts +3 -2
  62. package/dist/cjs/global-account/react/hooks/useAuthentication.js +2 -1
  63. package/dist/cjs/global-account/react/hooks/useBetterAuth.d.ts +1657 -22
  64. package/dist/cjs/global-account/react/hooks/useBetterAuth.js +7 -7
  65. package/dist/cjs/global-account/react/hooks/useClient.d.ts +3 -3
  66. package/dist/cjs/global-account/react/hooks/useFirstEOA.d.ts +4 -7666
  67. package/dist/cjs/global-account/react/hooks/useFirstEOA.js +1 -0
  68. package/dist/cjs/global-account/react/hooks/useNativeBalance.js +2 -2
  69. package/dist/cjs/global-account/react/hooks/usePortfolioBalance.d.ts +15 -0
  70. package/dist/cjs/global-account/react/hooks/usePortfolioBalance.js +76 -0
  71. package/dist/cjs/global-account/react/hooks/usePortfolioCollectibles.d.ts +12 -0
  72. package/dist/cjs/global-account/react/hooks/usePortfolioCollectibles.js +178 -0
  73. package/dist/cjs/global-account/react/hooks/useSiwe.d.ts +1 -1
  74. package/dist/cjs/global-account/react/hooks/useSiwe.native.d.ts +1 -1
  75. package/dist/cjs/global-account/react/hooks/useTWAuth.d.ts +1 -1
  76. package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
  77. package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +37 -27
  78. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +14 -2
  79. package/dist/cjs/global-account/types/b3-api.types.d.ts +5 -0
  80. package/dist/cjs/global-account/types/feature-flags.d.ts +5 -5
  81. package/dist/cjs/notifications/services/api.js +1 -0
  82. package/dist/cjs/shared/constants/chains/b3Chain.d.ts +30 -54
  83. package/dist/cjs/shared/constants/chains/b3Chain.js +5 -41
  84. package/dist/cjs/shared/constants/chains/supported.d.ts +1 -49
  85. package/dist/cjs/shared/constants/chains/supported.js +8 -36
  86. package/dist/cjs/shared/constants/index.d.ts +4 -0
  87. package/dist/cjs/shared/utils/chain-transformers.d.ts +4 -4
  88. package/dist/cjs/shared/utils/chain-transformers.js +38 -37
  89. package/dist/cjs/shared/utils/thirdweb-insights.js +2 -2
  90. package/dist/cjs/shared/utils/upload.d.ts +9 -0
  91. package/dist/cjs/shared/utils/upload.js +34 -0
  92. package/dist/cjs/shared/utils/zerionPositions.d.ts +96 -0
  93. package/dist/cjs/shared/utils/zerionPositions.js +188 -0
  94. package/dist/esm/anyspend/constants/rpc.d.ts +3 -1
  95. package/dist/esm/anyspend/constants/rpc.js +5 -1
  96. package/dist/esm/anyspend/react/components/AnySpend.d.ts +9 -1
  97. package/dist/esm/anyspend/react/components/AnySpend.js +124 -47
  98. package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +9 -11
  99. package/dist/esm/anyspend/react/components/AnySpendDeposit.d.ts +15 -3
  100. package/dist/esm/anyspend/react/components/AnySpendDeposit.js +80 -27
  101. package/dist/esm/anyspend/react/components/AnySpendStakeB3.js +33 -14
  102. package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.js +33 -11
  103. package/dist/esm/anyspend/react/components/QRDeposit.d.ts +22 -3
  104. package/dist/esm/anyspend/react/components/QRDeposit.js +27 -18
  105. package/dist/esm/anyspend/react/components/checkout/CryptoPayPanel.js +21 -14
  106. package/dist/esm/anyspend/react/components/common/PureTransferView.d.ts +30 -0
  107. package/dist/esm/anyspend/react/components/common/PureTransferView.js +61 -0
  108. package/dist/esm/anyspend/react/components/common/TokenBalance.js +6 -7
  109. package/dist/esm/anyspend/react/hooks/useCreateDepositFirstOrder.d.ts +3 -3
  110. package/dist/esm/anyspend/react/hooks/useSigMint.d.ts +1 -1
  111. package/dist/esm/anyspend/utils/address.d.ts +2 -1
  112. package/dist/esm/anyspend/utils/address.js +9 -6
  113. package/dist/esm/anyspend/utils/chain.d.ts +84 -1
  114. package/dist/esm/anyspend/utils/chain.js +73 -5
  115. package/dist/esm/anyspend/utils/token.d.ts +2 -0
  116. package/dist/esm/anyspend/utils/token.js +13 -0
  117. package/dist/esm/app.shared.d.ts +9 -1
  118. package/dist/esm/app.shared.js +17 -0
  119. package/dist/esm/global-account/app.native.d.ts +1 -1
  120. package/dist/esm/global-account/better-auth-client.d.ts +3314 -36
  121. package/dist/esm/global-account/better-auth-client.js +27 -4
  122. package/dist/esm/global-account/bsmnt.d.ts +2 -2
  123. package/dist/esm/global-account/bsmnt.native.d.ts +1 -1
  124. package/dist/esm/global-account/client-manager.d.ts +7 -5
  125. package/dist/esm/global-account/client-manager.js +51 -5
  126. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +6 -11
  127. package/dist/esm/global-account/react/components/B3Provider/B3ConfigProvider.d.ts +11 -0
  128. package/dist/esm/global-account/react/components/B3Provider/B3ConfigProvider.js +11 -0
  129. package/dist/esm/global-account/react/components/B3Provider/B3Provider.d.ts +12 -2
  130. package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +26 -4
  131. package/dist/esm/global-account/react/components/B3Provider/BetterAuthProvider.js +46 -5
  132. package/dist/esm/global-account/react/components/B3Provider/RelayKitProviderWrapper.d.ts +1 -2
  133. package/dist/esm/global-account/react/components/B3Provider/RelayKitProviderWrapper.js +11 -5
  134. package/dist/esm/global-account/react/components/ManageAccount/ContentTokens.js +24 -16
  135. package/dist/esm/global-account/react/components/ManageAccount/NFTContent.js +3 -3
  136. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +9 -7
  137. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.js +1 -1
  138. package/dist/esm/global-account/react/components/ManageAccount/TokenContent.js +18 -9
  139. package/dist/esm/global-account/react/components/Send/Send.js +16 -12
  140. package/dist/esm/global-account/react/components/SignInWithB3/BetterAuthSignIn.js +3 -1
  141. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -5
  142. package/dist/esm/global-account/react/components/SignInWithB3/components/AuthButton.js +2 -1
  143. package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.js +1 -0
  144. package/dist/esm/global-account/react/components/SignInWithB3/utils/signInUtils.d.ts +3 -2
  145. package/dist/esm/global-account/react/components/SignInWithB3/utils/signInUtils.js +3 -3
  146. package/dist/esm/global-account/react/components/index.d.ts +1 -1
  147. package/dist/esm/global-account/react/components/index.js +1 -1
  148. package/dist/esm/global-account/react/hooks/index.d.ts +2 -3
  149. package/dist/esm/global-account/react/hooks/index.js +2 -3
  150. package/dist/esm/global-account/react/hooks/useAuth.d.ts +5 -4
  151. package/dist/esm/global-account/react/hooks/useAuth.js +1 -0
  152. package/dist/esm/global-account/react/hooks/useAuthentication.d.ts +3 -2
  153. package/dist/esm/global-account/react/hooks/useAuthentication.js +2 -1
  154. package/dist/esm/global-account/react/hooks/useBetterAuth.d.ts +1657 -22
  155. package/dist/esm/global-account/react/hooks/useBetterAuth.js +8 -8
  156. package/dist/esm/global-account/react/hooks/useClient.d.ts +3 -3
  157. package/dist/esm/global-account/react/hooks/useFirstEOA.d.ts +4 -7666
  158. package/dist/esm/global-account/react/hooks/useFirstEOA.js +1 -0
  159. package/dist/esm/global-account/react/hooks/useNativeBalance.js +1 -1
  160. package/dist/esm/global-account/react/hooks/usePortfolioBalance.d.ts +15 -0
  161. package/dist/esm/global-account/react/hooks/usePortfolioBalance.js +72 -0
  162. package/dist/esm/global-account/react/hooks/usePortfolioCollectibles.d.ts +12 -0
  163. package/dist/esm/global-account/react/hooks/usePortfolioCollectibles.js +175 -0
  164. package/dist/esm/global-account/react/hooks/useSiwe.d.ts +1 -1
  165. package/dist/esm/global-account/react/hooks/useSiwe.native.d.ts +1 -1
  166. package/dist/esm/global-account/react/hooks/useTWAuth.d.ts +1 -1
  167. package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
  168. package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +37 -27
  169. package/dist/esm/global-account/react/stores/useModalStore.d.ts +14 -2
  170. package/dist/esm/global-account/types/b3-api.types.d.ts +5 -0
  171. package/dist/esm/global-account/types/feature-flags.d.ts +5 -5
  172. package/dist/esm/notifications/services/api.js +1 -0
  173. package/dist/esm/shared/constants/chains/b3Chain.d.ts +30 -54
  174. package/dist/esm/shared/constants/chains/b3Chain.js +4 -38
  175. package/dist/esm/shared/constants/chains/supported.d.ts +1 -49
  176. package/dist/esm/shared/constants/chains/supported.js +7 -35
  177. package/dist/esm/shared/constants/index.d.ts +4 -0
  178. package/dist/esm/shared/utils/chain-transformers.d.ts +4 -4
  179. package/dist/esm/shared/utils/chain-transformers.js +38 -37
  180. package/dist/esm/shared/utils/thirdweb-insights.js +2 -2
  181. package/dist/esm/shared/utils/upload.d.ts +9 -0
  182. package/dist/esm/shared/utils/upload.js +31 -0
  183. package/dist/esm/shared/utils/zerionPositions.d.ts +96 -0
  184. package/dist/esm/shared/utils/zerionPositions.js +180 -0
  185. package/dist/styles/index.css +1 -1
  186. package/dist/types/anyspend/constants/rpc.d.ts +3 -1
  187. package/dist/types/anyspend/react/components/AnySpend.d.ts +9 -1
  188. package/dist/types/anyspend/react/components/AnySpendDeposit.d.ts +15 -3
  189. package/dist/types/anyspend/react/components/QRDeposit.d.ts +22 -3
  190. package/dist/types/anyspend/react/components/common/PureTransferView.d.ts +30 -0
  191. package/dist/types/anyspend/react/hooks/useCreateDepositFirstOrder.d.ts +3 -3
  192. package/dist/types/anyspend/react/hooks/useSigMint.d.ts +1 -1
  193. package/dist/types/anyspend/utils/address.d.ts +2 -1
  194. package/dist/types/anyspend/utils/chain.d.ts +84 -1
  195. package/dist/types/anyspend/utils/token.d.ts +2 -0
  196. package/dist/types/app.shared.d.ts +9 -1
  197. package/dist/types/global-account/app.native.d.ts +1 -1
  198. package/dist/types/global-account/better-auth-client.d.ts +3314 -36
  199. package/dist/types/global-account/bsmnt.d.ts +2 -2
  200. package/dist/types/global-account/bsmnt.native.d.ts +1 -1
  201. package/dist/types/global-account/client-manager.d.ts +7 -5
  202. package/dist/types/global-account/react/components/B3Provider/B3ConfigProvider.d.ts +11 -0
  203. package/dist/types/global-account/react/components/B3Provider/B3Provider.d.ts +12 -2
  204. package/dist/types/global-account/react/components/B3Provider/RelayKitProviderWrapper.d.ts +1 -2
  205. package/dist/types/global-account/react/components/SignInWithB3/utils/signInUtils.d.ts +3 -2
  206. package/dist/types/global-account/react/components/index.d.ts +1 -1
  207. package/dist/types/global-account/react/hooks/index.d.ts +2 -3
  208. package/dist/types/global-account/react/hooks/useAuth.d.ts +5 -4
  209. package/dist/types/global-account/react/hooks/useAuthentication.d.ts +3 -2
  210. package/dist/types/global-account/react/hooks/useBetterAuth.d.ts +1657 -22
  211. package/dist/types/global-account/react/hooks/useClient.d.ts +3 -3
  212. package/dist/types/global-account/react/hooks/useFirstEOA.d.ts +4 -7666
  213. package/dist/types/global-account/react/hooks/usePortfolioBalance.d.ts +15 -0
  214. package/dist/types/global-account/react/hooks/usePortfolioCollectibles.d.ts +12 -0
  215. package/dist/types/global-account/react/hooks/useSiwe.d.ts +1 -1
  216. package/dist/types/global-account/react/hooks/useSiwe.native.d.ts +1 -1
  217. package/dist/types/global-account/react/hooks/useTWAuth.d.ts +1 -1
  218. package/dist/types/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
  219. package/dist/types/global-account/react/stores/useModalStore.d.ts +14 -2
  220. package/dist/types/global-account/types/b3-api.types.d.ts +5 -0
  221. package/dist/types/global-account/types/feature-flags.d.ts +5 -5
  222. package/dist/types/shared/constants/chains/b3Chain.d.ts +30 -54
  223. package/dist/types/shared/constants/chains/supported.d.ts +1 -49
  224. package/dist/types/shared/constants/index.d.ts +4 -0
  225. package/dist/types/shared/utils/chain-transformers.d.ts +4 -4
  226. package/dist/types/shared/utils/upload.d.ts +9 -0
  227. package/dist/types/shared/utils/zerionPositions.d.ts +96 -0
  228. package/node_modules/@b3/chain-registry/chains.json +1225 -0
  229. package/node_modules/@b3/chain-registry/dist/chains.json +1225 -0
  230. package/node_modules/@b3/chain-registry/dist/index.cjs +1676 -0
  231. package/node_modules/@b3/chain-registry/dist/index.d.cts +195 -0
  232. package/node_modules/@b3/chain-registry/dist/index.d.ts +195 -0
  233. package/node_modules/@b3/chain-registry/dist/index.mjs +1604 -0
  234. package/node_modules/@b3/chain-registry/dist/src/index.d.ts +193 -0
  235. package/node_modules/@b3/chain-registry/dist/src/index.js +408 -0
  236. package/node_modules/@b3/chain-registry/package.json +66 -0
  237. package/node_modules/@b3/chain-registry/src/index.test.ts +432 -0
  238. package/node_modules/@b3/chain-registry/src/index.ts +672 -0
  239. package/package.json +81 -30
  240. package/src/anyspend/README.md +2 -2
  241. package/src/anyspend/constants/rpc.ts +5 -2
  242. package/src/anyspend/docs/components.md +6 -6
  243. package/src/anyspend/docs/contributing.md +1 -1
  244. package/src/anyspend/docs/hooks.md +3 -3
  245. package/src/anyspend/docs/installation.md +2 -2
  246. package/src/anyspend/react/components/AnySpend.tsx +163 -47
  247. package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +10 -11
  248. package/src/anyspend/react/components/AnySpendDeposit.tsx +130 -31
  249. package/src/anyspend/react/components/AnySpendStakeB3.tsx +55 -14
  250. package/src/anyspend/react/components/AnySpendStakeB3ExactIn.tsx +55 -11
  251. package/src/anyspend/react/components/QRDeposit.tsx +101 -22
  252. package/src/anyspend/react/components/__tests__/QRDeposit.test.tsx +331 -0
  253. package/src/anyspend/react/components/checkout/CryptoPayPanel.tsx +38 -16
  254. package/src/anyspend/react/components/common/PureTransferView.tsx +212 -0
  255. package/src/anyspend/react/components/common/TokenBalance.tsx +10 -7
  256. package/src/anyspend/react/hooks/useAnyspendQuote.ts +13 -13
  257. package/src/anyspend/react/hooks/useCreateDepositFirstOrder.ts +4 -4
  258. package/src/anyspend/services/gas.test.ts +95 -18
  259. package/src/anyspend/types/api_req_res.ts +10 -5
  260. package/src/anyspend/utils/__tests__/address.test.ts +39 -0
  261. package/src/anyspend/utils/__tests__/deprecatedChains.test.ts +44 -0
  262. package/src/anyspend/utils/__tests__/toRegistryChainId.test.ts +17 -0
  263. package/src/anyspend/utils/address.ts +8 -6
  264. package/src/anyspend/utils/chain.ts +79 -3
  265. package/src/anyspend/utils/token.ts +14 -0
  266. package/src/app.shared.ts +21 -1
  267. package/src/global-account/app.native.ts +5 -1
  268. package/src/global-account/better-auth-client.ts +30 -4
  269. package/src/global-account/bsmnt.native.ts +5 -1
  270. package/src/global-account/bsmnt.ts +9 -2
  271. package/src/global-account/client-manager.ts +74 -9
  272. package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +6 -11
  273. package/src/global-account/react/components/B3Provider/B3ConfigProvider.tsx +12 -0
  274. package/src/global-account/react/components/B3Provider/B3Provider.tsx +40 -4
  275. package/src/global-account/react/components/B3Provider/BetterAuthProvider.tsx +51 -5
  276. package/src/global-account/react/components/B3Provider/RelayKitProviderWrapper.tsx +11 -11
  277. package/src/global-account/react/components/ManageAccount/ContentTokens.tsx +50 -21
  278. package/src/global-account/react/components/ManageAccount/NFTContent.tsx +5 -3
  279. package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +10 -6
  280. package/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +1 -1
  281. package/src/global-account/react/components/ManageAccount/TokenContent.tsx +22 -9
  282. package/src/global-account/react/components/Send/Send.tsx +39 -15
  283. package/src/global-account/react/components/SignInWithB3/BetterAuthSignIn.tsx +12 -1
  284. package/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx +1 -4
  285. package/src/global-account/react/components/SignInWithB3/components/AuthButton.tsx +9 -1
  286. package/src/global-account/react/components/SignInWithB3/steps/LoginStepBetterAuth.tsx +1 -0
  287. package/src/global-account/react/components/SignInWithB3/utils/signInUtils.ts +4 -4
  288. package/src/global-account/react/components/index.ts +1 -1
  289. package/src/global-account/react/components/ui/button.tsx +1 -2
  290. package/src/global-account/react/hooks/__tests__/useUnifiedChainSwitchAndExecute.test.tsx +156 -0
  291. package/src/global-account/react/hooks/index.ts +2 -3
  292. package/src/global-account/react/hooks/useAuth.ts +5 -4
  293. package/src/global-account/react/hooks/useAuthentication.ts +5 -4
  294. package/src/global-account/react/hooks/useBetterAuth.ts +10 -10
  295. package/src/global-account/react/hooks/useClient.ts +11 -2
  296. package/src/global-account/react/hooks/useFirstEOA.tsx +9 -2
  297. package/src/global-account/react/hooks/useNativeBalance.tsx +1 -1
  298. package/src/global-account/react/hooks/usePortfolioBalance.ts +89 -0
  299. package/src/global-account/react/hooks/usePortfolioCollectibles.ts +212 -0
  300. package/src/global-account/react/hooks/useSiwe.native.tsx +1 -1
  301. package/src/global-account/react/hooks/useSiwe.tsx +1 -1
  302. package/src/global-account/react/hooks/useTWAuth.tsx +1 -1
  303. package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +47 -31
  304. package/src/global-account/react/stores/useModalStore.ts +14 -2
  305. package/src/global-account/types/b3-api.types.ts +5 -1
  306. package/src/notifications/services/api.ts +1 -0
  307. package/src/shared/constants/chains/b3Chain.ts +4 -43
  308. package/src/shared/constants/chains/supported.ts +9 -48
  309. package/src/shared/constants/index.ts +8 -0
  310. package/src/shared/react/hooks/__tests__/useCurrencyConversion.test.ts +54 -43
  311. package/src/shared/utils/__tests__/zerionPositions.test.ts +248 -0
  312. package/src/shared/utils/chain-transformers.ts +41 -39
  313. package/src/shared/utils/thirdweb-insights.ts +2 -2
  314. package/src/shared/utils/upload.ts +48 -0
  315. package/src/shared/utils/zerionPositions.ts +247 -0
  316. package/src/styles/index.css +27 -0
  317. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Privy.d.ts +0 -10
  318. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Privy.js +0 -46
  319. package/dist/cjs/global-account/react/hooks/useHandleConnectWithPrivy.d.ts +0 -11
  320. package/dist/cjs/global-account/react/hooks/useHandleConnectWithPrivy.js +0 -70
  321. package/dist/cjs/global-account/react/hooks/useSimBalance.d.ts +0 -59
  322. package/dist/cjs/global-account/react/hooks/useSimBalance.js +0 -98
  323. package/dist/cjs/global-account/react/hooks/useSimCollectibles.d.ts +0 -45
  324. package/dist/cjs/global-account/react/hooks/useSimCollectibles.js +0 -190
  325. package/dist/cjs/global-account/react/utils/simdune.d.ts +0 -7
  326. package/dist/cjs/global-account/react/utils/simdune.js +0 -21
  327. package/dist/cjs/global-account/types/chain-networks.d.ts +0 -44
  328. package/dist/cjs/global-account/types/chain-networks.js +0 -48
  329. package/dist/cjs/shared/generated/chain-networks.json +0 -684
  330. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Privy.d.ts +0 -10
  331. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Privy.js +0 -43
  332. package/dist/esm/global-account/react/hooks/useHandleConnectWithPrivy.d.ts +0 -11
  333. package/dist/esm/global-account/react/hooks/useHandleConnectWithPrivy.js +0 -67
  334. package/dist/esm/global-account/react/hooks/useSimBalance.d.ts +0 -59
  335. package/dist/esm/global-account/react/hooks/useSimBalance.js +0 -93
  336. package/dist/esm/global-account/react/hooks/useSimCollectibles.d.ts +0 -45
  337. package/dist/esm/global-account/react/hooks/useSimCollectibles.js +0 -187
  338. package/dist/esm/global-account/react/utils/simdune.d.ts +0 -7
  339. package/dist/esm/global-account/react/utils/simdune.js +0 -17
  340. package/dist/esm/global-account/types/chain-networks.d.ts +0 -44
  341. package/dist/esm/global-account/types/chain-networks.js +0 -45
  342. package/dist/esm/shared/generated/chain-networks.json +0 -684
  343. package/dist/types/global-account/react/components/SignInWithB3/SignInWithB3Privy.d.ts +0 -10
  344. package/dist/types/global-account/react/hooks/useHandleConnectWithPrivy.d.ts +0 -11
  345. package/dist/types/global-account/react/hooks/useSimBalance.d.ts +0 -59
  346. package/dist/types/global-account/react/hooks/useSimCollectibles.d.ts +0 -45
  347. package/dist/types/global-account/react/utils/simdune.d.ts +0 -7
  348. package/dist/types/global-account/types/chain-networks.d.ts +0 -44
  349. package/src/global-account/react/components/SignInWithB3/SignInWithB3Privy.tsx +0 -63
  350. package/src/global-account/react/hooks/useHandleConnectWithPrivy.tsx +0 -79
  351. package/src/global-account/react/hooks/useSimBalance.ts +0 -164
  352. package/src/global-account/react/hooks/useSimCollectibles.ts +0 -238
  353. package/src/global-account/react/utils/simdune.ts +0 -20
  354. package/src/global-account/types/chain-networks.ts +0 -54
  355. package/src/shared/generated/chain-networks.json +0 -684
@@ -1,7 +1,9 @@
1
+ import { USDC_BASE } from "@b3dotfun/sdk/anyspend";
1
2
  import { components } from "@b3dotfun/sdk/anyspend/types/api";
2
3
  import { GetQuoteResponse } from "@b3dotfun/sdk/anyspend/types/api_req_res";
3
- import { Skeleton, useAccountWallet, useSimBalance, useTokenData } from "@b3dotfun/sdk/global-account/react";
4
+ import { Skeleton, useAccountWallet, usePortfolioBalance, useTokenData } from "@b3dotfun/sdk/global-account/react";
4
5
  import { cn } from "@b3dotfun/sdk/shared/utils/cn";
6
+ import { formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
5
7
  import {
6
8
  NetworkArbitrumOne,
7
9
  NetworkBase,
@@ -11,7 +13,7 @@ import {
11
13
  NetworkPolygonPos,
12
14
  } from "@web3icons/react";
13
15
  import { ChevronRight } from "lucide-react";
14
- import { useEffect, useMemo, useState } from "react";
16
+ import { useCallback, useEffect, useMemo, useState } from "react";
15
17
  import { AnySpend } from "./AnySpend";
16
18
  import { AnySpendCustomExactIn } from "./AnySpendCustomExactIn";
17
19
  import { ChainWarningText } from "./common/WarningText";
@@ -62,6 +64,13 @@ export interface AnySpendDepositProps {
62
64
  destinationTokenAddress: string;
63
65
  /** The destination chain ID */
64
66
  destinationTokenChainId: number;
67
+ /**
68
+ * When false, the destination token is user-selectable even though a default destination token is
69
+ * provided (the provided destination is used only as the initial/default value). Used by the
70
+ * wallet-funding deposit flow so the user can change the receive token away from the default
71
+ * (Base USDC). Defaults to true (locked destination, current behavior). Does not affect the
72
+ * QR/pure-transfer path. */
73
+ lockDestinationToken?: boolean;
65
74
  /** Callback when deposit succeeds */
66
75
  onSuccess?: (amount: string) => void;
67
76
  /** Callback for opening a custom modal (e.g., for special token handling) */
@@ -99,8 +108,6 @@ export interface AnySpendDepositProps {
99
108
  showFiatOption?: boolean;
100
109
  /** Custom list of supported chains. If not provided, uses default chains */
101
110
  supportedChains?: ChainConfig[];
102
- /** Minimum pool size for filtering tokens (default: 1,000,000) */
103
- minPoolSize?: number;
104
111
  /** Custom title for chain selection step */
105
112
  chainSelectionTitle?: string;
106
113
  /** Custom description for chain selection step */
@@ -124,6 +131,13 @@ export interface AnySpendDepositProps {
124
131
  classes?: AnySpendAllClasses;
125
132
  /** When true, allows direct transfer without swap if source and destination token/chain are the same */
126
133
  allowDirectTransfer?: boolean;
134
+ /**
135
+ * When true, the QR-deposit path is a PURE TRANSFER: the destination token/chain
136
+ * mirror whatever source token the user selects, so the exact token they send lands
137
+ * in their wallet on the same chain (no swap/bridge). Forwarded to QRDeposit.
138
+ * Defaults to false.
139
+ */
140
+ pureTransferOnly?: boolean;
127
141
  /** Fixed destination token amount (in wei/smallest unit). When provided, user cannot change the amount. */
128
142
  destinationTokenAmount?: string;
129
143
  /** Opaque metadata passed to the order for callbacks (e.g., workflow form data) */
@@ -148,8 +162,20 @@ const DEFAULT_SUPPORTED_CHAINS: ChainConfig[] = [
148
162
  { id: 56, name: "BNB Chain" },
149
163
  ];
150
164
 
151
- // Minimum pool size to filter out low liquidity tokens
152
- const DEFAULT_MIN_POOL_SIZE = 1_000_000;
165
+ /**
166
+ * Self-described fallback metadata for the default funding token(s), keyed by
167
+ * `${chainId}:${lowercased address}`. Used when `useTokenData` misses (returns
168
+ * null) so the destination token's decimals/symbol are correct WITHOUT depending
169
+ * on the network — critical in pure-transfer mode where there's no server-side
170
+ * correction and the wrong decimals would make `useWatchTransfer` show a wrong amount.
171
+ */
172
+ const KNOWN_FUNDING_TOKENS: Record<string, components["schemas"]["Token"]> = {
173
+ [`${USDC_BASE.chainId}:${USDC_BASE.address.toLowerCase()}`]: USDC_BASE,
174
+ };
175
+
176
+ function getKnownFundingToken(chainId: number, address: string): components["schemas"]["Token"] | undefined {
177
+ return KNOWN_FUNDING_TOKENS[`${chainId}:${address.toLowerCase()}`];
178
+ }
153
179
 
154
180
  type DepositStep = "select-chain" | "deposit" | "qr-deposit";
155
181
 
@@ -239,6 +265,7 @@ export function AnySpendDeposit({
239
265
  sourceTokenChainId: initialSourceChainId,
240
266
  destinationTokenAddress,
241
267
  destinationTokenChainId,
268
+ lockDestinationToken = true,
242
269
  onSuccess,
243
270
  onOpenCustomModal,
244
271
  mainFooter,
@@ -252,7 +279,6 @@ export function AnySpendDeposit({
252
279
  showChainSelection,
253
280
  showFiatOption = true,
254
281
  supportedChains = DEFAULT_SUPPORTED_CHAINS,
255
- minPoolSize = DEFAULT_MIN_POOL_SIZE,
256
282
  topChainsCount = 3,
257
283
  onClose,
258
284
  returnToHomeUrl,
@@ -261,6 +287,7 @@ export function AnySpendDeposit({
261
287
  isCustomDeposit = false,
262
288
  classes,
263
289
  allowDirectTransfer = false,
290
+ pureTransferOnly = false,
264
291
  destinationTokenAmount,
265
292
  callbackMetadata,
266
293
  senderAddress,
@@ -289,37 +316,48 @@ export function AnySpendDeposit({
289
316
  }, [showFiatOption, paymentType]);
290
317
 
291
318
  // Fetch destination token data
292
- const { data: destinationTokenData } = useTokenData(destinationTokenChainId, destinationTokenAddress);
319
+ const { data: destinationTokenData, isLoading: isDestinationTokenLoading } = useTokenData(
320
+ destinationTokenChainId,
321
+ destinationTokenAddress,
322
+ );
293
323
 
294
- // Construct full destination token object
295
- const destinationToken: components["schemas"]["Token"] = useMemo(
296
- () => ({
324
+ // Construct full destination token object. When `useTokenData` misses (it returns
325
+ // null on an API miss, not an error), fall back to a known-token entry so the
326
+ // decimals/symbol invariant holds regardless of the fetch — e.g. Base USDC is 6
327
+ // decimals, never the generic 18 fallback.
328
+ const destinationToken: components["schemas"]["Token"] = useMemo(() => {
329
+ const known = getKnownFundingToken(destinationTokenChainId, destinationTokenAddress);
330
+ return {
297
331
  address: destinationTokenAddress,
298
332
  chainId: destinationTokenChainId,
299
- symbol: destinationTokenData?.symbol ?? "",
300
- name: destinationTokenData?.name ?? "",
301
- decimals: destinationTokenData?.decimals ?? 18,
302
- metadata: { logoURI: destinationTokenData?.logoURI },
303
- }),
304
- [destinationTokenAddress, destinationTokenChainId, destinationTokenData],
305
- );
333
+ symbol: destinationTokenData?.symbol ?? known?.symbol ?? "",
334
+ name: destinationTokenData?.name ?? known?.name ?? "",
335
+ decimals: destinationTokenData?.decimals ?? known?.decimals ?? 18,
336
+ metadata: { logoURI: destinationTokenData?.logoURI ?? known?.metadata?.logoURI },
337
+ };
338
+ }, [destinationTokenAddress, destinationTokenChainId, destinationTokenData]);
306
339
 
307
340
  // Fetch balances for EOA wallet (use senderAddress as fallback for pre-filled balance display)
308
341
  const effectiveBalanceAddress = senderAddress || eoaAddress;
309
- const { data: balanceData, isLoading: isBalanceLoading } = useSimBalance(
342
+ const {
343
+ data: balances,
344
+ isLoading: isBalanceLoading,
345
+ isError: isBalanceError,
346
+ } = usePortfolioBalance(
310
347
  shouldShowChainSelection ? effectiveBalanceAddress : undefined,
311
348
  supportedChains.map(c => c.id),
312
349
  );
313
350
 
314
- // Group balances by chain and calculate total USD value per chain
351
+ // Group balances by chain and calculate total USD value per chain.
352
+ //
353
+ // There is deliberately no liquidity threshold here. The balance provider reports no pool size,
354
+ // so a `pool_size > n` test is false for every row and quietly reduces to "native only",
355
+ // erasing every ERC-20 the user holds from the chain summary. Spam filtering belongs to the
356
+ // token-filter service, which has the data to do it.
315
357
  const chainBalances = useMemo(() => {
316
- if (!balanceData?.balances) return {};
358
+ if (!balances) return {};
317
359
 
318
- const filteredBalances = balanceData.balances.filter(
319
- token => token.address === "native" || (token.pool_size && token.pool_size > minPoolSize),
320
- );
321
-
322
- return filteredBalances.reduce(
360
+ return balances.reduce(
323
361
  (acc, token) => {
324
362
  const chainId = token.chain_id;
325
363
  if (!acc[chainId]) {
@@ -336,7 +374,7 @@ export function AnySpendDeposit({
336
374
  },
337
375
  {} as Record<number, { chainId: number; chainName: string; totalUsdValue: number; tokenCount: number }>,
338
376
  );
339
- }, [balanceData, minPoolSize]);
377
+ }, [balances]);
340
378
 
341
379
  // Sort chains by USD value (highest first)
342
380
  const sortedChains = useMemo(() => {
@@ -359,6 +397,13 @@ export function AnySpendDeposit({
359
397
  return Object.values(chainBalances).reduce((sum, chain) => sum + chain.totalUsdValue, 0);
360
398
  }, [chainBalances]);
361
399
 
400
+ const handleQRDepositSuccess = useCallback(
401
+ (txHash?: string) => {
402
+ onSuccess?.(txHash ?? "");
403
+ },
404
+ [onSuccess],
405
+ );
406
+
362
407
  if (!recipientAddress) return null;
363
408
 
364
409
  const tokenSymbol = destinationToken.symbol || "TOKEN";
@@ -431,7 +476,7 @@ export function AnySpendDeposit({
431
476
  </button>
432
477
  )}
433
478
  {/* Balance header */}
434
- {!isBalanceLoading && totalBalance > 0 && (
479
+ {!isBalanceLoading && !isBalanceError && totalBalance > 0 && (
435
480
  <div
436
481
  className={
437
482
  depositClasses?.balanceContainer || "anyspend-deposit-balance border-theme-border-secondary border-b p-5"
@@ -474,8 +519,16 @@ export function AnySpendDeposit({
474
519
  </div>
475
520
  )}
476
521
 
522
+ {/* A failed read leaves every chain at zero, which reads as "you hold nothing" on a
523
+ funding screen. Say what actually happened instead. */}
524
+ {isBalanceError && !isBalanceLoading && (
525
+ <p className="text-as-primary/50 px-1 py-2 text-sm">
526
+ We couldn&apos;t read your balances just now. You can still pick a chain below.
527
+ </p>
528
+ )}
529
+
477
530
  {/* Top chains with balance */}
478
- {topChainsWithBalance.length > 0 && (
531
+ {!isBalanceError && topChainsWithBalance.length > 0 && (
479
532
  <div className={depositClasses?.chainsContainer || "anyspend-deposit-chains flex flex-col gap-2"}>
480
533
  {topChainsWithBalance.map(chain => (
481
534
  <button
@@ -502,7 +555,7 @@ export function AnySpendDeposit({
502
555
  depositClasses?.chainBalance || "anyspend-deposit-chain-balance text-as-secondary text-xs"
503
556
  }
504
557
  >
505
- {formatUsd(chain.balance)} available
558
+ {`${formatUsd(chain.balance)} available`}
506
559
  </p>
507
560
  </div>
508
561
  </div>
@@ -586,7 +639,9 @@ export function AnySpendDeposit({
586
639
  "anyspend-deposit-option-description text-as-secondary text-xs"
587
640
  }
588
641
  >
589
- Send tokens directly to deposit address
642
+ {pureTransferOnly
643
+ ? "Send tokens directly to deposit address"
644
+ : "Send any token — we'll convert it for you"}
590
645
  </p>
591
646
  </div>
592
647
  </div>
@@ -644,15 +699,58 @@ export function AnySpendDeposit({
644
699
 
645
700
  // QR Deposit view
646
701
  if (step === "qr-deposit") {
702
+ // In pure-transfer mode QRDeposit captures `destinationToken` as its initial
703
+ // SOURCE token via useState, so it must be fully resolved (correct symbol +
704
+ // decimals) before QRDeposit mounts. Known funding tokens (e.g. Base USDC) are
705
+ // already fully resolved via the self-described fallback, so only show a spinner
706
+ // for unknown tokens whose metadata still has to load over the network.
707
+ const hasKnownDestination = !!getKnownFundingToken(destinationTokenChainId, destinationTokenAddress);
708
+ // NOTE: all current Fund Wallet callers derive `destinationTokenAddress` from
709
+ // `getDefaultDepositDestination`, which always returns Base USDC — exactly a
710
+ // `KNOWN_FUNDING_TOKENS` key — so `hasKnownDestination` is always true and this
711
+ // branch never fires for them. The guard is defensive for FUTURE callers that pass
712
+ // an unknown token together with `pureTransferOnly=true`.
713
+ // Only surface the fixed destination amount on the QR path when its decimals are trustworthy
714
+ // (a known funding token or a resolved API lookup) — otherwise `destinationToken.decimals`
715
+ // is the generic 18 fallback and formatting a 6-decimal token's wei against it would be off by
716
+ // 10^12. When unresolved we still show the destination token/chain, just without an amount.
717
+ const destinationDecimalsResolved = hasKnownDestination || !!destinationTokenData;
718
+ const destinationAmountDisplay =
719
+ destinationTokenAmount &&
720
+ /^\d+$/.test(destinationTokenAmount) &&
721
+ BigInt(destinationTokenAmount) > 0n &&
722
+ destinationDecimalsResolved
723
+ ? formatTokenAmount(BigInt(destinationTokenAmount), destinationToken.decimals, 6, false)
724
+ : undefined;
725
+
726
+ if (pureTransferOnly && !hasKnownDestination && !destinationTokenData && isDestinationTokenLoading) {
727
+ return (
728
+ <div
729
+ className={cn(
730
+ "anyspend-deposit anyspend-deposit-qr-loading font-inter bg-as-surface-primary mx-auto w-full max-w-[460px] p-6",
731
+ mode === "page" && "border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl",
732
+ )}
733
+ >
734
+ <div className="anyspend-deposit-qr-loading-content flex flex-col items-center justify-center gap-4 py-12">
735
+ <Skeleton className="h-8 w-8 rounded-full" />
736
+ <Skeleton className="h-4 w-40" />
737
+ </div>
738
+ </div>
739
+ );
740
+ }
741
+
647
742
  return (
648
743
  <QRDeposit
649
744
  mode={mode}
650
745
  recipientAddress={recipientAddress}
651
746
  destinationToken={destinationToken}
652
747
  destinationChainId={destinationTokenChainId}
748
+ destinationAmountDisplay={destinationAmountDisplay}
749
+ pureTransferOnly={pureTransferOnly}
653
750
  depositContractConfig={depositContractConfig}
654
751
  onBack={handleBack}
655
752
  onClose={onClose ?? handleBack}
753
+ onSuccess={handleQRDepositSuccess}
656
754
  classes={classes?.qrDeposit}
657
755
  />
658
756
  );
@@ -746,6 +844,7 @@ export function AnySpendDeposit({
746
844
  sourceChainId={selectedChainId}
747
845
  destinationTokenAddress={destinationTokenAddress}
748
846
  destinationTokenChainId={destinationTokenChainId}
847
+ lockDestinationToken={lockDestinationToken}
749
848
  onSuccess={txHash => onSuccess?.(txHash ?? "")}
750
849
  onTokenSelect={onTokenSelect}
751
850
  customUsdInputValues={customUsdInputValues}
@@ -8,7 +8,7 @@ import {
8
8
  toast,
9
9
  useHasMounted,
10
10
  useModalStore,
11
- useSimBalance,
11
+ usePortfolioBalance,
12
12
  useUnifiedChainSwitchAndExecute,
13
13
  } from "@b3dotfun/sdk/global-account/react";
14
14
  import { PUBLIC_BASE_RPC_URL } from "@b3dotfun/sdk/shared/constants";
@@ -75,12 +75,32 @@ export function AnySpendStakeB3({
75
75
  const { address } = useAccount();
76
76
  const { switchChainAndExecute, isSwitchingOrExecuting } = useUnifiedChainSwitchAndExecute();
77
77
 
78
- // Fetch B3 token balance
79
- const { data: simBalance, isLoading: isBalanceLoading } = useSimBalance(address, [base.id]);
80
- const b3RawBalanceStr = simBalance?.balances.find(b => eqci(b.address, B3_TOKEN.address))?.amount || "0";
78
+ // Fetch B3 token balance. `isBalanceUnknown` must gate every use of `b3RawBalance`: a failed read
79
+ // yields the same 0 as an empty wallet, and acting on it pushes a holder into the swap flow to
80
+ // buy a token they already have.
81
+ const {
82
+ data: balances,
83
+ isLoading: isBalanceLoading,
84
+ isError: isBalanceError,
85
+ refetch: refetchBalance,
86
+ } = usePortfolioBalance(address, [base.id]);
87
+ // Guarded on `address`: with no wallet connected the query never runs, and a query that was
88
+ // never asked is not a query that failed. Without this the screen tells a visitor their
89
+ // balance is unavailable and refuses to continue, when they simply have not connected yet.
90
+ const isBalanceUnknown = Boolean(address) && (isBalanceError || (!isBalanceLoading && balances === undefined));
91
+ const b3RawBalanceStr = balances?.find(b => eqci(b.address, B3_TOKEN.address))?.amount || "0";
81
92
  const b3RawBalance = BigInt(b3RawBalanceStr);
82
93
  const b3Balance = formatTokenAmount(b3RawBalance, B3_TOKEN.decimals);
83
94
 
95
+ /**
96
+ * Whether the wallet demonstrably holds enough B3 to stake `amountRaw` directly.
97
+ *
98
+ * False while the balance is unknown — but callers must not read that as a shortfall. An unknown
99
+ * balance is neither enough nor short, and the two need different UI: a shortfall offers the swap
100
+ * flow, an unknown offers a retry. Check `isBalanceUnknown` first.
101
+ */
102
+ const hasEnoughB3 = (amountRaw: string) => !isBalanceUnknown && BigInt(amountRaw || "0") <= b3RawBalance;
103
+
84
104
  // State for direct staking flow
85
105
  const [isStaking, setIsStaking] = useState(false);
86
106
  const [stakingTxHash, setStakingTxHash] = useState<string>("");
@@ -273,10 +293,12 @@ export function AnySpendStakeB3({
273
293
  return;
274
294
  }
275
295
 
276
- // Check if user has sufficient B3 balance for direct staking
277
- const hasEnoughBalance = b3RawBalance && BigInt(userStakeAmount) <= b3RawBalance;
296
+ if (isBalanceUnknown) {
297
+ toast.error("Can't read your B3 balance right now. Please try again.");
298
+ return;
299
+ }
278
300
 
279
- if (hasEnoughBalance) {
301
+ if (hasEnoughB3(userStakeAmount)) {
280
302
  // User has enough B3, proceed with direct staking
281
303
  handleDirectStaking();
282
304
  } else {
@@ -334,10 +356,9 @@ export function AnySpendStakeB3({
334
356
  transition={{ duration: 0.3, delay: 0.1, ease: "easeInOut" }}
335
357
  >
336
358
  <h2 className="font-sf-rounded font-neue-montreal-medium mb-1 text-center text-2xl font-semibold">
337
- {(() => {
338
- const hasEnoughBalance = b3RawBalance && BigInt(debouncedUserStakeAmount || "0") <= b3RawBalance;
339
- return hasEnoughBalance || !debouncedAmount ? "Stake B3" : "Swap & Stake B3";
340
- })()}
359
+ {isBalanceUnknown || !debouncedAmount || hasEnoughB3(debouncedUserStakeAmount)
360
+ ? "Stake B3"
361
+ : "Swap & Stake B3"}
341
362
  </h2>
342
363
  </motion.div>
343
364
  </div>
@@ -356,7 +377,14 @@ export function AnySpendStakeB3({
356
377
  <div className="flex items-center justify-between">
357
378
  <p className="text-as-primary/70 text-sm font-medium">I want to stake</p>
358
379
  <span className="text-as-primary/50 flex items-center gap-1 text-sm">
359
- Available: {isBalanceLoading ? <Loader2 className="h-3 w-3 animate-spin" /> : `${b3Balance} B3`}
380
+ Available:{" "}
381
+ {isBalanceLoading ? (
382
+ <Loader2 className="h-3 w-3 animate-spin" />
383
+ ) : isBalanceUnknown ? (
384
+ "unavailable"
385
+ ) : (
386
+ `${b3Balance} B3`
387
+ )}
360
388
  </span>
361
389
  </div>
362
390
  </div>
@@ -379,9 +407,22 @@ export function AnySpendStakeB3({
379
407
 
380
408
  <div className="mt-4">
381
409
  {(() => {
382
- const hasEnoughBalance = b3RawBalance && BigInt(debouncedUserStakeAmount || "0") <= b3RawBalance;
410
+ // An unreadable balance is not a shortfall, so it must not open the swap upsell —
411
+ // that would sell a swap to someone who may already hold the tokens.
412
+ if (isBalanceUnknown) {
413
+ return (
414
+ <div className="bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5">
415
+ <p className="text-as-primary/70 text-sm font-medium">
416
+ We couldn&apos;t read your B3 balance just now.
417
+ </p>
418
+ <Button variant="ghost" onClick={() => refetchBalance()} className="text-as-primary text-sm">
419
+ Try again
420
+ </Button>
421
+ </div>
422
+ );
423
+ }
383
424
 
384
- if (!hasEnoughBalance || !debouncedAmount) {
425
+ if (!hasEnoughB3(debouncedUserStakeAmount) || !debouncedAmount) {
385
426
  return (
386
427
  <div className="bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5">
387
428
  <div className="flex items-center justify-center gap-2">
@@ -9,7 +9,7 @@ import {
9
9
  toast,
10
10
  useHasMounted,
11
11
  useModalStore,
12
- useSimBalance,
12
+ usePortfolioBalance,
13
13
  useUnifiedChainSwitchAndExecute,
14
14
  } from "@b3dotfun/sdk/global-account/react";
15
15
  import { PUBLIC_BASE_RPC_URL } from "@b3dotfun/sdk/shared/constants";
@@ -82,12 +82,32 @@ export function AnySpendStakeB3ExactIn({
82
82
  const { address } = useAccount();
83
83
  const { switchChainAndExecute, isSwitchingOrExecuting } = useUnifiedChainSwitchAndExecute();
84
84
 
85
- // Fetch B3 token balance
86
- const { data: simBalance, isLoading: isBalanceLoading } = useSimBalance(address, [base.id]);
87
- const b3RawBalanceStr = simBalance?.balances.find(b => eqci(b.address, B3_TOKEN.address))?.amount || "0";
85
+ // Fetch B3 token balance. `isBalanceUnknown` must gate every use of `b3RawBalance`: a failed read
86
+ // yields the same 0 as an empty wallet, and acting on it pushes a holder into the swap flow to
87
+ // buy a token they already have.
88
+ const {
89
+ data: balances,
90
+ isLoading: isBalanceLoading,
91
+ isError: isBalanceError,
92
+ refetch: refetchBalance,
93
+ } = usePortfolioBalance(address, [base.id]);
94
+ // Guarded on `address`: with no wallet connected the query never runs, and a query that was
95
+ // never asked is not a query that failed. Without this the screen tells a visitor their
96
+ // balance is unavailable and refuses to continue, when they simply have not connected yet.
97
+ const isBalanceUnknown = Boolean(address) && (isBalanceError || (!isBalanceLoading && balances === undefined));
98
+ const b3RawBalanceStr = balances?.find(b => eqci(b.address, B3_TOKEN.address))?.amount || "0";
88
99
  const b3RawBalance = BigInt(b3RawBalanceStr);
89
100
  const b3Balance = formatTokenAmount(b3RawBalance, B3_TOKEN.decimals);
90
101
 
102
+ /**
103
+ * Whether the wallet demonstrably holds enough B3 to stake `amountRaw` directly.
104
+ *
105
+ * False while the balance is unknown — but callers must not read that as a shortfall. An unknown
106
+ * balance is neither enough nor short, and the two need different UI: a shortfall offers the swap
107
+ * flow, an unknown offers a retry. Check `isBalanceUnknown` first.
108
+ */
109
+ const hasEnoughB3 = (amountRaw: string) => !isBalanceUnknown && BigInt(amountRaw || "0") <= b3RawBalance;
110
+
91
111
  // State for direct staking flow
92
112
  const [isStaking, setIsStaking] = useState(false);
93
113
  const [stakingTxHash, setStakingTxHash] = useState<string>("");
@@ -283,9 +303,12 @@ export function AnySpendStakeB3ExactIn({
283
303
  }
284
304
 
285
305
  // Check if user has sufficient B3 balance for direct staking
286
- const hasEnoughBalance = b3RawBalance && BigInt(userStakeAmount) <= b3RawBalance;
306
+ if (isBalanceUnknown) {
307
+ toast.error("Can't read your B3 balance right now. Please try again.");
308
+ return;
309
+ }
287
310
 
288
- if (hasEnoughBalance) {
311
+ if (hasEnoughB3(userStakeAmount)) {
289
312
  // User has enough B3, proceed with direct staking
290
313
  handleDirectStaking();
291
314
  } else {
@@ -353,8 +376,9 @@ export function AnySpendStakeB3ExactIn({
353
376
  >
354
377
  <h2 className="font-sf-rounded font-neue-montreal-medium mb-1 text-center text-2xl font-semibold">
355
378
  {(() => {
356
- const hasEnoughBalance = b3RawBalance && BigInt(debouncedUserStakeAmount || "0") <= b3RawBalance;
357
- return hasEnoughBalance || !debouncedAmount ? "Stake B3" : "Swap & Stake B3";
379
+ return isBalanceUnknown || !debouncedAmount || hasEnoughB3(debouncedUserStakeAmount)
380
+ ? "Stake B3"
381
+ : "Swap & Stake B3";
358
382
  })()}
359
383
  </h2>
360
384
  </motion.div>
@@ -374,7 +398,14 @@ export function AnySpendStakeB3ExactIn({
374
398
  <div className="flex items-center justify-between">
375
399
  <p className="text-as-primary/70 text-sm font-medium">I want to stake</p>
376
400
  <span className="text-as-primary/50 flex items-center gap-1 text-sm">
377
- Available: {isBalanceLoading ? <Loader2 className="h-3 w-3 animate-spin" /> : `${b3Balance} B3`}
401
+ Available:{" "}
402
+ {isBalanceLoading ? (
403
+ <Loader2 className="h-3 w-3 animate-spin" />
404
+ ) : isBalanceUnknown ? (
405
+ "unavailable"
406
+ ) : (
407
+ `${b3Balance} B3`
408
+ )}
378
409
  </span>
379
410
  </div>
380
411
  </div>
@@ -397,9 +428,22 @@ export function AnySpendStakeB3ExactIn({
397
428
 
398
429
  <div className="mt-4">
399
430
  {(() => {
400
- const hasEnoughBalance = b3RawBalance && BigInt(debouncedUserStakeAmount || "0") <= b3RawBalance;
431
+ // An unreadable balance is not a shortfall, so it must not open the swap upsell —
432
+ // that would sell a swap to someone who may already hold the tokens.
433
+ if (isBalanceUnknown) {
434
+ return (
435
+ <div className="bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5">
436
+ <p className="text-as-primary/70 text-sm font-medium">
437
+ We couldn&apos;t read your B3 balance just now.
438
+ </p>
439
+ <Button variant="ghost" onClick={() => refetchBalance()} className="text-as-primary text-sm">
440
+ Try again
441
+ </Button>
442
+ </div>
443
+ );
444
+ }
401
445
 
402
- if (!hasEnoughBalance || !debouncedAmount) {
446
+ if (!hasEnoughB3(debouncedUserStakeAmount) || !debouncedAmount) {
403
447
  return (
404
448
  <div className="bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5">
405
449
  <div className="flex items-center justify-center gap-2">