@b3dotfun/sdk 0.1.68-alpha.3 → 0.1.68-alpha.5

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 (167) hide show
  1. package/dist/cjs/anyspend/platform/client.d.ts +35 -0
  2. package/dist/cjs/anyspend/platform/client.js +158 -0
  3. package/dist/cjs/anyspend/platform/errors.d.ts +38 -0
  4. package/dist/cjs/anyspend/platform/errors.js +77 -0
  5. package/dist/cjs/anyspend/platform/index.d.ts +87 -0
  6. package/dist/cjs/anyspend/platform/index.js +85 -0
  7. package/dist/cjs/anyspend/platform/resources/analytics.d.ts +7 -0
  8. package/dist/cjs/anyspend/platform/resources/analytics.js +12 -0
  9. package/dist/cjs/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
  10. package/dist/cjs/anyspend/platform/resources/checkout-sessions.js +27 -0
  11. package/dist/cjs/anyspend/platform/resources/customers.d.ts +19 -0
  12. package/dist/cjs/anyspend/platform/resources/customers.js +34 -0
  13. package/dist/cjs/anyspend/platform/resources/discount-codes.d.ts +29 -0
  14. package/dist/cjs/anyspend/platform/resources/discount-codes.js +31 -0
  15. package/dist/cjs/anyspend/platform/resources/events.d.ts +14 -0
  16. package/dist/cjs/anyspend/platform/resources/events.js +16 -0
  17. package/dist/cjs/anyspend/platform/resources/notifications.d.ts +18 -0
  18. package/dist/cjs/anyspend/platform/resources/notifications.js +27 -0
  19. package/dist/cjs/anyspend/platform/resources/organization.d.ts +17 -0
  20. package/dist/cjs/anyspend/platform/resources/organization.js +15 -0
  21. package/dist/cjs/anyspend/platform/resources/payment-links.d.ts +21 -0
  22. package/dist/cjs/anyspend/platform/resources/payment-links.js +49 -0
  23. package/dist/cjs/anyspend/platform/resources/products.d.ts +27 -0
  24. package/dist/cjs/anyspend/platform/resources/products.js +31 -0
  25. package/dist/cjs/anyspend/platform/resources/transactions.d.ts +11 -0
  26. package/dist/cjs/anyspend/platform/resources/transactions.js +25 -0
  27. package/dist/cjs/anyspend/platform/resources/webhooks.d.ts +14 -0
  28. package/dist/cjs/anyspend/platform/resources/webhooks.js +33 -0
  29. package/dist/cjs/anyspend/platform/resources/widgets.d.ts +38 -0
  30. package/dist/cjs/anyspend/platform/resources/widgets.js +31 -0
  31. package/dist/cjs/anyspend/platform/types.d.ts +478 -0
  32. package/dist/cjs/anyspend/platform/types.js +5 -0
  33. package/dist/cjs/anyspend/platform/utils/idempotency.d.ts +4 -0
  34. package/dist/cjs/anyspend/platform/utils/idempotency.js +17 -0
  35. package/dist/cjs/anyspend/platform/utils/pagination.d.ts +12 -0
  36. package/dist/cjs/anyspend/platform/utils/pagination.js +22 -0
  37. package/dist/cjs/anyspend/react/components/AnySpend.d.ts +3 -1
  38. package/dist/cjs/anyspend/react/components/AnySpend.js +128 -11
  39. package/dist/cjs/anyspend/react/components/checkout/FiatCheckoutPanel.js +13 -12
  40. package/dist/cjs/anyspend/react/components/checkout/KycGate.d.ts +11 -0
  41. package/dist/cjs/anyspend/react/components/checkout/KycGate.js +181 -0
  42. package/dist/cjs/anyspend/react/hooks/index.d.ts +1 -0
  43. package/dist/cjs/anyspend/react/hooks/index.js +1 -0
  44. package/dist/cjs/anyspend/react/hooks/useAnyspendCreateOnrampOrder.js +9 -0
  45. package/dist/cjs/anyspend/react/hooks/useKycStatus.d.ts +42 -0
  46. package/dist/cjs/anyspend/react/hooks/useKycStatus.js +113 -0
  47. package/dist/cjs/anyspend/services/anyspend.d.ts +3 -1
  48. package/dist/cjs/anyspend/services/anyspend.js +2 -1
  49. package/dist/cjs/global-account/react/components/B3DynamicModal.js +1 -1
  50. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.js +3 -3
  51. package/dist/cjs/global-account/react/hooks/useAuth.js +1 -1
  52. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +4 -0
  53. package/dist/cjs/global-account/react/stores/useModalStore.js +2 -0
  54. package/dist/cjs/global-account/react/utils/createWagmiConfig.d.ts +18 -0
  55. package/dist/cjs/global-account/react/utils/createWagmiConfig.js +17 -0
  56. package/dist/esm/anyspend/platform/client.d.ts +35 -0
  57. package/dist/esm/anyspend/platform/client.js +153 -0
  58. package/dist/esm/anyspend/platform/errors.d.ts +38 -0
  59. package/dist/esm/anyspend/platform/errors.js +67 -0
  60. package/dist/esm/anyspend/platform/index.d.ts +87 -0
  61. package/dist/esm/anyspend/platform/index.js +75 -0
  62. package/dist/esm/anyspend/platform/resources/analytics.d.ts +7 -0
  63. package/dist/esm/anyspend/platform/resources/analytics.js +8 -0
  64. package/dist/esm/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
  65. package/dist/esm/anyspend/platform/resources/checkout-sessions.js +23 -0
  66. package/dist/esm/anyspend/platform/resources/customers.d.ts +19 -0
  67. package/dist/esm/anyspend/platform/resources/customers.js +30 -0
  68. package/dist/esm/anyspend/platform/resources/discount-codes.d.ts +29 -0
  69. package/dist/esm/anyspend/platform/resources/discount-codes.js +27 -0
  70. package/dist/esm/anyspend/platform/resources/events.d.ts +14 -0
  71. package/dist/esm/anyspend/platform/resources/events.js +12 -0
  72. package/dist/esm/anyspend/platform/resources/notifications.d.ts +18 -0
  73. package/dist/esm/anyspend/platform/resources/notifications.js +23 -0
  74. package/dist/esm/anyspend/platform/resources/organization.d.ts +17 -0
  75. package/dist/esm/anyspend/platform/resources/organization.js +11 -0
  76. package/dist/esm/anyspend/platform/resources/payment-links.d.ts +21 -0
  77. package/dist/esm/anyspend/platform/resources/payment-links.js +45 -0
  78. package/dist/esm/anyspend/platform/resources/products.d.ts +27 -0
  79. package/dist/esm/anyspend/platform/resources/products.js +27 -0
  80. package/dist/esm/anyspend/platform/resources/transactions.d.ts +11 -0
  81. package/dist/esm/anyspend/platform/resources/transactions.js +21 -0
  82. package/dist/esm/anyspend/platform/resources/webhooks.d.ts +14 -0
  83. package/dist/esm/anyspend/platform/resources/webhooks.js +29 -0
  84. package/dist/esm/anyspend/platform/resources/widgets.d.ts +38 -0
  85. package/dist/esm/anyspend/platform/resources/widgets.js +27 -0
  86. package/dist/esm/anyspend/platform/types.d.ts +478 -0
  87. package/dist/esm/anyspend/platform/types.js +4 -0
  88. package/dist/esm/anyspend/platform/utils/idempotency.d.ts +4 -0
  89. package/dist/esm/anyspend/platform/utils/idempotency.js +14 -0
  90. package/dist/esm/anyspend/platform/utils/pagination.d.ts +12 -0
  91. package/dist/esm/anyspend/platform/utils/pagination.js +19 -0
  92. package/dist/esm/anyspend/react/components/AnySpend.d.ts +3 -1
  93. package/dist/esm/anyspend/react/components/AnySpend.js +129 -12
  94. package/dist/esm/anyspend/react/components/checkout/FiatCheckoutPanel.js +13 -12
  95. package/dist/esm/anyspend/react/components/checkout/KycGate.d.ts +11 -0
  96. package/dist/esm/anyspend/react/components/checkout/KycGate.js +145 -0
  97. package/dist/esm/anyspend/react/hooks/index.d.ts +1 -0
  98. package/dist/esm/anyspend/react/hooks/index.js +1 -0
  99. package/dist/esm/anyspend/react/hooks/useAnyspendCreateOnrampOrder.js +9 -0
  100. package/dist/esm/anyspend/react/hooks/useKycStatus.d.ts +42 -0
  101. package/dist/esm/anyspend/react/hooks/useKycStatus.js +107 -0
  102. package/dist/esm/anyspend/services/anyspend.d.ts +3 -1
  103. package/dist/esm/anyspend/services/anyspend.js +2 -1
  104. package/dist/esm/global-account/react/components/B3DynamicModal.js +1 -1
  105. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.js +3 -3
  106. package/dist/esm/global-account/react/hooks/useAuth.js +2 -2
  107. package/dist/esm/global-account/react/stores/useModalStore.d.ts +4 -0
  108. package/dist/esm/global-account/react/stores/useModalStore.js +2 -0
  109. package/dist/esm/global-account/react/utils/createWagmiConfig.d.ts +18 -0
  110. package/dist/esm/global-account/react/utils/createWagmiConfig.js +16 -0
  111. package/dist/styles/index.css +1 -1
  112. package/dist/types/anyspend/platform/client.d.ts +35 -0
  113. package/dist/types/anyspend/platform/errors.d.ts +38 -0
  114. package/dist/types/anyspend/platform/index.d.ts +87 -0
  115. package/dist/types/anyspend/platform/resources/analytics.d.ts +7 -0
  116. package/dist/types/anyspend/platform/resources/checkout-sessions.d.ts +17 -0
  117. package/dist/types/anyspend/platform/resources/customers.d.ts +19 -0
  118. package/dist/types/anyspend/platform/resources/discount-codes.d.ts +29 -0
  119. package/dist/types/anyspend/platform/resources/events.d.ts +14 -0
  120. package/dist/types/anyspend/platform/resources/notifications.d.ts +18 -0
  121. package/dist/types/anyspend/platform/resources/organization.d.ts +17 -0
  122. package/dist/types/anyspend/platform/resources/payment-links.d.ts +21 -0
  123. package/dist/types/anyspend/platform/resources/products.d.ts +27 -0
  124. package/dist/types/anyspend/platform/resources/transactions.d.ts +11 -0
  125. package/dist/types/anyspend/platform/resources/webhooks.d.ts +14 -0
  126. package/dist/types/anyspend/platform/resources/widgets.d.ts +38 -0
  127. package/dist/types/anyspend/platform/types.d.ts +478 -0
  128. package/dist/types/anyspend/platform/utils/idempotency.d.ts +4 -0
  129. package/dist/types/anyspend/platform/utils/pagination.d.ts +12 -0
  130. package/dist/types/anyspend/react/components/AnySpend.d.ts +3 -1
  131. package/dist/types/anyspend/react/components/checkout/KycGate.d.ts +11 -0
  132. package/dist/types/anyspend/react/hooks/index.d.ts +1 -0
  133. package/dist/types/anyspend/react/hooks/useKycStatus.d.ts +42 -0
  134. package/dist/types/anyspend/services/anyspend.d.ts +3 -1
  135. package/dist/types/global-account/react/stores/useModalStore.d.ts +4 -0
  136. package/dist/types/global-account/react/utils/createWagmiConfig.d.ts +18 -0
  137. package/package.json +7 -1
  138. package/src/anyspend/platform/client.ts +198 -0
  139. package/src/anyspend/platform/errors.ts +92 -0
  140. package/src/anyspend/platform/index.ts +129 -0
  141. package/src/anyspend/platform/resources/analytics.ts +10 -0
  142. package/src/anyspend/platform/resources/checkout-sessions.ts +36 -0
  143. package/src/anyspend/platform/resources/customers.ts +54 -0
  144. package/src/anyspend/platform/resources/discount-codes.ts +63 -0
  145. package/src/anyspend/platform/resources/events.ts +22 -0
  146. package/src/anyspend/platform/resources/notifications.ts +37 -0
  147. package/src/anyspend/platform/resources/organization.ts +24 -0
  148. package/src/anyspend/platform/resources/payment-links.ts +74 -0
  149. package/src/anyspend/platform/resources/products.ts +59 -0
  150. package/src/anyspend/platform/resources/transactions.ts +33 -0
  151. package/src/anyspend/platform/resources/webhooks.ts +47 -0
  152. package/src/anyspend/platform/resources/widgets.ts +63 -0
  153. package/src/anyspend/platform/types.ts +532 -0
  154. package/src/anyspend/platform/utils/idempotency.ts +15 -0
  155. package/src/anyspend/platform/utils/pagination.ts +32 -0
  156. package/src/anyspend/react/components/AnySpend.tsx +150 -13
  157. package/src/anyspend/react/components/checkout/FiatCheckoutPanel.tsx +16 -13
  158. package/src/anyspend/react/components/checkout/KycGate.tsx +351 -0
  159. package/src/anyspend/react/hooks/index.ts +1 -0
  160. package/src/anyspend/react/hooks/useAnyspendCreateOnrampOrder.ts +10 -0
  161. package/src/anyspend/react/hooks/useKycStatus.ts +140 -0
  162. package/src/anyspend/services/anyspend.ts +4 -0
  163. package/src/global-account/react/components/B3DynamicModal.tsx +0 -2
  164. package/src/global-account/react/components/ManageAccount/BottomNavigation.tsx +7 -7
  165. package/src/global-account/react/hooks/useAuth.ts +2 -2
  166. package/src/global-account/react/stores/useModalStore.ts +6 -0
  167. package/src/global-account/react/utils/createWagmiConfig.tsx +18 -0
