@unifold/connect-react 0.1.76 → 0.1.78

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.
package/dist/index.mjs CHANGED
@@ -6093,12 +6093,12 @@ import {
6093
6093
  generatePrefixedKSUID as generatePrefixedKSUID2,
6094
6094
  DepositEventType as DepositEventType2
6095
6095
  } from "@unifold/core";
6096
- import { useEffect as useEffect32 } from "react";
6097
6096
  import { useQuery } from "@tanstack/react-query";
6098
6097
  import {
6099
6098
  createDepositAddress,
6100
6099
  isDepositAddressValidationError
6101
6100
  } from "@unifold/core";
6101
+ import { useEffect as useEffect32 } from "react";
6102
6102
  import * as React52 from "react";
6103
6103
  import { jsx as jsx52 } from "react/jsx-runtime";
6104
6104
  import { useEffect as useEffect42, useState as useState32 } from "react";
@@ -6625,7 +6625,7 @@ function generateKSUID() {
6625
6625
  function generatePrefixedKSUID(prefix) {
6626
6626
  return `${prefix}_${generateKSUID()}`;
6627
6627
  }
6628
- var PACKAGE_VERSION = "0.1.76";
6628
+ var PACKAGE_VERSION = "0.1.78";
6629
6629
  var LIBRARY_NAME = "@unifold/analytics";
6630
6630
  var DEFAULT_DEDUP_MS = 500;
6631
6631
  var SESSION_PREFIX = "asess";
@@ -6715,8 +6715,12 @@ var EventTracker = class {
6715
6715
  }
6716
6716
  /**
6717
6717
  * Associate subsequent events with an internal Unifold user.id
6718
- * (`user_<ksuid>`). Pass `null` to clear. Usually called once the
6719
- * deposit-addresses response returns the id.
6718
+ * (`user_<ksuid>`). Pass `null` to clear.
6719
+ *
6720
+ * The tracker is shared across flows and outlives any one journey, so a
6721
+ * journey stamps its own user at the start — with the id if it already
6722
+ * knows one, `null` if it doesn't — rather than inheriting whatever the
6723
+ * previous journey left here.
6720
6724
  */
6721
6725
  setUserId(userId) {
6722
6726
  this.userId = userId || void 0;
@@ -6727,8 +6731,8 @@ var EventTracker = class {
6727
6731
  * {@link EventTracker.endSession} carries it.
6728
6732
  *
6729
6733
  * Does not touch `userId`: the internal `user_<ksuid>` is attached separately
6730
- * via {@link EventTracker.setUserId} once the deposit-addresses response
6731
- * returns, and persists until the host replaces it.
6734
+ * via {@link EventTracker.setUserId}, and persists until the host replaces
6735
+ * it which the SDK's modals do on every journey start.
6732
6736
  */
6733
6737
  startSession() {
6734
6738
  this.sessionId = generatePrefixedKSUID(SESSION_PREFIX);
@@ -12819,7 +12823,7 @@ import {
12819
12823
  generatePrefixedKSUID as generatePrefixedKSUID10
12820
12824
  } from "@unifold/core";
12821
12825
  import { Fragment as Fragment17, jsx as jsx722, jsxs as jsxs62 } from "react/jsx-runtime";
12822
- import { useState as useState49, useEffect as useEffect48, useLayoutEffect as useLayoutEffect42, useCallback as useCallback17, useMemo as useMemo21, useRef as useRef20 } from "react";
12826
+ import { useState as useState49, useEffect as useEffect47, useLayoutEffect as useLayoutEffect42, useCallback as useCallback17, useMemo as useMemo21, useRef as useRef20 } from "react";
12823
12827
  import { useQuery as useQuery21 } from "@tanstack/react-query";
12824
12828
  import {
12825
12829
  getSupportedDestinationTokens
@@ -12840,7 +12844,7 @@ import {
12840
12844
  ActionType as ActionType5
12841
12845
  } from "@unifold/core";
12842
12846
  import { jsx as jsx73, jsxs as jsxs63 } from "react/jsx-runtime";
12843
- import { useState as useState47, useCallback as useCallback16, useMemo as useMemo20, useEffect as useEffect46 } from "react";
12847
+ import { useState as useState47, useCallback as useCallback16, useMemo as useMemo20, useEffect as useEffect45 } from "react";
12844
12848
  import {
12845
12849
  checkHypercoreActivation as checkHypercoreActivation3
12846
12850
  } from "@unifold/core";
@@ -12852,13 +12856,12 @@ import {
12852
12856
  } from "@unifold/core";
12853
12857
  import { useMemo as useMemo19 } from "react";
12854
12858
  import { ActionType as ActionType6 } from "@unifold/core";
12855
- import { useEffect as useEffect45 } from "react";
12856
12859
  import { useQuery as useQuery26 } from "@tanstack/react-query";
12857
12860
  import { getDepositAddress } from "@unifold/core";
12858
12861
  import { Fragment as Fragment18, jsx as jsx74, jsxs as jsxs64 } from "react/jsx-runtime";
12859
12862
  import { ExecutionStatus as ExecutionStatus7, getIconUrl as getIconUrl5 } from "@unifold/core";
12860
12863
  import { jsx as jsx75, jsxs as jsxs65 } from "react/jsx-runtime";
12861
- import { useState as useState48, useEffect as useEffect47 } from "react";
12864
+ import { useState as useState48, useEffect as useEffect46 } from "react";
12862
12865
  import { Fragment as Fragment19, jsx as jsx76, jsxs as jsxs66 } from "react/jsx-runtime";
12863
12866
  import {
12864
12867
  createDepositAddress as createDepositAddress2,
@@ -13268,6 +13271,9 @@ var en_default = {
13268
13271
  transactionBreakdown: "Transaction breakdown",
13269
13272
  networkFee: "Network fee",
13270
13273
  confirmOrder: "Confirm Order",
13274
+ mfaEnrollmentTitle: "Enable SMS or Authy 2FA",
13275
+ mfaEnrollmentMessage: "Please make sure you enable SMS or Authy 2FA in your Coinbase account. Press Continue after you enable it.",
13276
+ mfaEnrollmentSettingsLink: "Open Coinbase security settings",
13271
13277
  termsNoticePrefix: "By clicking on Confirm Order, you agree to our ",
13272
13278
  termsNoticeLink: "terms",
13273
13279
  termsNoticeSuffix: "."
@@ -13398,7 +13404,12 @@ var en_default = {
13398
13404
  prefix: "By continuing, you agree to Coinbase's ",
13399
13405
  separator: ", ",
13400
13406
  lastSeparator: ", and ",
13401
- suffix: ". Coinbase is the regulated provider of this fiat-to-crypto onramp."
13407
+ suffix: ".",
13408
+ agreements: {
13409
+ guest_checkout_terms: "Terms of Service",
13410
+ user_agreement: "User Agreement",
13411
+ privacy_policy: "Privacy Policy"
13412
+ }
13402
13413
  },
13403
13414
  errors: {
13404
13415
  rateLimited: "Too many attempts. Please wait a few minutes and try again.",
@@ -14057,6 +14068,9 @@ var zh_default = {
14057
14068
  transactionBreakdown: "\u4EA4\u6613\u660E\u7EC6",
14058
14069
  networkFee: "\u7F51\u7EDC\u624B\u7EED\u8D39",
14059
14070
  confirmOrder: "\u786E\u8BA4\u8BA2\u5355",
14071
+ mfaEnrollmentTitle: "\u8BF7\u542F\u7528\u77ED\u4FE1\u6216 Authy \u53CC\u91CD\u9A8C\u8BC1",
14072
+ mfaEnrollmentMessage: "\u8BF7\u786E\u8BA4\u60A8\u5DF2\u5728 Coinbase \u8D26\u6237\u4E2D\u542F\u7528\u77ED\u4FE1\u6216 Authy \u53CC\u91CD\u9A8C\u8BC1\u3002\u542F\u7528\u540E\u8BF7\u6309\u7EE7\u7EED\u3002",
14073
+ mfaEnrollmentSettingsLink: "\u6253\u5F00 Coinbase \u5B89\u5168\u8BBE\u7F6E",
14060
14074
  termsNoticePrefix: "\u70B9\u51FB\u201C\u786E\u8BA4\u8BA2\u5355\u201D\u5373\u8868\u793A\u60A8\u540C\u610F\u6211\u4EEC\u7684",
14061
14075
  termsNoticeLink: "\u6761\u6B3E",
14062
14076
  termsNoticeSuffix: "\u3002"
@@ -14187,7 +14201,12 @@ var zh_default = {
14187
14201
  prefix: "\u7EE7\u7EED\u5373\u8868\u793A\u60A8\u540C\u610F Coinbase \u7684",
14188
14202
  separator: "\u3001",
14189
14203
  lastSeparator: "\u548C",
14190
- suffix: "\u3002Coinbase \u662F\u672C\u6CD5\u5E01\u5151\u52A0\u5BC6\u8D27\u5E01\u5145\u503C\u670D\u52A1\u7684\u53D7\u76D1\u7BA1\u63D0\u4F9B\u65B9\u3002"
14204
+ suffix: "\u3002",
14205
+ agreements: {
14206
+ guest_checkout_terms: "\u670D\u52A1\u6761\u6B3E",
14207
+ user_agreement: "\u7528\u6237\u534F\u8BAE",
14208
+ privacy_policy: "\u9690\u79C1\u653F\u7B56"
14209
+ }
14191
14210
  },
14192
14211
  errors: {
14193
14212
  rateLimited: "\u5C1D\u8BD5\u6B21\u6570\u8FC7\u591A\u3002\u8BF7\u7A0D\u7B49\u51E0\u5206\u949F\u540E\u91CD\u8BD5\u3002",
@@ -14846,6 +14865,9 @@ var zh_TW_default = {
14846
14865
  transactionBreakdown: "\u4EA4\u6613\u660E\u7D30",
14847
14866
  networkFee: "\u7DB2\u8DEF\u624B\u7E8C\u8CBB",
14848
14867
  confirmOrder: "\u78BA\u8A8D\u8A02\u55AE",
14868
+ mfaEnrollmentTitle: "\u8ACB\u555F\u7528\u7C21\u8A0A\u6216 Authy \u96D9\u91CD\u9A57\u8B49",
14869
+ mfaEnrollmentMessage: "\u8ACB\u78BA\u8A8D\u60A8\u5DF2\u5728 Coinbase \u5E33\u6236\u4E2D\u555F\u7528\u7C21\u8A0A\u6216 Authy \u96D9\u91CD\u9A57\u8B49\u3002\u555F\u7528\u5F8C\u8ACB\u6309\u7E7C\u7E8C\u3002",
14870
+ mfaEnrollmentSettingsLink: "\u958B\u555F Coinbase \u5B89\u5168\u8A2D\u5B9A",
14849
14871
  termsNoticePrefix: "\u9EDE\u64CA\u300C\u78BA\u8A8D\u8A02\u55AE\u300D\u5373\u8868\u793A\u60A8\u540C\u610F\u6211\u5011\u7684",
14850
14872
  termsNoticeLink: "\u689D\u6B3E",
14851
14873
  termsNoticeSuffix: "\u3002"
@@ -14976,7 +14998,12 @@ var zh_TW_default = {
14976
14998
  prefix: "\u7E7C\u7E8C\u5373\u8868\u793A\u60A8\u540C\u610F Coinbase \u7684",
14977
14999
  separator: "\u3001",
14978
15000
  lastSeparator: "\u548C",
14979
- suffix: "\u3002Coinbase \u662F\u672C\u6CD5\u5E63\u514C\u52A0\u5BC6\u8CA8\u5E63\u5132\u503C\u670D\u52D9\u7684\u53D7\u76E3\u7BA1\u63D0\u4F9B\u65B9\u3002"
15001
+ suffix: "\u3002",
15002
+ agreements: {
15003
+ guest_checkout_terms: "\u670D\u52D9\u689D\u6B3E",
15004
+ user_agreement: "\u4F7F\u7528\u8005\u5354\u8B70",
15005
+ privacy_policy: "\u96B1\u79C1\u6B0A\u653F\u7B56"
15006
+ }
14980
15007
  },
14981
15008
  errors: {
14982
15009
  rateLimited: "\u5617\u8A66\u6B21\u6578\u904E\u591A\u3002\u8ACB\u7A0D\u7B49\u5E7E\u5206\u9418\u5F8C\u91CD\u8A66\u3002",
@@ -15892,6 +15919,13 @@ function useAnalytics() {
15892
15919
  );
15893
15920
  return { track, startSession, endSession, getSessionId, setUserId, subscribe };
15894
15921
  }
15922
+ function useStampInternalUserId({ internalUserId }) {
15923
+ const { setUserId } = useAnalytics();
15924
+ useEffect32(() => {
15925
+ if (!internalUserId) return;
15926
+ setUserId(internalUserId);
15927
+ }, [internalUserId, setUserId]);
15928
+ }
15895
15929
  function useDepositAddress(params) {
15896
15930
  const {
15897
15931
  userId,
@@ -15904,7 +15938,6 @@ function useDepositAddress(params) {
15904
15938
  contractCalls,
15905
15939
  enabled = true
15906
15940
  } = params;
15907
- const { setUserId } = useAnalytics();
15908
15941
  const query = useQuery({
15909
15942
  queryKey: [
15910
15943
  "unifold",
@@ -15947,11 +15980,7 @@ function useDepositAddress(params) {
15947
15980
  retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
15948
15981
  // 1s, 2s, 4s (max 10s)
15949
15982
  });
15950
- useEffect32(() => {
15951
- if (query.data?.user_id) {
15952
- setUserId(query.data.user_id);
15953
- }
15954
- }, [query.data?.user_id, setUserId]);
15983
+ useStampInternalUserId({ internalUserId: query.data?.user_id });
15955
15984
  return query;
15956
15985
  }
15957
15986
  function useDebounce(value, delay) {
@@ -18153,6 +18182,10 @@ function BuyWithCard({
18153
18182
  wallet_address: wallet.address,
18154
18183
  subdivision_code: userIpInfo?.subdivisionCode || void 0,
18155
18184
  external_id: externalId,
18185
+ // The rail this quote was priced for, so the provider opens on it. Most
18186
+ // are `card`, which is also the server default, but a local rail (e.g.
18187
+ // `upi` in India) is the whole reason its provider was quoted.
18188
+ payment_method_type: selectedProvider.payment_method_type,
18156
18189
  // Exactly one of source_amount / destination_amount (mutually exclusive):
18157
18190
  // destination mode starts the session by the fixed crypto amount (fees on
18158
18191
  // top); otherwise by the entered fiat amount.
@@ -18170,7 +18203,11 @@ function BuyWithCard({
18170
18203
  method: "card",
18171
18204
  flow_type: "deposit",
18172
18205
  provider: selectedProvider.service_provider,
18173
- amount_usd: amount
18206
+ amount_usd: amount,
18207
+ // The execution only exists once the provider's payout lands on this
18208
+ // wallet, and it carries this id — so it's the join key for a purchase
18209
+ // that starts here and never reaches flow_completed.
18210
+ deposit_wallet_id: depositWalletId
18174
18211
  });
18175
18212
  onEvent?.({
18176
18213
  id: generatePrefixedKSUID2("sevt"),
@@ -19607,6 +19644,8 @@ var BuyWithWalletPay = React82.forwardRef(
19607
19644
  const [limitUpgradeError, setLimitUpgradeError] = useState152(null);
19608
19645
  const [upgradeSubmitting, setUpgradeSubmitting] = useState152(false);
19609
19646
  const upgradeFlowAbortRef = useRef62(null);
19647
+ const applyLimitRoutingRef = useRef62(() => {
19648
+ });
19610
19649
  const [amount, setAmount] = useState152(amountUsd ?? "");
19611
19650
  const [preparedOrder, setPreparedOrder] = useState152(null);
19612
19651
  const sessionAbortRef = useRef62(null);
@@ -19741,6 +19780,14 @@ var BuyWithWalletPay = React82.forwardRef(
19741
19780
  },
19742
19781
  [email, normalizedPhone, userId]
19743
19782
  );
19783
+ const { action: initialAction, refetchWalletPayLimits } = useWalletPayInitialScreen({
19784
+ userId,
19785
+ publishableKey,
19786
+ normalizedPhone,
19787
+ userEmail,
19788
+ sessionPhoneVerified: verificationSession?.phone?.status === "verified",
19789
+ isWaiting: defaultTokenLoading || legalAgreementsLoading || userIpInfoLoading
19790
+ });
19744
19791
  const createSessionAndSendOtp = useCallback42(async () => {
19745
19792
  setView("submitting_session");
19746
19793
  setErrorMessage("");
@@ -19750,7 +19797,12 @@ var BuyWithWalletPay = React82.forwardRef(
19750
19797
  email,
19751
19798
  phone: normalizedPhone,
19752
19799
  terms_accepted: true,
19753
- email_already_verified: true
19800
+ // TODO: when the API honors `false`, this will trigger email OTP.
19801
+ // Today `false` still skips email (we don't verify it) and JWT ev
19802
+ // is null. Don't send `true` — that was a fake attest.
19803
+ email_already_verified: false
19804
+ // Coinbase stays Redis-only + JWT until bank-transfer identity
19805
+ // is live. Do not persist from this path yet.
19754
19806
  },
19755
19807
  publishableKey
19756
19808
  );
@@ -19760,6 +19812,34 @@ var BuyWithWalletPay = React82.forwardRef(
19760
19812
  }
19761
19813
  setClientSecret(session.client_secret);
19762
19814
  storeWalletPaySession();
19815
+ if (session.status === "verified") {
19816
+ const tokenRes = await exchangeOnrampVerificationToken(
19817
+ session.id,
19818
+ session.client_secret,
19819
+ publishableKey
19820
+ );
19821
+ setOnrampToken(tokenRes);
19822
+ storeWalletPaySession({
19823
+ emailVerifiedAt: session.email.verified_at,
19824
+ phoneVerifiedAt: session.phone.verified_at,
19825
+ onrampToken: tokenRes.token,
19826
+ onrampTokenExpiresAtMs: Date.now() + tokenRes.expires_in * 1e3
19827
+ });
19828
+ if (amountUsd) setAmount(amountUsd);
19829
+ try {
19830
+ const result = await refetchWalletPayLimits();
19831
+ if (result.data) {
19832
+ const nextView = getViewForLimitStatus(result.data);
19833
+ if (nextView) {
19834
+ applyLimitRoutingRef.current(nextView, result.data.upgrade_status);
19835
+ return;
19836
+ }
19837
+ }
19838
+ } catch {
19839
+ }
19840
+ setView("amount");
19841
+ return;
19842
+ }
19763
19843
  await sendOnrampVerificationOtp(session.id, "phone", session.client_secret, publishableKey);
19764
19844
  setResendCooldown(30);
19765
19845
  setView("phone_otp");
@@ -19768,19 +19848,19 @@ var BuyWithWalletPay = React82.forwardRef(
19768
19848
  setErrorMessage(prettifyVerificationError(raw));
19769
19849
  setView("phone_input");
19770
19850
  }
19771
- }, [email, normalizedPhone, publishableKey, storeWalletPaySession]);
19851
+ }, [
19852
+ email,
19853
+ normalizedPhone,
19854
+ publishableKey,
19855
+ storeWalletPaySession,
19856
+ userId,
19857
+ amountUsd,
19858
+ refetchWalletPayLimits
19859
+ ]);
19772
19860
  const clearUpgradeFields = useCallback42(() => {
19773
19861
  setSsnLast4("");
19774
19862
  setDobInput("");
19775
19863
  }, []);
19776
- const { action: initialAction, refetchWalletPayLimits } = useWalletPayInitialScreen({
19777
- userId,
19778
- publishableKey,
19779
- normalizedPhone,
19780
- userEmail,
19781
- sessionPhoneVerified: verificationSession?.phone?.status === "verified",
19782
- isWaiting: defaultTokenLoading || legalAgreementsLoading || userIpInfoLoading
19783
- });
19784
19864
  const pollLimitUpgradeStatus = useCallback42(
19785
19865
  async (signal) => {
19786
19866
  const POLL_INTERVAL_MS5 = 1500;
@@ -19891,6 +19971,7 @@ var BuyWithWalletPay = React82.forwardRef(
19891
19971
  },
19892
19972
  [startUpgradePolling]
19893
19973
  );
19974
+ applyLimitRoutingRef.current = applyLimitRouting;
19894
19975
  const hasInitializedRef = useRef62(false);
19895
19976
  useEffect122(() => {
19896
19977
  if (hasInitializedRef.current) return;
@@ -20120,7 +20201,10 @@ var BuyWithWalletPay = React82.forwardRef(
20120
20201
  track("flow_started", {
20121
20202
  method,
20122
20203
  flow_type: "deposit",
20123
- amount_usd: walletPayAmountUsd
20204
+ amount_usd: walletPayAmountUsd,
20205
+ // No execution yet — one appears when the payout lands on this
20206
+ // wallet, carrying the same id.
20207
+ deposit_wallet_id: depositWalletId
20124
20208
  });
20125
20209
  onEvent?.({
20126
20210
  id: generatePrefixedKSUID32("sevt"),
@@ -20170,6 +20254,7 @@ var BuyWithWalletPay = React82.forwardRef(
20170
20254
  defaultTokenLoading,
20171
20255
  defaultTokenError,
20172
20256
  depositWallet?.address,
20257
+ depositWalletId,
20173
20258
  userEmail,
20174
20259
  publishableKey,
20175
20260
  onEvent,
@@ -21144,7 +21229,7 @@ var FALLBACK_AGREEMENTS = [
21144
21229
  {
21145
21230
  key: "guest_checkout_terms",
21146
21231
  name: "Guest Checkout Terms of Service",
21147
- url: "https://www.coinbase.com/legal/cb-pay/onramp-guest-checkout-terms"
21232
+ url: "https://www.coinbase.com/legal/guest-checkout/us"
21148
21233
  },
21149
21234
  {
21150
21235
  key: "user_agreement",
@@ -21164,22 +21249,24 @@ function LegalDisclaimer({ legalAgreements, loading }) {
21164
21249
  return /* @__PURE__ */ jsxs14(
21165
21250
  "div",
21166
21251
  {
21167
- className: "uf-mt-3 uf-mb-3 uf-px-1 uf-space-y-1.5 uf-animate-pulse",
21252
+ className: "uf-mt-3 uf-mb-3 uf-px-1 uf-space-y-1.5 uf-animate-pulse uf-opacity-50",
21168
21253
  "aria-hidden": true,
21169
21254
  "aria-busy": "true",
21170
21255
  children: [
21171
- /* @__PURE__ */ jsx18("div", { className: "uf-h-2.5 uf-rounded uf-w-full", style: { backgroundColor: colors2.card } }),
21172
- /* @__PURE__ */ jsx18("div", { className: "uf-h-2.5 uf-rounded uf-w-11/12", style: { backgroundColor: colors2.card } }),
21173
- /* @__PURE__ */ jsx18("div", { className: "uf-h-2.5 uf-rounded uf-w-3/4", style: { backgroundColor: colors2.card } })
21256
+ /* @__PURE__ */ jsx18("div", { className: "uf-h-2 uf-rounded uf-w-full", style: { backgroundColor: colors2.card } }),
21257
+ /* @__PURE__ */ jsx18("div", { className: "uf-h-2 uf-rounded uf-w-11/12", style: { backgroundColor: colors2.card } }),
21258
+ /* @__PURE__ */ jsx18("div", { className: "uf-h-2 uf-rounded uf-w-3/4", style: { backgroundColor: colors2.card } })
21174
21259
  ]
21175
21260
  }
21176
21261
  );
21177
21262
  }
21178
21263
  const agreements = legalAgreements?.agreements ?? FALLBACK_AGREEMENTS;
21264
+ const shortLabels = t.agreements;
21265
+ const lastSeparator = t.lastSeparator.replace(/\s+$/, "\xA0");
21179
21266
  return /* @__PURE__ */ jsxs14(
21180
21267
  "p",
21181
21268
  {
21182
- className: "uf-text-[11px] uf-leading-relaxed uf-mt-3 uf-mb-3 uf-px-1",
21269
+ className: "uf-text-[10px] uf-leading-relaxed uf-mt-3 uf-mb-3 uf-opacity-60 uf-text-center",
21183
21270
  style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
21184
21271
  children: [
21185
21272
  t.prefix,
@@ -21190,12 +21277,12 @@ function LegalDisclaimer({ legalAgreements, loading }) {
21190
21277
  href: a.url,
21191
21278
  target: "_blank",
21192
21279
  rel: "noopener noreferrer",
21193
- className: "uf-underline",
21194
- style: { color: colors2.foreground },
21195
- children: a.name
21280
+ className: "uf-no-underline",
21281
+ style: { color: "inherit", textDecoration: "none", whiteSpace: "nowrap" },
21282
+ children: shortLabels[a.key] ?? a.name
21196
21283
  }
21197
21284
  ),
21198
- idx < arr.length - 2 ? t.separator : idx === arr.length - 2 ? t.lastSeparator : ""
21285
+ idx < arr.length - 2 ? t.separator : idx === arr.length - 2 ? lastSeparator : ""
21199
21286
  ] }, a.key)),
21200
21287
  t.suffix
21201
21288
  ]
@@ -21838,6 +21925,7 @@ function PayWithCashApp({
21838
21925
  destinationChainType,
21839
21926
  destinationChainId,
21840
21927
  destinationTokenAddress,
21928
+ contractCalls,
21841
21929
  cashAppIconUrl,
21842
21930
  view: controlledView,
21843
21931
  onViewChange,
@@ -21930,7 +22018,8 @@ function PayWithCashApp({
21930
22018
  destination_token_address: destinationTokenAddress,
21931
22019
  recipient_address: recipientAddress,
21932
22020
  source_amount: amount,
21933
- external_id: externalId
22021
+ external_id: externalId,
22022
+ ...contractCalls?.length ? { contract_calls: contractCalls } : {}
21934
22023
  },
21935
22024
  publishableKey
21936
22025
  );
@@ -21943,7 +22032,10 @@ function PayWithCashApp({
21943
22032
  track("flow_started", {
21944
22033
  method: "cashapp",
21945
22034
  flow_type: "deposit",
21946
- amount_usd: amount
22035
+ amount_usd: amount,
22036
+ // No execution yet — one appears when the payout lands on this
22037
+ // wallet, carrying the same id.
22038
+ deposit_wallet_id: depositWalletId
21947
22039
  });
21948
22040
  onEvent?.({
21949
22041
  id: generatePrefixedKSUID5("sevt"),
@@ -21968,6 +22060,8 @@ function PayWithCashApp({
21968
22060
  destinationChainType,
21969
22061
  destinationChainId,
21970
22062
  destinationTokenAddress,
22063
+ contractCalls,
22064
+ depositWalletId,
21971
22065
  onEvent,
21972
22066
  onDepositError,
21973
22067
  track,
@@ -22569,7 +22663,10 @@ function BankTransfer({
22569
22663
  method: "bank_transfer",
22570
22664
  flow_type: "deposit",
22571
22665
  provider: request.service_provider,
22572
- amount_usd: request.source_amount
22666
+ amount_usd: request.source_amount,
22667
+ // No execution yet — one appears when the provider's payout lands on
22668
+ // this wallet, carrying the same id.
22669
+ deposit_wallet_id: pollingWalletId
22573
22670
  });
22574
22671
  onEvent?.({
22575
22672
  id: generatePrefixedKSUID6("sevt"),
@@ -28650,7 +28747,11 @@ function PayWithStripeLink({
28650
28747
  if (checkoutResult.successful) {
28651
28748
  handledTerminalSessionRef.current = null;
28652
28749
  executionReconciledSessionRef.current = null;
28653
- track("flow_started", { method: "stripe_link", flow_type: "deposit" });
28750
+ track("flow_started", {
28751
+ method: "stripe_link",
28752
+ flow_type: "deposit",
28753
+ deposit_wallet_id: depositWalletId
28754
+ });
28654
28755
  setConfirmedSessionId(activeSessionId);
28655
28756
  setSessionStatus(STRIPE_SESSION_STATUS.FULFILLMENT_PROCESSING);
28656
28757
  if (selectedTokenSingleUseRef.current) clearSelectedPaymentToken();
@@ -30147,7 +30248,14 @@ function PayWithStripeLink({
30147
30248
  ]
30148
30249
  }
30149
30250
  ),
30150
- /* @__PURE__ */ jsx50("div", { ref: authMountRef, className: "uf-w-full uf-min-h-[200px]" })
30251
+ /* @__PURE__ */ jsx50(
30252
+ "div",
30253
+ {
30254
+ ref: authMountRef,
30255
+ className: "uf-w-full uf-min-h-[200px]",
30256
+ style: { colorScheme: "only light" }
30257
+ }
30258
+ )
30151
30259
  ]
30152
30260
  }
30153
30261
  );
@@ -31410,6 +31518,9 @@ function CoinbaseConnect({
31410
31518
  flow_type: "deposit",
31411
31519
  method: "exchange_connect",
31412
31520
  provider: IntegrationProvider.COINBASE,
31521
+ // No execution yet — one appears when the exchange's transfer lands on
31522
+ // this wallet, carrying the same id.
31523
+ deposit_wallet_id: transferDepositWalletId,
31413
31524
  amount_usd: sendAmount || void 0,
31414
31525
  currency: selectedAsset?.currency.toLowerCase().replace(/[^a-z0-9]+/g, "_"),
31415
31526
  chain: sourceChain?.chain_id,
@@ -31417,6 +31528,34 @@ function CoinbaseConnect({
31417
31528
  network: sourceChain?.network
31418
31529
  });
31419
31530
  };
31531
+ const applyConfirmResult = (result) => {
31532
+ if (result.status === "mfa_required") {
31533
+ track("verification_started", {
31534
+ flow_type: "deposit",
31535
+ method: "exchange_connect",
31536
+ provider: IntegrationProvider.COINBASE,
31537
+ verification_type: "mfa",
31538
+ verification_status: result.status
31539
+ });
31540
+ transitionTo("mfa");
31541
+ setMfaCode("");
31542
+ setMfaError(false);
31543
+ } else if (result.status === "mfa_enrollment_required") {
31544
+ transitionTo("mfa_enrollment");
31545
+ } else if (result.status === "completed") {
31546
+ trackTransferStarted();
31547
+ setConfirmResult(result);
31548
+ transitionTo("success");
31549
+ onTransferSuccess?.(result);
31550
+ } else {
31551
+ setErrorMessage(result.message || t.errors.transferFailed);
31552
+ transitionTo("error");
31553
+ onTransferError?.({
31554
+ message: result.message || t.errors.transferFailed,
31555
+ code: result.status
31556
+ });
31557
+ }
31558
+ };
31420
31559
  const handleConfirmTransfer = async () => {
31421
31560
  if (!transferIntent || !accessToken) return;
31422
31561
  setIsLoading(true);
@@ -31451,30 +31590,7 @@ function CoinbaseConnect({
31451
31590
  });
31452
31591
  throw err;
31453
31592
  });
31454
- if (result.status === "mfa_required") {
31455
- track("verification_started", {
31456
- flow_type: "deposit",
31457
- method: "exchange_connect",
31458
- provider: IntegrationProvider.COINBASE,
31459
- verification_type: "mfa",
31460
- verification_status: result.status
31461
- });
31462
- transitionTo("mfa");
31463
- setMfaCode("");
31464
- setMfaError(false);
31465
- } else if (result.status === "completed") {
31466
- trackTransferStarted();
31467
- setConfirmResult(result);
31468
- transitionTo("success");
31469
- onTransferSuccess?.(result);
31470
- } else {
31471
- setErrorMessage(result.message || t.errors.transferFailed);
31472
- transitionTo("error");
31473
- onTransferError?.({
31474
- message: result.message || t.errors.transferFailed,
31475
- code: result.status
31476
- });
31477
- }
31593
+ applyConfirmResult(result);
31478
31594
  } catch (err) {
31479
31595
  const message = err instanceof Error ? err.message : t.errors.transferFailed;
31480
31596
  setErrorMessage(message);
@@ -31631,6 +31747,9 @@ function CoinbaseConnect({
31631
31747
  setShowTransferDetails(false);
31632
31748
  transitionTo("enter_amount");
31633
31749
  break;
31750
+ case "mfa_enrollment":
31751
+ transitionTo("transfer_confirm");
31752
+ break;
31634
31753
  case "mfa":
31635
31754
  transitionTo("transfer_confirm");
31636
31755
  break;
@@ -33187,6 +33306,55 @@ function CoinbaseConnect({
33187
33306
  ] })
33188
33307
  ] });
33189
33308
  }
33309
+ if (view === "mfa_enrollment") {
33310
+ return /* @__PURE__ */ jsxs46(Fragment92, { children: [
33311
+ /* @__PURE__ */ jsx51(DepositHeader, { title: t.title, showBack: true, onBack: handleBack, onClose }),
33312
+ /* @__PURE__ */ jsxs46(
33313
+ "div",
33314
+ {
33315
+ className: "uf-flex uf-flex-col uf-items-center uf-px-4 uf-pb-4",
33316
+ style: viewTransitionStyle,
33317
+ children: [
33318
+ /* @__PURE__ */ jsx51(
33319
+ DepositErrorState,
33320
+ {
33321
+ title: t.transfer.mfaEnrollmentTitle,
33322
+ message: t.transfer.mfaEnrollmentMessage
33323
+ }
33324
+ ),
33325
+ /* @__PURE__ */ jsxs46(
33326
+ "a",
33327
+ {
33328
+ href: "https://www.coinbase.com/settings/security",
33329
+ target: "_blank",
33330
+ rel: "noopener noreferrer",
33331
+ className: "uf-text-sm uf-underline uf-mb-8 uf-inline-flex uf-items-center uf-gap-1",
33332
+ style: { color: colors2.primary, fontFamily: fonts.medium },
33333
+ children: [
33334
+ t.transfer.mfaEnrollmentSettingsLink,
33335
+ /* @__PURE__ */ jsx51(ExternalLink, { className: "uf-w-3.5 uf-h-3.5" })
33336
+ ]
33337
+ }
33338
+ ),
33339
+ /* @__PURE__ */ jsx51(
33340
+ "button",
33341
+ {
33342
+ onClick: handleConfirmTransfer,
33343
+ disabled: isLoading,
33344
+ className: "uf-w-full uf-rounded-xl uf-py-3.5 uf-text-sm uf-font-medium uf-transition-all hover:uf-opacity-90 disabled:uf-opacity-50 uf-flex uf-items-center uf-justify-center uf-gap-2",
33345
+ style: {
33346
+ backgroundColor: colors2.primary,
33347
+ color: "#fff",
33348
+ fontFamily: fonts.medium
33349
+ },
33350
+ children: isLoading ? /* @__PURE__ */ jsx51(LoaderCircle, { className: "uf-w-4 uf-h-4 uf-animate-spin" }) : t.continue
33351
+ }
33352
+ )
33353
+ ]
33354
+ }
33355
+ )
33356
+ ] });
33357
+ }
33190
33358
  if (view === "mfa") {
33191
33359
  return /* @__PURE__ */ jsxs46(Fragment92, { children: [
33192
33360
  /* @__PURE__ */ jsx51(DepositHeader, { title: t.title, showBack: true, onBack: handleBack, onClose }),
@@ -39114,7 +39282,11 @@ function WalletConnect({
39114
39282
  chain: String(token.chain_id),
39115
39283
  network: token.network,
39116
39284
  token: token.symbol ?? token.token_address,
39117
- currency: token.currency
39285
+ currency: token.currency,
39286
+ // No execution exists yet — it's created when this send lands on the
39287
+ // wallet. The wallet id is what that execution will carry, so it's
39288
+ // how a send that never completes is matched to what followed.
39289
+ deposit_wallet_id: activeDepositWallet?.id
39118
39290
  });
39119
39291
  setReceivedUsdAtSubmission(checkoutReceivedUsd ?? "0");
39120
39292
  setHasSignedTransaction(true);
@@ -39701,7 +39873,7 @@ function DepositModal({
39701
39873
  const applePaySubTitle = applePaySubTitleProp ?? t.applePayMenu.subtitle;
39702
39874
  const googlePayTitle = googlePayTitleProp ?? t.googlePayMenu.title;
39703
39875
  const googlePaySubTitle = googlePaySubTitleProp ?? t.googlePayMenu.subtitle;
39704
- const { track, startSession, endSession, getSessionId, subscribe } = useAnalytics();
39876
+ const { track, startSession, endSession, getSessionId, setUserId, subscribe } = useAnalytics();
39705
39877
  const normalizedPrefilledAmountUsd = useMemo17(
39706
39878
  () => normalizePrefilledUsdAmount(prefilledAmountUsd),
39707
39879
  [prefilledAmountUsd]
@@ -39709,6 +39881,7 @@ function DepositModal({
39709
39881
  const analyticsMethod = (method) => method === "transfer" ? "transfer_crypto" : method;
39710
39882
  const journeyActiveRef = useRef16(false);
39711
39883
  const journeySessionIdRef = useRef16(void 0);
39884
+ const journeyExternalUserIdRef = useRef16(void 0);
39712
39885
  const externalUserId = userId || void 0;
39713
39886
  const emitEvent = useCallback14(
39714
39887
  (event) => onEvent?.({ ...event, externalUserId }),
@@ -39736,6 +39909,9 @@ function DepositModal({
39736
39909
  method: analyticsMethod(method),
39737
39910
  flow_type: "deposit",
39738
39911
  amount_usd: execution?.destinationAmountUsd ?? execution?.sourceAmountUsd,
39912
+ // The one high-cardinality field we do send: the join key from a
39913
+ // funnel session back to the execution row it produced.
39914
+ execution_id: data.executionId ?? execution?.id,
39739
39915
  // Flat, low-cardinality execution dimensions for PostHog breakdowns
39740
39916
  // (precise/opaque fields like base units, addresses, tx hashes live in
39741
39917
  // the onEvent DirectExecution instead).
@@ -39763,6 +39939,7 @@ function DepositModal({
39763
39939
  method: analyticsMethod(method),
39764
39940
  flow_type: "deposit",
39765
39941
  error_code: error.code,
39942
+ execution_id: execution?.id,
39766
39943
  failure_reason: execution?.failureReason ?? void 0,
39767
39944
  status: execution?.status,
39768
39945
  source_chain_type: execution?.sourceChainType,
@@ -40191,8 +40368,10 @@ function DepositModal({
40191
40368
  const beginJourney = useCallback14(() => {
40192
40369
  journeySessionIdRef.current = startSession();
40193
40370
  journeyActiveRef.current = true;
40371
+ journeyExternalUserIdRef.current = userId;
40372
+ setUserId(null);
40194
40373
  track("widget_opened", { flow_type: "deposit" });
40195
- }, [startSession, track]);
40374
+ }, [startSession, track, setUserId, userId]);
40196
40375
  const handleClose = () => {
40197
40376
  finalizeJourney();
40198
40377
  onOpenChange(false);
@@ -40217,6 +40396,11 @@ function DepositModal({
40217
40396
  }
40218
40397
  beginJourney();
40219
40398
  }, [open]);
40399
+ useLayoutEffect22(() => {
40400
+ if (!open || journeyExternalUserIdRef.current === userId) return;
40401
+ journeyExternalUserIdRef.current = userId;
40402
+ setUserId(null);
40403
+ }, [open, userId, setUserId]);
40220
40404
  useLayoutEffect22(() => {
40221
40405
  if (!open) return;
40222
40406
  if (resetViewTimeoutRef.current) {
@@ -41128,6 +41312,7 @@ function DepositModal({
41128
41312
  destinationChainType,
41129
41313
  destinationChainId,
41130
41314
  destinationTokenAddress,
41315
+ contractCalls,
41131
41316
  cashAppIconUrl: projectConfig?.asset_cdn_url ? `${projectConfig.asset_cdn_url}/api/public/icons/onramps/svg/cashapp.svg` : void 0,
41132
41317
  view: cashAppView,
41133
41318
  onViewChange: setCashAppView,
@@ -41463,6 +41648,9 @@ function CheckoutModal({
41463
41648
  flowCompletedRef.current = true;
41464
41649
  track("flow_completed", {
41465
41650
  flow_type: "checkout",
41651
+ // Checkout has no direct execution; the intent is what a funnel
41652
+ // session joins back to.
41653
+ payment_intent_id: data.paymentIntentId,
41466
41654
  ...method ? { method: method === "transfer" ? "transfer_crypto" : method } : {}
41467
41655
  });
41468
41656
  }
@@ -41683,7 +41871,7 @@ function CheckoutModal({
41683
41871
  journeySessionIdRef.current = startSession();
41684
41872
  journeyActiveRef.current = true;
41685
41873
  flowCompletedRef.current = false;
41686
- setUserId(null);
41874
+ setUserId(paymentIntentUserId ?? null);
41687
41875
  track("widget_opened", { flow_type: "checkout" });
41688
41876
  if (resetViewTimeoutRef.current) {
41689
41877
  clearTimeout(resetViewTimeoutRef.current);
@@ -42268,7 +42456,7 @@ function useAddressBalance(params) {
42268
42456
  }
42269
42457
  function useExecutions(userId, publishableKey, options) {
42270
42458
  const actionType = options?.actionType ?? ActionType4.Deposit;
42271
- return useQuery24({
42459
+ const query = useQuery24({
42272
42460
  queryKey: ["unifold", "executions", actionType, userId, publishableKey],
42273
42461
  queryFn: () => queryExecutions4(userId, publishableKey, actionType),
42274
42462
  enabled: (options?.enabled ?? true) && !!userId,
@@ -42277,6 +42465,8 @@ function useExecutions(userId, publishableKey, options) {
42277
42465
  gcTime: 1e3 * 60 * 5,
42278
42466
  refetchOnWindowFocus: false
42279
42467
  });
42468
+ useStampInternalUserId({ internalUserId: query.data?.data[0]?.user_id });
42469
+ return query;
42280
42470
  }
42281
42471
  var POLL_INTERVAL_MS4 = 2500;
42282
42472
  var POLL_ENDPOINT_INTERVAL_MS2 = 5e3;
@@ -42651,7 +42841,6 @@ function useGetDepositAddress(params) {
42651
42841
  actionType,
42652
42842
  enabled = true
42653
42843
  } = params;
42654
- const { setUserId } = useAnalytics();
42655
42844
  const canFire = !!userId && !!recipientAddress && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress;
42656
42845
  const query = useQuery26({
42657
42846
  queryKey: [
@@ -42683,11 +42872,7 @@ function useGetDepositAddress(params) {
42683
42872
  refetchOnWindowFocus: false,
42684
42873
  retry: 1
42685
42874
  });
42686
- useEffect45(() => {
42687
- if (query.data?.user_id) {
42688
- setUserId(query.data.user_id);
42689
- }
42690
- }, [query.data?.user_id, setUserId]);
42875
+ useStampInternalUserId({ internalUserId: query.data?.user_id });
42691
42876
  return query;
42692
42877
  }
42693
42878
  var isHypercore = (chainId) => chainId === HYPERCORE_CHAIN_ID;
@@ -42822,14 +43007,14 @@ function WithdrawForm({
42822
43007
  const [detailsExpanded, setDetailsExpanded] = useState47(false);
42823
43008
  const [glossaryOpen, setGlossaryOpen] = useState47(false);
42824
43009
  const [isMaxed, setIsMaxed] = useState47(false);
42825
- useEffect46(() => {
43010
+ useEffect45(() => {
42826
43011
  setRecipientAddress(recipientAddressProp || "");
42827
43012
  setAmount("");
42828
43013
  setInputUnit("fiat");
42829
43014
  setSubmitError(null);
42830
43015
  setIsMaxed(false);
42831
43016
  }, [recipientAddressProp]);
42832
- useEffect46(() => {
43017
+ useEffect45(() => {
42833
43018
  setIsMaxed(false);
42834
43019
  }, [balanceData?.balanceBaseUnit]);
42835
43020
  const trimmedAddress = recipientAddress.trim();
@@ -43639,7 +43824,7 @@ function WithdrawConfirmingView({
43639
43824
  const t = strings.withdrawModal.details;
43640
43825
  const [showButton, setShowButton] = useState48(false);
43641
43826
  const latestExecution = executions.length > 0 ? executions[executions.length - 1] : null;
43642
- useEffect47(() => {
43827
+ useEffect46(() => {
43643
43828
  if (latestExecution) return;
43644
43829
  const timer = setTimeout(() => setShowButton(true), SHOW_BUTTON_DELAY_MS);
43645
43830
  return () => clearTimeout(timer);
@@ -43791,7 +43976,7 @@ function WithdrawModal({
43791
43976
  );
43792
43977
  const onEventRef = useRef20(emitEvent);
43793
43978
  onEventRef.current = emitEvent;
43794
- useEffect48(
43979
+ useEffect47(
43795
43980
  () => subscribe((event) => {
43796
43981
  if (event.properties?.flow_type !== "withdraw") return;
43797
43982
  const selection = selectionPayload(event);
@@ -43808,12 +43993,16 @@ function WithdrawModal({
43808
43993
  );
43809
43994
  const journeyActiveRef = useRef20(false);
43810
43995
  const journeySessionIdRef = useRef20(void 0);
43996
+ const journeyExternalUserIdRef = useRef20(void 0);
43811
43997
  const onWithdrawSuccessFor = useCallback17(
43812
43998
  (data) => {
43813
43999
  const execution = data.execution?.data.object;
43814
44000
  track("flow_completed", {
43815
44001
  flow_type: "withdraw",
43816
44002
  amount_usd: execution?.destinationAmountUsd ?? execution?.sourceAmountUsd,
44003
+ // The one high-cardinality field we do send: the join key from a
44004
+ // funnel session back to the execution row it produced.
44005
+ execution_id: data.executionId ?? execution?.id,
43817
44006
  // Flat, low-cardinality execution dimensions for PostHog breakdowns.
43818
44007
  status: execution?.status,
43819
44008
  source_chain_type: execution?.sourceChainType,
@@ -43834,6 +44023,7 @@ function WithdrawModal({
43834
44023
  track("flow_failed", {
43835
44024
  flow_type: "withdraw",
43836
44025
  error_code: error.code,
44026
+ execution_id: execution?.id,
43837
44027
  failure_reason: execution?.failureReason ?? void 0,
43838
44028
  status: execution?.status,
43839
44029
  source_chain_type: execution?.sourceChainType,
@@ -43855,7 +44045,7 @@ function WithdrawModal({
43855
44045
  const [resolvedTheme, setResolvedTheme] = useState49(
43856
44046
  theme === "auto" ? "dark" : theme
43857
44047
  );
43858
- useEffect48(() => {
44048
+ useEffect47(() => {
43859
44049
  if (theme === "auto") {
43860
44050
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
43861
44051
  setResolvedTheme(mq.matches ? "dark" : "light");
@@ -43907,6 +44097,7 @@ function WithdrawModal({
43907
44097
  ) ?? null : null;
43908
44098
  const [view, setView] = useState49("form");
43909
44099
  const [withdrawDepositWalletId, setWithdrawDepositWalletId] = useState49();
44100
+ const withdrawDepositWalletIdRef = useRef20(void 0);
43910
44101
  const [selectedExecution, setSelectedExecution] = useState49(null);
43911
44102
  const [submittedTxInfo, setSubmittedTxInfo] = useState49(null);
43912
44103
  const { executions: realtimeExecutions } = useWithdrawPolling({
@@ -43944,6 +44135,7 @@ function WithdrawModal({
43944
44135
  if (!depositWallet) {
43945
44136
  throw new Error(`No deposit wallet available for ${sourceChainType}`);
43946
44137
  }
44138
+ withdrawDepositWalletIdRef.current = depositWallet.id;
43947
44139
  setWithdrawDepositWalletId(depositWallet.id);
43948
44140
  return depositWallet;
43949
44141
  },
@@ -43963,7 +44155,12 @@ function WithdrawModal({
43963
44155
  currency: tokenData?.currency,
43964
44156
  amount: txInfo.amount,
43965
44157
  amount_base_unit: txInfo.amountBaseUnit,
43966
- ...txInfo.amountUsd ? { amount_usd: txInfo.amountUsd } : {}
44158
+ ...txInfo.amountUsd ? { amount_usd: txInfo.amountUsd } : {},
44159
+ // The execution doesn't exist yet — it's created when the user's send
44160
+ // lands on the withdraw deposit wallet, and carries this id. So a
44161
+ // withdrawal confirmed but never completed still joins to whatever
44162
+ // did (or didn't) follow on that wallet.
44163
+ deposit_wallet_id: withdrawDepositWalletIdRef.current
43967
44164
  });
43968
44165
  emitEvent({
43969
44166
  id: generatePrefixedKSUID12("sevt"),
@@ -43997,8 +44194,10 @@ function WithdrawModal({
43997
44194
  const beginJourney = useCallback17(() => {
43998
44195
  journeySessionIdRef.current = startSession();
43999
44196
  journeyActiveRef.current = true;
44197
+ journeyExternalUserIdRef.current = externalUserId;
44198
+ setUserId(null);
44000
44199
  track("widget_opened", { flow_type: "withdraw" });
44001
- }, [startSession, track]);
44200
+ }, [startSession, track, setUserId, externalUserId]);
44002
44201
  const handleClose = useCallback17(() => {
44003
44202
  finalizeJourney();
44004
44203
  onOpenChange(false);
@@ -44007,6 +44206,7 @@ function WithdrawModal({
44007
44206
  setView("form");
44008
44207
  setSelectedExecution(null);
44009
44208
  setSubmittedTxInfo(null);
44209
+ withdrawDepositWalletIdRef.current = void 0;
44010
44210
  setWithdrawDepositWalletId(void 0);
44011
44211
  resetViewTimeoutRef.current = null;
44012
44212
  }, 200);
@@ -44024,9 +44224,15 @@ function WithdrawModal({
44024
44224
  setView("form");
44025
44225
  setSelectedExecution(null);
44026
44226
  setSubmittedTxInfo(null);
44227
+ withdrawDepositWalletIdRef.current = void 0;
44027
44228
  setWithdrawDepositWalletId(void 0);
44028
44229
  }, [open]);
44029
- useEffect48(
44230
+ useLayoutEffect42(() => {
44231
+ if (!open || journeyExternalUserIdRef.current === externalUserId) return;
44232
+ journeyExternalUserIdRef.current = externalUserId;
44233
+ setUserId(null);
44234
+ }, [open, externalUserId, setUserId]);
44235
+ useEffect47(
44030
44236
  () => () => {
44031
44237
  if (journeyActiveRef.current) {
44032
44238
  journeyActiveRef.current = false;
@@ -44035,12 +44241,12 @@ function WithdrawModal({
44035
44241
  },
44036
44242
  [endSession, getSessionId]
44037
44243
  );
44038
- useEffect48(() => {
44244
+ useEffect47(() => {
44039
44245
  if (!open) return;
44040
44246
  const screen = view === "detail" ? "tracker_detail" : view;
44041
44247
  track("screen_viewed", { flow_type: "withdraw", screen });
44042
44248
  }, [open, view, track]);
44043
- useEffect48(
44249
+ useEffect47(
44044
44250
  () => () => {
44045
44251
  if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
44046
44252
  },