@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
@@ -11,7 +11,7 @@ import { cn } from "@b3dotfun/sdk/shared/utils/cn";
11
11
  import { TokenSelector } from "@relayprotocol/relay-kit-ui";
12
12
  import { Check, ChevronsUpDown, Copy, Loader2 } from "lucide-react";
13
13
  import { QRCodeSVG } from "qrcode.react";
14
- import { useEffect, useRef, useState } from "react";
14
+ import { useCallback, useEffect, useRef, useState } from "react";
15
15
  import { useAnyspendOrderAndTransactions } from "../hooks/useAnyspendOrderAndTransactions";
16
16
  import { useCreateDepositFirstOrder } from "../hooks/useCreateDepositFirstOrder";
17
17
  import { useOnOrderSuccess } from "../hooks/useOnOrderSuccess";
@@ -36,6 +36,22 @@ export interface QRDepositProps {
36
36
  destinationToken: components["schemas"]["Token"];
37
37
  /** The destination chain ID */
38
38
  destinationChainId: number;
39
+ /**
40
+ * Human-formatted destination amount (e.g. "9.365547"), shown as an APPROXIMATE
41
+ * target in swap mode only. The QR deposit path accepts an arbitrary sent amount,
42
+ * so this is never a guaranteed receive figure — the UI frames it as "any amount
43
+ * works". Omitted when no fixed amount is set or the destination decimals are
44
+ * unresolved (to avoid a mis-scaled number). Ignored in pure-transfer mode.
45
+ */
46
+ destinationAmountDisplay?: string;
47
+ /**
48
+ * When true, the deposit is a PURE TRANSFER: the destination token/chain mirror
49
+ * the user's currently selected source token/chain, so the exact token the user
50
+ * sends lands in their wallet on the same chain — no swap/bridge order is created.
51
+ * The `destinationToken`/`destinationChainId` props are then used only as the
52
+ * initial source selection (they must be fully resolved before mount). Defaults to false.
53
+ */
54
+ pureTransferOnly?: boolean;
39
55
  /** Creator address (optional) */
40
56
  creatorAddress?: string;
41
57
  /** Contract config for custom execution after deposit */
@@ -46,8 +62,11 @@ export interface QRDepositProps {
46
62
  onClose?: () => void;
47
63
  /** Callback when order is created successfully */
48
64
  onOrderCreated?: (orderId: string) => void;
49
- /** Callback when deposit is completed */
50
- onSuccess?: (txHash?: string) => void;
65
+ /**
66
+ * Callback when deposit is completed. The argument carries the deposited amount string
67
+ * (e.g. "200.00") on the pure-transfer path, or the order tx hash otherwise.
68
+ */
69
+ onSuccess?: (amountOrTxHash?: string) => void;
51
70
  /** Custom classes for styling */
52
71
  classes?: QRDepositClasses;
53
72
  }
@@ -85,6 +104,8 @@ export function QRDeposit({
85
104
  sourceChainId: sourceChainIdProp,
86
105
  destinationToken,
87
106
  destinationChainId,
107
+ destinationAmountDisplay,
108
+ pureTransferOnly = false,
88
109
  creatorAddress,
89
110
  depositContractConfig,
90
111
  onBack,
@@ -99,31 +120,45 @@ export function QRDeposit({
99
120
  const orderCreatedRef = useRef(false);
100
121
  const [transferResult, setTransferResult] = useState<TransferResult | null>(null);
101
122
 
102
- // Source token/chain as state (can be changed by user)
103
- const [sourceChainId, setSourceChainId] = useState(sourceChainIdProp ?? 8453);
123
+ // Source token/chain as state (can be changed by user).
124
+ // In pure-transfer mode the initial source is the passed destination (caller sets
125
+ // it to the desired default funding token), so the deposit mirrors the user's selection.
126
+ const [sourceChainId, setSourceChainId] = useState(
127
+ sourceChainIdProp ?? (pureTransferOnly ? destinationChainId : 8453),
128
+ );
104
129
  const [sourceToken, setSourceToken] = useState<components["schemas"]["Token"]>(
105
- sourceTokenProp ?? DEFAULT_ETH_ON_BASE,
130
+ sourceTokenProp ?? (pureTransferOnly ? destinationToken : DEFAULT_ETH_ON_BASE),
106
131
  );
107
132
 
133
+ // In pure-transfer mode the effective destination mirrors the selected source,
134
+ // forcing isPureTransfer = true (no swap/bridge order is created).
135
+ const effectiveDestinationToken = pureTransferOnly ? sourceToken : destinationToken;
136
+ const effectiveDestinationChainId = pureTransferOnly ? sourceChainId : destinationChainId;
137
+
108
138
  // Check if this is a pure transfer (same chain and token)
109
139
  const isPureTransfer = isSameChainAndToken(
110
140
  sourceChainId,
111
141
  sourceToken.address,
112
- destinationChainId,
113
- destinationToken.address,
142
+ effectiveDestinationChainId,
143
+ effectiveDestinationToken.address,
144
+ );
145
+
146
+ const handleTransferDetected = useCallback(
147
+ (result: TransferResult) => {
148
+ setTransferResult(result);
149
+ onSuccess?.(result.formattedAmount);
150
+ },
151
+ [onSuccess],
114
152
  );
115
153
 
116
154
  // Watch for pure transfers (same chain and token)
117
- const { isWatching: isWatchingTransfer } = useWatchTransfer({
155
+ const { isWatching: isWatchingTransfer, reset: resetWatchTransfer } = useWatchTransfer({
118
156
  address: recipientAddress,
119
157
  chainId: sourceChainId,
120
158
  tokenAddress: sourceToken.address,
121
159
  tokenDecimals: sourceToken.decimals,
122
160
  enabled: isPureTransfer && !transferResult,
123
- onTransferDetected: result => {
124
- setTransferResult(result);
125
- onSuccess?.();
126
- },
161
+ onTransferDetected: handleTransferDetected,
127
162
  });
128
163
 
129
164
  // Handle token selection from TokenSelector
@@ -142,6 +177,8 @@ export function QRDeposit({
142
177
  setGlobalAddress(undefined);
143
178
  orderCreatedRef.current = false;
144
179
  setTransferResult(null);
180
+ // Reset the balance watcher baseline so the new token isn't compared against the old token's balance
181
+ resetWatchTransfer();
145
182
 
146
183
  // Update token and chain
147
184
  setSourceChainId(newToken.chainId);
@@ -176,18 +213,18 @@ export function QRDeposit({
176
213
  createOrder({
177
214
  recipientAddress,
178
215
  srcChain: sourceChainId,
179
- dstChain: destinationChainId,
216
+ dstChain: effectiveDestinationChainId,
180
217
  srcToken: sourceToken,
181
- dstToken: destinationToken,
218
+ dstToken: effectiveDestinationToken,
182
219
  creatorAddress,
183
220
  contractConfig: depositContractConfig,
184
221
  });
185
222
  }, [
186
223
  recipientAddress,
187
224
  sourceChainId,
188
- destinationChainId,
225
+ effectiveDestinationChainId,
189
226
  sourceToken,
190
- destinationToken,
227
+ effectiveDestinationToken,
191
228
  creatorAddress,
192
229
  depositContractConfig,
193
230
  createOrder,
@@ -382,6 +419,32 @@ export function QRDeposit({
382
419
  />
383
420
  </div>
384
421
 
422
+ {/* Receive (swap mode only) — makes the conversion explicit: what the sent token
423
+ becomes and on which chain. Gated on the computed isPureTransfer (not the static
424
+ prop) so a runtime source change back to the same token correctly hides it. */}
425
+ {!isPureTransfer && (
426
+ <div className="anyspend-qr-receive flex flex-col gap-1.5">
427
+ <label className="anyspend-qr-receive-label text-as-secondary text-sm">Receive</label>
428
+ <div className="anyspend-qr-receive-row border-as-stroke bg-as-surface-secondary flex w-full items-center gap-2 rounded-xl border px-3 py-2.5">
429
+ {effectiveDestinationToken.metadata?.logoURI ? (
430
+ <ChainTokenIcon
431
+ chainUrl={ALL_CHAINS[effectiveDestinationChainId]?.logoUrl}
432
+ tokenUrl={effectiveDestinationToken.metadata.logoURI}
433
+ className="h-8 min-h-8 w-8 min-w-8"
434
+ />
435
+ ) : (
436
+ <div className="h-8 w-8 rounded-full bg-gray-700" />
437
+ )}
438
+ <div className="flex flex-col items-start gap-0">
439
+ <div className="text-as-primary font-semibold">{effectiveDestinationToken.symbol || "Token"}</div>
440
+ <div className="text-as-primary/70 text-xs">
441
+ {ALL_CHAINS[effectiveDestinationChainId]?.name ?? "Unknown"}
442
+ </div>
443
+ </div>
444
+ </div>
445
+ </div>
446
+ )}
447
+
385
448
  {/* QR Code and Address - horizontal layout */}
386
449
  <div
387
450
  className={
@@ -425,11 +488,27 @@ export function QRDeposit({
425
488
  </div>
426
489
 
427
490
  {/* Warnings */}
428
- <ChainWarningText chainId={destinationChainId} />
429
- <WarningText>
430
- Only send {sourceToken.symbol} on {ALL_CHAINS[sourceChainId]?.name ?? "the specified chain"}. Other tokens
431
- will not be converted.
432
- </WarningText>
491
+ <ChainWarningText chainId={effectiveDestinationChainId} />
492
+ {isPureTransfer ? (
493
+ <WarningText>
494
+ Only send {sourceToken.symbol} on {ALL_CHAINS[sourceChainId]?.name ?? "the specified chain"}. Other tokens
495
+ will not be converted.
496
+ </WarningText>
497
+ ) : (
498
+ <>
499
+ <WarningText>
500
+ Only send {sourceToken.symbol} on {ALL_CHAINS[sourceChainId]?.name ?? "the specified chain"} to this
501
+ address — it will be converted to {effectiveDestinationToken.symbol || "the destination token"} on{" "}
502
+ {ALL_CHAINS[effectiveDestinationChainId]?.name ?? "the destination chain"}.
503
+ </WarningText>
504
+ {destinationAmountDisplay && (
505
+ <p className="anyspend-qr-amount-hint text-as-secondary text-xs">
506
+ Target ≈ {destinationAmountDisplay} {effectiveDestinationToken.symbol || "tokens"}. Any amount of{" "}
507
+ {sourceToken.symbol || "tokens"} works — you'll receive whatever your deposit converts to.
508
+ </p>
509
+ )}
510
+ </>
511
+ )}
433
512
 
434
513
  {/* Watching indicator for pure transfers */}
435
514
  {isPureTransfer && isWatchingTransfer && (
@@ -0,0 +1,331 @@
1
+ import { RELAY_SOLANA_MAINNET_CHAIN_ID, USDC_BASE } from "@b3dotfun/sdk/anyspend";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+
5
+ /**
6
+ * Deterministic component test for the `pureTransferOnly` "Fund Wallet" behavior.
7
+ *
8
+ * When `pureTransferOnly` is true, the destination token MIRRORS the user-selected
9
+ * source token, so funding is always a same-chain/same-token PURE TRANSFER:
10
+ * - NO `deposit_first` swap order is created (the order-creation effect early-returns
11
+ * on `isPureTransfer`), so `createOrder` is never called.
12
+ * - The QR/deposit address is the recipient's OWN wallet address (not a global/order
13
+ * address minted by AnySpend).
14
+ * - `useWatchTransfer` watches the user's wallet for the EXACT token they selected.
15
+ *
16
+ * This guards the bug where "Fund Wallet" with USDC delivered ETH instead.
17
+ */
18
+
19
+ // --- Spies / captured args observable across the test file ---
20
+
21
+ // createOrder spy returned by useCreateDepositFirstOrder.
22
+ const createOrderSpy = vi.fn();
23
+
24
+ // reset spy returned by useWatchTransfer — QRDeposit calls reset() on token switch to
25
+ // clear the stale balance baseline (see Test B).
26
+ const resetSpy = vi.fn();
27
+
28
+ // Captures the most recent props passed to useWatchTransfer so we can assert which
29
+ // token/decimals/address the pure-transfer path is watching.
30
+ let watchTransferArgs: any;
31
+
32
+ // Holds the `setToken` callback handed to the mocked Relay TokenSelector so a test
33
+ // can simulate the user switching the source token.
34
+ let capturedSetToken: ((token: any) => void) | undefined;
35
+
36
+ // Allows Test D to flip useTokenData's return (null = API miss) for the
37
+ // AnySpendDeposit-level decimals-invariant assertion.
38
+ const tokenDataState: { data: any; isLoading: boolean } = { data: null, isLoading: false };
39
+
40
+ // --- Mocks ---
41
+
42
+ // Mock the four hooks QRDeposit imports (relative paths from the component file).
43
+ vi.mock("../../hooks/useCreateDepositFirstOrder", () => ({
44
+ useCreateDepositFirstOrder: () => ({ createOrder: createOrderSpy, isCreatingOrder: false }),
45
+ }));
46
+
47
+ vi.mock("../../hooks/useAnyspendOrderAndTransactions", () => ({
48
+ useAnyspendOrderAndTransactions: () => ({ orderAndTransactions: undefined }),
49
+ }));
50
+
51
+ vi.mock("../../hooks/useWatchTransfer", () => ({
52
+ useWatchTransfer: (props: any) => {
53
+ watchTransferArgs = props;
54
+ return { isWatching: true, reset: resetSpy };
55
+ },
56
+ }));
57
+
58
+ vi.mock("../../hooks/useOnOrderSuccess", () => ({
59
+ useOnOrderSuccess: () => undefined,
60
+ }));
61
+
62
+ // Mock the Relay TokenSelector: render a button that, when clicked, invokes the passed
63
+ // `setToken` with a chosen token, simulating the user switching the source token. Also
64
+ // render the provided `trigger` so the rest of the component tree still mounts.
65
+ vi.mock("@relayprotocol/relay-kit-ui", () => ({
66
+ TokenSelector: ({ setToken, trigger }: any) => {
67
+ capturedSetToken = setToken;
68
+ return (
69
+ <div data-testid="token-selector">
70
+ {trigger}
71
+ <button data-testid="switch-token" onClick={() => setToken(SWITCHED_ETH_ON_BASE)} />
72
+ </div>
73
+ );
74
+ },
75
+ }));
76
+
77
+ vi.mock("@stripe/stripe-js", () => ({
78
+ loadStripe: vi.fn(() => Promise.resolve(null)),
79
+ }));
80
+
81
+ // Spread the real global-account/react (Button, Badge, etc. are needed by transitively
82
+ // imported sub-components and render fine under happy-dom). Override only `toast` so the
83
+ // error path doesn't depend on a toast provider.
84
+ vi.mock("@b3dotfun/sdk/global-account/react", async importOriginal => {
85
+ const actual = await importOriginal<any>();
86
+ return { ...actual, toast: { error: vi.fn(), success: vi.fn() } };
87
+ });
88
+
89
+ // Mock the wallet/balance/token hooks at their SOURCE modules (the barrel re-exports
90
+ // these, so the override binds reliably). This lets AnySpendDeposit (Test D) render
91
+ // without a ThirdwebProvider / wallet context and keeps the token-data fetch deterministic.
92
+ vi.mock("@b3dotfun/sdk/global-account/react/hooks/useAccountWallet", () => ({
93
+ useAccountWallet: () => ({ connectedEOAWallet: undefined }),
94
+ }));
95
+
96
+ vi.mock("@b3dotfun/sdk/global-account/react/hooks/usePortfolioBalance", () => ({
97
+ usePortfolioBalance: () => ({ data: undefined, isLoading: false, isError: false }),
98
+ usePortfolioTokenBalance: () => ({ data: undefined, isLoading: false, isError: false }),
99
+ }));
100
+
101
+ vi.mock("@b3dotfun/sdk/global-account/react/hooks/useTokenData", () => ({
102
+ useTokenData: () => tokenDataState,
103
+ }));
104
+
105
+ // --- Fixtures ---
106
+
107
+ const RECIPIENT = "0x1111111111111111111111111111111111111111";
108
+
109
+ // A DIFFERENT token than USDC for the "switch source token" test: native ETH on Base.
110
+ const SWITCHED_ETH_ON_BASE = {
111
+ chainId: 8453,
112
+ address: "0x0000000000000000000000000000000000000000",
113
+ symbol: "ETH",
114
+ name: "Ethereum",
115
+ decimals: 18,
116
+ logoURI: "https://assets.relay.link/icons/1/light.png",
117
+ };
118
+
119
+ // Imported lazily so module-level mocks are registered before the component graph loads.
120
+ async function loadQRDeposit() {
121
+ const mod = await import("../QRDeposit");
122
+ return mod.QRDeposit;
123
+ }
124
+
125
+ async function loadAnySpendDeposit() {
126
+ const mod = await import("../AnySpendDeposit");
127
+ return mod.AnySpendDeposit;
128
+ }
129
+
130
+ beforeEach(() => {
131
+ watchTransferArgs = undefined;
132
+ capturedSetToken = undefined;
133
+ tokenDataState.data = null;
134
+ tokenDataState.isLoading = false;
135
+ });
136
+
137
+ afterEach(() => {
138
+ vi.clearAllMocks();
139
+ });
140
+
141
+ describe("QRDeposit pureTransferOnly (Fund Wallet)", () => {
142
+ it("Test A — pure transfer creates NO order and uses the wallet's own address", async () => {
143
+ const QRDeposit = await loadQRDeposit();
144
+
145
+ render(
146
+ <QRDeposit
147
+ pureTransferOnly
148
+ recipientAddress={RECIPIENT}
149
+ destinationToken={USDC_BASE}
150
+ destinationChainId={8453}
151
+ />,
152
+ );
153
+
154
+ // The whole point: no swap/bridge order is created in pure-transfer mode.
155
+ expect(createOrderSpy).not.toHaveBeenCalled();
156
+
157
+ // It watches the recipient's OWN wallet for a direct incoming transfer, and is enabled.
158
+ expect(watchTransferArgs).toBeDefined();
159
+ expect(watchTransferArgs.address).toBe(RECIPIENT);
160
+ expect(watchTransferArgs.enabled).toBe(true);
161
+
162
+ // The mirror followed the initial selection: it watches for the EXACT funding token
163
+ // (Base USDC, 6 decimals) — NOT a generic 18-decimal fallback.
164
+ expect(watchTransferArgs.chainId).toBe(USDC_BASE.chainId);
165
+ expect(watchTransferArgs.tokenAddress).toBe(USDC_BASE.address);
166
+ expect(watchTransferArgs.tokenDecimals).toBe(6);
167
+
168
+ // The displayed deposit address is the recipient's own address, NOT a global/order address.
169
+ expect(screen.getByText(RECIPIENT)).toBeTruthy();
170
+
171
+ // Pure-transfer UI is unchanged: NO "Receive" row (there is no distinct destination),
172
+ // and the accurate "will not be converted" warning is kept verbatim.
173
+ expect(screen.queryByText("Receive")).toBeNull();
174
+ expect(screen.getByText(/Other tokens will not be converted/)).toBeTruthy();
175
+ });
176
+
177
+ it("Test B — switching the source token stays a pure transfer (no order; mirror follows selection)", async () => {
178
+ const QRDeposit = await loadQRDeposit();
179
+
180
+ render(
181
+ <QRDeposit
182
+ pureTransferOnly
183
+ recipientAddress={RECIPIENT}
184
+ destinationToken={USDC_BASE}
185
+ destinationChainId={8453}
186
+ />,
187
+ );
188
+
189
+ // Sanity: still USDC before the switch.
190
+ expect(watchTransferArgs.tokenAddress).toBe(USDC_BASE.address);
191
+ expect(watchTransferArgs.tokenDecimals).toBe(6);
192
+
193
+ // User switches the source token to native ETH on Base via the (mocked) TokenSelector.
194
+ expect(capturedSetToken).toBeDefined();
195
+ fireEvent.click(screen.getByTestId("switch-token"));
196
+
197
+ // The balance watcher baseline is reset on token switch, so the new token isn't
198
+ // compared against the old token's (differently-scaled) balance.
199
+ expect(resetSpy).toHaveBeenCalled();
200
+
201
+ // Still a pure transfer: no order is ever created, even after switching tokens.
202
+ expect(createOrderSpy).not.toHaveBeenCalled();
203
+
204
+ // The mirror followed the new selection: now watching native ETH (18 decimals) on Base.
205
+ expect(watchTransferArgs.address).toBe(RECIPIENT);
206
+ expect(watchTransferArgs.enabled).toBe(true);
207
+ expect(watchTransferArgs.chainId).toBe(SWITCHED_ETH_ON_BASE.chainId);
208
+ expect(watchTransferArgs.tokenAddress).toBe(SWITCHED_ETH_ON_BASE.address);
209
+ expect(watchTransferArgs.tokenDecimals).toBe(18);
210
+ });
211
+
212
+ it("Test C — control: pureTransferOnly=false with source != destination DOES create an order", async () => {
213
+ const QRDeposit = await loadQRDeposit();
214
+
215
+ // No pureTransferOnly: source defaults to ETH-on-Base, which differs from the USDC dest,
216
+ // so this is a real swap and the normal deposit_first order path must run.
217
+ const { container } = render(
218
+ <QRDeposit
219
+ recipientAddress={RECIPIENT}
220
+ destinationToken={USDC_BASE}
221
+ destinationChainId={8453}
222
+ destinationAmountDisplay="9.365547"
223
+ />,
224
+ );
225
+
226
+ // The flag is what gates the pure-transfer behavior: without it, an order IS created once.
227
+ expect(createOrderSpy).toHaveBeenCalledTimes(1);
228
+
229
+ // And it's created with the USDC destination token (the swap path is intact).
230
+ const orderArgs = createOrderSpy.mock.calls[0][0];
231
+ expect(orderArgs.recipientAddress).toBe(RECIPIENT);
232
+ expect(orderArgs.dstToken.address).toBe(USDC_BASE.address);
233
+ expect(orderArgs.dstToken.decimals).toBe(6);
234
+ // Source defaulted to native ETH on Base (the differing token that forces a swap).
235
+ expect(orderArgs.srcToken.address).toBe("0x0000000000000000000000000000000000000000");
236
+
237
+ // Swap-mode UX clarity: a read-only "Receive" row now discloses the destination token…
238
+ expect(screen.getByText("Receive")).toBeTruthy();
239
+ // …the misleading "will not be converted" copy is gone…
240
+ expect(screen.queryByText(/will not be converted/)).toBeNull();
241
+ // …the warning states the conversion explicitly, and the fixed amount shows as an
242
+ // approximate target (never a guaranteed receive figure).
243
+ expect(container.textContent).toContain("it will be converted to USDC on Base");
244
+ expect(container.textContent).toContain("Target ≈ 9.365547 USDC");
245
+ });
246
+
247
+ it("Test C3 — case-mutated Solana mints require a swap order", async () => {
248
+ const QRDeposit = await loadQRDeposit();
249
+ const wrappedSol = "So11111111111111111111111111111111111111112";
250
+ const sourceToken = {
251
+ chainId: RELAY_SOLANA_MAINNET_CHAIN_ID,
252
+ address: wrappedSol,
253
+ symbol: "wSOL",
254
+ name: "Wrapped SOL",
255
+ decimals: 9,
256
+ metadata: {},
257
+ };
258
+ const destinationToken = {
259
+ ...sourceToken,
260
+ address: `s${wrappedSol.slice(1)}`,
261
+ symbol: "OTHER",
262
+ name: "Distinct Solana Mint",
263
+ };
264
+
265
+ render(
266
+ <QRDeposit
267
+ recipientAddress={RECIPIENT}
268
+ sourceToken={sourceToken}
269
+ sourceChainId={RELAY_SOLANA_MAINNET_CHAIN_ID}
270
+ destinationToken={destinationToken}
271
+ destinationChainId={RELAY_SOLANA_MAINNET_CHAIN_ID}
272
+ destinationAmountDisplay="1"
273
+ />,
274
+ );
275
+
276
+ expect(createOrderSpy).toHaveBeenCalledTimes(1);
277
+ expect(createOrderSpy.mock.calls[0][0].dstToken.address).toBe(destinationToken.address);
278
+ expect(watchTransferArgs.enabled).toBe(false);
279
+ });
280
+
281
+ it("Test C2 — swap mode without a fixed amount shows the Receive row but no target hint", async () => {
282
+ const QRDeposit = await loadQRDeposit();
283
+
284
+ // Swap mode (source ETH-on-Base != USDC dest) but NO destinationAmountDisplay — the common
285
+ // open-ended funding case. The destination must still be disclosed, but there must be no
286
+ // dangling "Target ≈" line (and no blank amount).
287
+ const { container } = render(
288
+ <QRDeposit recipientAddress={RECIPIENT} destinationToken={USDC_BASE} destinationChainId={8453} />,
289
+ );
290
+
291
+ // Destination is still disclosed…
292
+ expect(screen.getByText("Receive")).toBeTruthy();
293
+ expect(container.textContent).toContain("it will be converted to USDC on Base");
294
+ // …but no amount hint is rendered when no amount is provided.
295
+ expect(container.textContent).not.toContain("Target ≈");
296
+ });
297
+ });
298
+
299
+ describe("AnySpendDeposit decimals invariant (KNOWN_FUNDING_TOKENS fallback)", () => {
300
+ it("Test D — Base USDC keeps decimals: 6 even when useTokenData returns null", async () => {
301
+ const AnySpendDeposit = await loadAnySpendDeposit();
302
+
303
+ // Simulate the API miss: useTokenData returns null. The KNOWN_FUNDING_TOKENS fallback
304
+ // in AnySpendDeposit must still resolve Base USDC to decimals: 6 (never the generic 18),
305
+ // and that fully-resolved token is forwarded to QRDeposit as the pure-transfer source.
306
+ tokenDataState.data = null;
307
+ tokenDataState.isLoading = false;
308
+
309
+ render(
310
+ <AnySpendDeposit
311
+ pureTransferOnly
312
+ recipientAddress={RECIPIENT}
313
+ destinationTokenAddress={USDC_BASE.address}
314
+ destinationTokenChainId={USDC_BASE.chainId}
315
+ />,
316
+ );
317
+
318
+ // pureTransferOnly no longer auto-opens QR — AnySpendDeposit lands on the chooser
319
+ // (select-chain) screen first. Navigate into QR exactly like the user would, by
320
+ // clicking the "Deposit with QR Code" option.
321
+ fireEvent.click(screen.getByText("Deposit with QR Code"));
322
+
323
+ // Verified end-to-end through the REAL AnySpendDeposit -> REAL QRDeposit: the pure-transfer
324
+ // source mirrors the destination, so useWatchTransfer is called with USDC's 6 decimals.
325
+ expect(watchTransferArgs).toBeDefined();
326
+ expect(watchTransferArgs.tokenAddress).toBe(USDC_BASE.address);
327
+ expect(watchTransferArgs.tokenDecimals).toBe(6);
328
+ // No swap order in pure-transfer mode.
329
+ expect(createOrderSpy).not.toHaveBeenCalled();
330
+ });
331
+ });
@@ -6,13 +6,18 @@ import { useAnyspendCreateOrder } from "@b3dotfun/sdk/anyspend/react/hooks/useAn
6
6
  import { useAnyspendOrderAndTransactions } from "@b3dotfun/sdk/anyspend/react/hooks/useAnyspendOrderAndTransactions";
7
7
  import { useCreateDepositFirstOrder } from "@b3dotfun/sdk/anyspend/react/hooks/useCreateDepositFirstOrder";
8
8
  import { useOnOrderSuccess } from "@b3dotfun/sdk/anyspend/react/hooks/useOnOrderSuccess";
9
- import { ALL_CHAINS, RELAY_SOLANA_MAINNET_CHAIN_ID, getAvailableChainIds } from "@b3dotfun/sdk/anyspend";
10
- import { getPaymentUrl } from "@b3dotfun/sdk/anyspend/utils/chain";
9
+ import {
10
+ ALL_CHAINS,
11
+ RELAY_SOLANA_MAINNET_CHAIN_ID,
12
+ getAvailableChainIds,
13
+ isSameChainAndToken,
14
+ } from "@b3dotfun/sdk/anyspend";
15
+ import { getPaymentUrl, toRegistryChainId } from "@b3dotfun/sdk/anyspend/utils/chain";
11
16
  import { isNativeToken } from "@b3dotfun/sdk/anyspend/utils/token";
12
17
  import {
13
18
  useAccountWallet,
14
19
  useIsMobile,
15
- useSimTokenBalance,
20
+ usePortfolioTokenBalance,
16
21
  useTokenData,
17
22
  useUnifiedChainSwitchAndExecute,
18
23
  } from "@b3dotfun/sdk/global-account/react";
@@ -97,9 +102,13 @@ export function CryptoPayPanel({
97
102
  }, [selectedSrcToken, dstTokenData, destinationTokenAddress, destinationTokenChainId]);
98
103
 
99
104
  const isSameToken =
100
- selectedSrcToken &&
101
- selectedSrcToken.address.toLowerCase() === destinationTokenAddress.toLowerCase() &&
102
- selectedSrcToken.chainId === destinationTokenChainId;
105
+ selectedSrcToken !== null &&
106
+ isSameChainAndToken(
107
+ selectedSrcToken.chainId,
108
+ selectedSrcToken.address,
109
+ destinationTokenChainId,
110
+ destinationTokenAddress,
111
+ );
103
112
 
104
113
  const { anyspendQuote, isLoadingAnyspendQuote } = useAnyspendQuote({
105
114
  type: "swap",
@@ -116,13 +125,21 @@ export function CryptoPayPanel({
116
125
  ? "native"
117
126
  : selectedSrcToken.address
118
127
  : undefined;
119
- const { data: balanceData } = useSimTokenBalance(effectiveAddress, tokenAddress, selectedSrcChainId);
128
+ // `selectedSrcChainId` is Relay-numbered; balance rows are keyed by the chain registry's id.
129
+ const { data: balanceRow, isError: isBalanceError } = usePortfolioTokenBalance(
130
+ effectiveAddress,
131
+ tokenAddress,
132
+ toRegistryChainId(selectedSrcChainId),
133
+ );
120
134
 
121
135
  const balance = useMemo(() => {
122
- const b = balanceData?.balances?.[0];
123
- if (!b?.amount) return { raw: BigInt(0), formatted: "0", decimals: 18 };
124
- return { raw: BigInt(b.amount), formatted: formatTokenAmount(BigInt(b.amount), b.decimals), decimals: b.decimals };
125
- }, [balanceData]);
136
+ if (!balanceRow?.amount) return { raw: BigInt(0), formatted: "0", decimals: 18 };
137
+ return {
138
+ raw: BigInt(balanceRow.amount),
139
+ formatted: formatTokenAmount(BigInt(balanceRow.amount), balanceRow.decimals),
140
+ decimals: balanceRow.decimals,
141
+ };
142
+ }, [balanceRow]);
126
143
 
127
144
  const srcAmount = useMemo(() => {
128
145
  if (isSameToken) return totalAmount;
@@ -134,7 +151,9 @@ export function CryptoPayPanel({
134
151
  return formatTokenAmount(BigInt(srcAmount || "0"), selectedSrcToken.decimals || 18);
135
152
  }, [srcAmount, selectedSrcToken]);
136
153
 
137
- const hasEnoughBalance = balance.raw >= BigInt(srcAmount || "0");
154
+ // A failed balance read must not masquerade as a shortfall: it would disable Pay and tell a
155
+ // funded user they are short. Unknown blocks auto-pay but leaves the manual path open.
156
+ const hasEnoughBalance = !isBalanceError && balance.raw >= BigInt(srcAmount || "0");
138
157
 
139
158
  /* ------------------------------------------------------------------ */
140
159
  /* Destination token object (shared by both flows) */
@@ -385,7 +404,8 @@ export function CryptoPayPanel({
385
404
 
386
405
  const isLoading = isLoadingAnyspendQuote;
387
406
  const isPending = isCreatingSwapOrder || isSendingDeposit || isWaitingForExecution;
388
- const canPay = connectedAddress && selectedSrcToken && hasEnoughBalance && !isLoading && !isPending;
407
+ const canPay =
408
+ connectedAddress && selectedSrcToken && (hasEnoughBalance || isBalanceError) && !isLoading && !isPending;
389
409
 
390
410
  const chainName = ALL_CHAINS[selectedSrcChainId]?.name || "the specified chain";
391
411
  const chainLogoUrl = ALL_CHAINS[selectedSrcChainId]?.logoUrl;
@@ -494,7 +514,7 @@ export function CryptoPayPanel({
494
514
  </div>
495
515
  </motion.div>
496
516
 
497
- {/* ---- Insufficient balance warning ---- */}
517
+ {/* ---- Balance warning ---- */}
498
518
  <AnimatePresence>
499
519
  {connectedAddress && selectedSrcToken && !hasEnoughBalance && !isLoading && (
500
520
  <motion.p
@@ -503,9 +523,11 @@ export function CryptoPayPanel({
503
523
  animate={{ opacity: 1, height: "auto" }}
504
524
  exit={{ opacity: 0, height: 0 }}
505
525
  transition={{ duration: 0.2, ease: "easeOut" }}
506
- className="text-center text-sm text-red-500"
526
+ className={`text-center text-sm ${isBalanceError ? "text-as-primary/50" : "text-red-500"}`}
507
527
  >
508
- Insufficient {selectedSrcToken.symbol} balance
528
+ {isBalanceError
529
+ ? `Couldn't check your ${selectedSrcToken.symbol} balance`
530
+ : `Insufficient ${selectedSrcToken.symbol} balance`}
509
531
  </motion.p>
510
532
  )}
511
533
  </AnimatePresence>