@@ -27,6 +27,8 @@ import {
27
27
  toast,
28
28
  TransitionPanel,
29
29
  useAccountWallet,
30
+ useAuth,
31
+ useAuthStore,
30
32
  useB3Config,
31
33
  useModalStore,
32
34
  useProfile,
@@ -64,6 +66,9 @@ import { FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaym
64
66
  import { GasIndicator } from "./common/GasIndicator";
65
67
  import { OrderDetails, OrderDetailsLoadingView } from "./common/OrderDetails";
66
68
  import { OrderHistory } from "./common/OrderHistory";
69
+ import { KycGate } from "./checkout/KycGate";
70
+ import { useWalletAuthHeaders } from "../hooks/useKycStatus";
71
+ import { LoginStep } from "@b3dotfun/sdk/global-account/react/components/SignInWithB3/steps/LoginStep";
67
72
  import { PanelOnramp } from "./common/PanelOnramp";
68
73
  import { PanelOnrampPayment } from "./common/PanelOnrampPayment";
69
74
  import { PointsDetailPanel } from "./common/PointsDetailPanel";
@@ -94,6 +99,8 @@ export enum PanelView {
94
99
  POINTS_DETAIL,
95
100
  FEE_DETAIL,
96
101
  DIRECT_TRANSFER_SUCCESS,
102
+ FIAT_KYC,
103
+ FIAT_AUTH,
97
104
  }
98
105
 
99
106
  const ANYSPEND_RECIPIENTS_KEY = "anyspend_recipients";
@@ -209,6 +216,16 @@ function AnySpendInner({
209
216
  const { partnerId } = useB3Config();
210
217
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
211
218
  const setB3ModalOpen = useModalStore(state => state.setB3ModalOpen);
219
+ const { isAuthenticated } = useAuth();
220
+ // KYC approval is tracked per-session so we only prompt the wallet
221
+ // signature when the user actually clicks Buy, not on panel mount.
222
+ // useRef so handleFiatOrder can read the updated value synchronously
223
+ // in the same frame that onStatusResolved sets it (setState is async).
224
+ const kycApprovedRef = useRef(false);
225
+ // Pre-warm wallet auth headers inside user-gesture context (button click)
226
+ // so the signing prompt fires before we navigate away — browsers block
227
+ // wallet popups triggered from async/non-gesture contexts (React Query queryFn).
228
+ const { getHeaders: getKycHeaders } = useWalletAuthHeaders();
212
229
 
213
230
  // Determine if we're in "buy mode" based on whether destination token props are provided
214
231
  const isBuyMode = !!(destinationTokenAddress && destinationTokenChainId);
@@ -236,7 +253,17 @@ function AnySpendInner({
236
253
  // Track previous panel for proper back navigation
237
254
  const previousPanel = useRef<PanelView>(PanelView.MAIN);
238
255
 
239
- const [activeTab, setActiveTab] = useState<"crypto" | "fiat">(defaultActiveTab);
256
+ const [activeTab, setActiveTab] = useState<"crypto" | "fiat">(() => {
257
+ if (typeof window !== "undefined") {
258
+ const stored = sessionStorage.getItem("anyspend_active_tab") as "crypto" | "fiat" | null;
259
+ if (stored === "crypto" || stored === "fiat") return stored;
260
+ }
261
+ return defaultActiveTab;
262
+ });
263
+
264
+ useEffect(() => {
265
+ sessionStorage.setItem("anyspend_active_tab", activeTab);
266
+ }, [activeTab]);
240
267
 
241
268
  const [orderId, setOrderId] = useState<string | undefined>(loadOrder);
242
269
  const [directTransferTxHash, setDirectTransferTxHash] = useState<string | undefined>();
@@ -273,10 +300,20 @@ function AnySpendInner({
273
300
  resetPaymentMethods,
274
301
  } = useCryptoPaymentMethodState();
275
302
 
276
- const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState<FiatPaymentMethod>(FiatPaymentMethod.NONE);
303
+ const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState<FiatPaymentMethod>(() => {
304
+ if (typeof window !== "undefined") {
305
+ const stored = sessionStorage.getItem("anyspend_fiat_method") as FiatPaymentMethod | null;
306
+ if (stored && Object.values(FiatPaymentMethod).includes(stored)) return stored;
307
+ }
308
+ return FiatPaymentMethod.NONE;
309
+ });
277
310
  // const [newRecipientAddress, setNewRecipientAddress] = useState("");
278
311
  // const recipientInputRef = useRef<HTMLInputElement>(null);
279
312
 
313
+ useEffect(() => {
314
+ sessionStorage.setItem("anyspend_fiat_method", selectedFiatPaymentMethod);
315
+ }, [selectedFiatPaymentMethod]);
316
+
280
317
  // Get initial chain IDs from URL or defaults
281
318
  const initialSrcChainId = sourceChainId || parseInt(searchParams.get("fromChainId") || "0") || mainnet.id;
282
319
  const initialDstChainId =
@@ -297,11 +334,27 @@ function AnySpendInner({
297
334
  const { data: srcTokenMetadata } = useTokenData(selectedSrcToken?.chainId, selectedSrcToken?.address);
298
335
  const [srcAmount, setSrcAmount] = useState<string>(searchParams.get("fromAmount") || "0");
299
336
 
300
- // State for onramp amount
301
- const [srcAmountOnRamp, setSrcAmountOnRamp] = useState<string>(searchParams.get("fromAmount") || "5");
337
+ // State for onramp amount — persisted in sessionStorage so it survives Persona KYC roundtrip
338
+ const [srcAmountOnRamp, setSrcAmountOnRamp] = useState<string>(() => {
339
+ if (typeof window !== "undefined") {
340
+ const stored = sessionStorage.getItem("anyspend_fiat_amount");
341
+ if (stored) return stored;
342
+ }
343
+ return searchParams.get("fromAmount") || "5";
344
+ });
302
345
 
303
- // State for destination chain/token selection
304
- const [selectedDstChainId, setSelectedDstChainId] = useState<number>(initialDstChainId);
346
+ useEffect(() => {
347
+ sessionStorage.setItem("anyspend_fiat_amount", srcAmountOnRamp);
348
+ }, [srcAmountOnRamp]);
349
+
350
+ // State for destination chain/token selection (sync effects come after state declarations below) — persisted in sessionStorage for Persona KYC roundtrip
351
+ const [selectedDstChainId, setSelectedDstChainId] = useState<number>(() => {
352
+ if (!isBuyMode && typeof window !== "undefined") {
353
+ const stored = sessionStorage.getItem("anyspend_dst_chain_id");
354
+ if (stored) return parseInt(stored, 10);
355
+ }
356
+ return initialDstChainId;
357
+ });
305
358
  // Helper to check if address is Hyperliquid USDC (supports both 34-char and 42-char formats)
306
359
  const isHyperliquidUSDCAddress = (address?: string) =>
307
360
  eqci(address, HYPERLIQUID_USDC_ADDRESS) || eqci(address, ZERO_ADDRESS);
@@ -323,12 +376,29 @@ function AnySpendInner({
323
376
  defaultToken: defaultDstToken,
324
377
  prefix: "to",
325
378
  });
326
- const [selectedDstToken, setSelectedDstToken] = useState<components["schemas"]["Token"]>(
327
- isBuyMode ? defaultDstToken : dstTokenFromUrl,
328
- );
379
+ const [selectedDstToken, setSelectedDstToken] = useState<components["schemas"]["Token"]>(() => {
380
+ if (!isBuyMode && typeof window !== "undefined") {
381
+ const stored = sessionStorage.getItem("anyspend_dst_token");
382
+ if (stored) {
383
+ try {
384
+ return JSON.parse(stored) as components["schemas"]["Token"];
385
+ } catch {}
386
+ }
387
+ }
388
+ return isBuyMode ? defaultDstToken : dstTokenFromUrl;
389
+ });
329
390
  const { data: dstTokenMetadata } = useTokenData(selectedDstToken?.chainId, selectedDstToken?.address);
330
391
  const [dstAmount, setDstAmount] = useState<string>(searchParams.get("toAmount") || "");
331
392
 
393
+ // Sync dst chain/token to sessionStorage so they survive Persona KYC roundtrip
394
+ useEffect(() => {
395
+ if (!isBuyMode) sessionStorage.setItem("anyspend_dst_chain_id", selectedDstChainId.toString());
396
+ }, [selectedDstChainId, isBuyMode]);
397
+
398
+ useEffect(() => {
399
+ if (!isBuyMode) sessionStorage.setItem("anyspend_dst_token", JSON.stringify(selectedDstToken));
400
+ }, [selectedDstToken, isBuyMode]);
401
+
332
402
  const [isSrcInputDirty, setIsSrcInputDirty] = useState(true);
333
403
  // Add refs to track if we've applied metadata
334
404
  const appliedSrcMetadataRef = useRef(false);
@@ -728,6 +798,17 @@ function AnySpendInner({
728
798
  // Call onSuccess when order is executed
729
799
  useOnOrderSuccess({ orderData: oat, orderId, onSuccess });
730
800
 
801
+ // Clear all persisted selection state once an order is submitted — next open starts fresh
802
+ useEffect(() => {
803
+ if (orderId) {
804
+ sessionStorage.removeItem("anyspend_fiat_amount");
805
+ sessionStorage.removeItem("anyspend_active_tab");
806
+ sessionStorage.removeItem("anyspend_fiat_method");
807
+ sessionStorage.removeItem("anyspend_dst_chain_id");
808
+ sessionStorage.removeItem("anyspend_dst_token");
809
+ }
810
+ }, [orderId]);
811
+
731
812
  const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
732
813
  onSuccess: data => {
733
814
  const orderId = data.data.id;
@@ -817,8 +898,8 @@ function AnySpendInner({
817
898
  if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
818
899
  return { text: "Select payment method", disable: false, error: false, loading: false };
819
900
  }
820
- // If payment method is selected, show "Buy"
821
- return { text: "Buy", disable: false, error: false, loading: false };
901
+ // If payment method is selected, show "Continue"
902
+ return { text: "Continue", disable: false, error: false, loading: false };
822
903
  }
823
904
 
824
905
  if (activeTab === "crypto") {
@@ -845,7 +926,7 @@ function AnySpendInner({
845
926
  }
846
927
  }
847
928
 
848
- return { text: "Buy", disable: false, error: false, loading: false };
929
+ return { text: "Continue", disable: false, error: false, loading: false };
849
930
  }, [
850
931
  activeInputAmountInWei,
851
932
  isSameChainSameToken,
@@ -1028,7 +1109,22 @@ function AnySpendInner({
1028
1109
  vendor = "stripe";
1029
1110
  paymentMethodString = "";
1030
1111
  } else if (paymentMethod === FiatPaymentMethod.STRIPE_WEB2) {
1031
- // Stripe embedded payment form
1112
+ // Stripe embedded payment form requires authentication + KYC
1113
+ // Read from store directly to avoid stale closure when called from onLoginSuccess callback
1114
+ const currentlyAuthenticated = useAuthStore.getState().isAuthenticated;
1115
+ if (!currentlyAuthenticated) {
1116
+ navigateToPanel(PanelView.FIAT_AUTH, "forward");
1117
+ return;
1118
+ }
1119
+ if (!kycApprovedRef.current) {
1120
+ // Pre-sign the KYC auth message NOW (user-gesture context) so the
1121
+ // result is cached before useKycStatus fires its queryFn inside the
1122
+ // FIAT_KYC panel. Wallets/browsers block signing prompts from async
1123
+ // (non-gesture) contexts, which is exactly what React Query uses.
1124
+ await getKycHeaders().catch(() => {});
1125
+ navigateToPanel(PanelView.FIAT_KYC, "forward");
1126
+ return;
1127
+ }
1032
1128
  if (!stripeWeb2Support.isSupport) {
1033
1129
  toast.error("Pay with Card not available");
1034
1130
  return;
@@ -1147,6 +1243,15 @@ function AnySpendInner({
1147
1243
  };
1148
1244
  }, [activePanel, navigateBack]);
1149
1245
 
1246
+ // When auth completes while on the FIAT_AUTH panel, navigate back and retry the order
1247
+ useEffect(() => {
1248
+ if (isAuthenticated && activePanel === PanelView.FIAT_AUTH) {
1249
+ navigateBack();
1250
+ handleFiatOrder(selectedFiatPaymentMethod);
1251
+ }
1252
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1253
+ }, [isAuthenticated]);
1254
+
1150
1255
  const historyView = (
1151
1256
  <div className={"mx-auto flex w-[560px] max-w-full flex-col items-center"}>
1152
1257
  <OrderHistory mode={mode} onBack={navigateBack} onSelectOrder={onSelectOrder} />
@@ -1593,6 +1698,32 @@ function AnySpendInner({
1593
1698
  </div>
1594
1699
  );
1595
1700
 
1701
+ const kycView = (
1702
+ <div className="mx-auto flex w-full max-w-[460px] flex-col gap-4 px-5 pt-5">
1703
+ <KycGate
1704
+ enabled={activePanel === PanelView.FIAT_KYC}
1705
+ onStatusResolved={approved => {
1706
+ if (approved) {
1707
+ kycApprovedRef.current = true;
1708
+ navigateBack();
1709
+ handleFiatOrder(selectedFiatPaymentMethod);
1710
+ }
1711
+ }}
1712
+ />
1713
+ </div>
1714
+ );
1715
+
1716
+ const authView = (
1717
+ <div className="mx-auto w-full max-w-[460px]">
1718
+ <LoginStep
1719
+ chain={baseChain}
1720
+ onSuccess={async () => {
1721
+ // isAuthenticated will be true at this point — the useEffect below handles navigation
1722
+ }}
1723
+ />
1724
+ </div>
1725
+ );
1726
+
1596
1727
  // Add tabs to the main component when no order is loaded
1597
1728
  return (
1598
1729
  <StyleRoot>
@@ -1667,6 +1798,12 @@ function AnySpendInner({
1667
1798
  <div key="direct-transfer-success-view" className={cn(mode === "page" && "p-6")}>
1668
1799
  {directTransferSuccessView}
1669
1800
  </div>,
1801
+ <div key="fiat-kyc-view" className={cn(mode === "page" && "p-6")}>
1802
+ {kycView}
1803
+ </div>,
1804
+ <div key="fiat-auth-view" className={cn(mode === "page" && "p-6")}>
1805
+ {authView}
1806
+ </div>,
1670
1807
  ]}
1671
1808
  </TransitionPanel>
1672
1809
  </div>
@@ -17,6 +17,7 @@ import { Loader2, Lock } from "lucide-react";
17
17
  import { AnimatePresence, motion } from "motion/react";
18
18
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
19
19
  import type { AnySpendCheckoutClasses } from "./AnySpendCheckout";
20
+ import { KycGate } from "./KycGate";
20
21
 
21
22
  interface FiatCheckoutPanelProps {
22
23
  recipientAddress: string;
@@ -89,18 +90,6 @@ export function FiatCheckoutPanel({
89
90
  return parseFloat(raw).toFixed(2);
90
91
  }, [isStablecoin, formattedAmount, anyspendQuote]);
91
92
 
92
- // Debug: log computed values for Stripe flow diagnostics
93
- useEffect(() => {
94
- console.log("@@fiat-checkout:debug", {
95
- totalAmount,
96
- formattedAmount,
97
- isStablecoin,
98
- isLoadingAnyspendQuote,
99
- quoteAmount: anyspendQuote?.data?.currencyIn?.amount,
100
- usdAmount,
101
- });
102
- }, [totalAmount, formattedAmount, isStablecoin, isLoadingAnyspendQuote, anyspendQuote, usdAmount]);
103
-
104
93
  const {
105
94
  geoData,
106
95
  stripeOnrampSupport,
@@ -108,6 +97,13 @@ export function FiatCheckoutPanel({
108
97
  isLoading: isLoadingGeo,
109
98
  } = useGeoOnrampOptions(usdAmount || "0");
110
99
 
100
+ // KYC state
101
+ const [kycApproved, setKycApproved] = useState(false);
102
+
103
+ const handleKycResolved = useCallback((approved: boolean) => {
104
+ setKycApproved(approved);
105
+ }, []);
106
+
111
107
  // Order state
112
108
  const [orderId, setOrderId] = useState<string | null>(null);
113
109
  const [stripePaymentIntentId, setStripePaymentIntentId] = useState<string | null>(null);
@@ -131,7 +127,7 @@ export function FiatCheckoutPanel({
131
127
  },
132
128
  });
133
129
 
134
- // Auto-create onramp order when Stripe Web2 is supported and all data is ready
130
+ // Auto-create onramp order when Stripe Web2 is supported, KYC approved, and all data is ready
135
131
  useEffect(() => {
136
132
  if (
137
133
  !isLoadingGeo &&
@@ -139,6 +135,7 @@ export function FiatCheckoutPanel({
139
135
  usdAmount &&
140
136
  parseFloat(usdAmount) > 0 &&
141
137
  stripeWeb2Support?.isSupport &&
138
+ kycApproved &&
142
139
  !orderCreatedRef.current &&
143
140
  !orderId &&
144
141
  !isCreatingOrder &&
@@ -182,6 +179,7 @@ export function FiatCheckoutPanel({
182
179
  isLoadingAnyspendQuote,
183
180
  usdAmount,
184
181
  stripeWeb2Support,
182
+ kycApproved,
185
183
  orderId,
186
184
  isCreatingOrder,
187
185
  orderError,
@@ -232,6 +230,11 @@ export function FiatCheckoutPanel({
232
230
  );
233
231
  }
234
232
 
233
+ // KYC gate — shown before order creation when verification is needed
234
+ if (!kycApproved) {
235
+ return <KycGate themeColor={themeColor} classes={classes} enabled onStatusResolved={handleKycResolved} />;
236
+ }
237
+
235
238
  // Order creation error - show with retry
236
239
  if (orderError) {
237
240
  return (