@swype-org/react-sdk 0.2.372 → 0.2.377

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.cjs CHANGED
@@ -13,9 +13,12 @@ var core = require('@wagmi/core');
13
13
  var viem = require('viem');
14
14
  var utils = require('viem/utils');
15
15
  var QRCode = require('qrcode');
16
+ var posthog = require('posthog-js');
16
17
  var Select = require('@radix-ui/react-select');
17
18
 
18
19
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
20
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
21
+
19
22
  function _interopNamespace(e) {
20
23
  if (e && e.__esModule) return e;
21
24
  var n = Object.create(null);
@@ -35,6 +38,7 @@ function _interopNamespace(e) {
35
38
  }
36
39
 
37
40
  var QRCode__namespace = /*#__PURE__*/_interopNamespace(QRCode);
41
+ var posthog__default = /*#__PURE__*/_interopDefault(posthog);
38
42
  var Select__namespace = /*#__PURE__*/_interopNamespace(Select);
39
43
 
40
44
  var __defProp = Object.defineProperty;
@@ -523,6 +527,14 @@ function isVisibleUsdAmountAtTwoDecimals(amount) {
523
527
  function isSelectableDepositSourceAmountUsd(amount, minTransferAmountUsd = DEFAULT_MIN_SEND_AMOUNT_USD) {
524
528
  return Number.isFinite(amount) && amount >= minTransferAmountUsd;
525
529
  }
530
+ function buildNativeUnsupportedEntries(options) {
531
+ return options.map((option) => ({
532
+ tokenSymbol: option.tokenSymbol,
533
+ chainName: option.chainName,
534
+ amount: parseRawBalance(option.rawBalance, option.decimals),
535
+ logoURI: option.logoURI ?? null
536
+ })).filter((entry) => entry.amount > 0);
537
+ }
526
538
  function buildSelectSourceChoices(options, minTransferAmountUsd = DEFAULT_MIN_SEND_AMOUNT_USD) {
527
539
  const chainChoices = [];
528
540
  const chainIndexByName = /* @__PURE__ */ new Map();
@@ -1016,10 +1028,6 @@ var BLINK_PRIVY_APP_ID = "cmlil87uv004n0ck0blwumwek";
1016
1028
  var BLINK_WC_PROJECT_ID = "f6c60234412f94ef9108dc8f67f4362c";
1017
1029
  var BLINK_FINGERPRINT_API_KEY = "nr4FvTsZ6M5z2141FqrM";
1018
1030
  var BLINK_FINGERPRINT_REGION = "us";
1019
- function FingerprintVisitorPing() {
1020
- react$1.useVisitorData({ immediate: true });
1021
- return null;
1022
- }
1023
1031
  function buildStaticConnectors() {
1024
1032
  const userAgent = typeof navigator === "undefined" ? null : navigator.userAgent;
1025
1033
  return [
@@ -1128,30 +1136,30 @@ function BlinkProvider({
1128
1136
  );
1129
1137
  return (
1130
1138
  // Outermost wrapper: loads the Fingerprint browser agent once per
1131
- // provider mount, independent of wagmi/privy/query state. Visitor data
1132
- // collection starts here; no hook is exposed yet (see SDK barrel).
1133
- /* @__PURE__ */ jsxRuntime.jsxs(react$1.FingerprintProvider, { apiKey: BLINK_FINGERPRINT_API_KEY, region: BLINK_FINGERPRINT_REGION, children: [
1134
- /* @__PURE__ */ jsxRuntime.jsx(FingerprintVisitorPing, {}),
1135
- /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClientRef.current, children: /* @__PURE__ */ jsxRuntime.jsx(wagmi.WagmiProvider, { config: wagmiConfig, reconnectOnMount: false, children: /* @__PURE__ */ jsxRuntime.jsx(
1136
- reactAuth.PrivyProvider,
1137
- {
1138
- appId: privyAppId ?? BLINK_PRIVY_APP_ID,
1139
- config: {
1140
- appearance: {
1141
- theme: getThemeBase(theme),
1142
- accentColor: getTheme(theme).accent
1143
- },
1144
- intl: {
1145
- defaultCountry: "US"
1146
- },
1147
- embeddedWallets: {
1148
- showWalletUIs: false
1149
- }
1139
+ // provider mount, independent of wagmi/privy/query state. The agent loads
1140
+ // here (including during the hidden preload warm-up), but identification is
1141
+ // deferred to explicit flow events fired from `BlinkPayment` see
1142
+ // `useFingerprintFlowEvents` so a preload that never opens is never
1143
+ // identified.
1144
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.FingerprintProvider, { apiKey: BLINK_FINGERPRINT_API_KEY, region: BLINK_FINGERPRINT_REGION, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClientRef.current, children: /* @__PURE__ */ jsxRuntime.jsx(wagmi.WagmiProvider, { config: wagmiConfig, reconnectOnMount: false, children: /* @__PURE__ */ jsxRuntime.jsx(
1145
+ reactAuth.PrivyProvider,
1146
+ {
1147
+ appId: privyAppId ?? BLINK_PRIVY_APP_ID,
1148
+ config: {
1149
+ appearance: {
1150
+ theme: getThemeBase(theme),
1151
+ accentColor: getTheme(theme).accent
1150
1152
  },
1151
- children: /* @__PURE__ */ jsxRuntime.jsx(BlinkContext.Provider, { value, children })
1152
- }
1153
- ) }) })
1154
- ] })
1153
+ intl: {
1154
+ defaultCountry: "US"
1155
+ },
1156
+ embeddedWallets: {
1157
+ showWalletUIs: false
1158
+ }
1159
+ },
1160
+ children: /* @__PURE__ */ jsxRuntime.jsx(BlinkContext.Provider, { value, children })
1161
+ }
1162
+ ) }) }) })
1155
1163
  );
1156
1164
  }
1157
1165
  function useBlinkConfig() {
@@ -1573,11 +1581,11 @@ function detachAccountChangeListeners() {
1573
1581
  accountChangeBinding = null;
1574
1582
  }
1575
1583
  function providerKey(selection) {
1576
- const providerName = selection.providerName?.trim();
1577
- if (!providerName) {
1584
+ const providerName2 = selection.providerName?.trim();
1585
+ if (!providerName2) {
1578
1586
  throw new Error("Solana wallet metadata is missing providerName.");
1579
1587
  }
1580
- return `${selection.providerId ?? ""}:${providerName.toLowerCase()}`;
1588
+ return `${selection.providerId ?? ""}:${providerName2.toLowerCase()}`;
1581
1589
  }
1582
1590
  function assertSupportedProvider(selection) {
1583
1591
  const name = selection.providerName?.trim().toLowerCase();
@@ -4145,14 +4153,14 @@ function isBatchableAction(action) {
4145
4153
  return BATCHABLE_ACTION_TYPES.has(action.type);
4146
4154
  }
4147
4155
  function getSolanaWalletSelection(action) {
4148
- const providerName = action.metadata?.providerName;
4149
- if (typeof providerName !== "string" || providerName.trim() === "") {
4156
+ const providerName2 = action.metadata?.providerName;
4157
+ if (typeof providerName2 !== "string" || providerName2.trim() === "") {
4150
4158
  throw new Error(`${action.type} metadata is missing providerName.`);
4151
4159
  }
4152
4160
  const providerId = action.metadata?.providerId;
4153
4161
  return {
4154
4162
  ...typeof providerId === "string" && providerId.trim() !== "" ? { providerId } : {},
4155
- providerName
4163
+ providerName: providerName2
4156
4164
  };
4157
4165
  }
4158
4166
  function isPhantomEvmProviderAvailable() {
@@ -8463,6 +8471,209 @@ function applyAction(state, action) {
8463
8471
  return state;
8464
8472
  }
8465
8473
  }
8474
+ var BLOCKED_SUBSTRINGS = [
8475
+ "bearer",
8476
+ "signature",
8477
+ "signedpayload",
8478
+ "userop",
8479
+ "jwt",
8480
+ "secret",
8481
+ "password",
8482
+ "privatekey",
8483
+ "mnemonic",
8484
+ "seedphrase"
8485
+ ];
8486
+ function isBlockedKey(key) {
8487
+ const lower = key.toLowerCase();
8488
+ if (lower === "token" || lower.endsWith("token")) return true;
8489
+ return BLOCKED_SUBSTRINGS.some((blocked) => lower.includes(blocked));
8490
+ }
8491
+ function isReady() {
8492
+ return typeof posthog__default.default !== "undefined" && posthog__default.default.__loaded === true;
8493
+ }
8494
+ function sanitizeProps(props) {
8495
+ if (!props) return props;
8496
+ const clean = {};
8497
+ for (const [key, value] of Object.entries(props)) {
8498
+ if (isBlockedKey(key)) continue;
8499
+ if (value === void 0) continue;
8500
+ clean[key] = value;
8501
+ }
8502
+ return clean;
8503
+ }
8504
+ function registerSuperProps(props) {
8505
+ if (!isReady()) return;
8506
+ try {
8507
+ posthog__default.default.register(sanitizeProps(props) ?? {});
8508
+ } catch {
8509
+ }
8510
+ }
8511
+ function track(event, props) {
8512
+ if (!isReady()) return;
8513
+ try {
8514
+ posthog__default.default.capture(event, sanitizeProps(props));
8515
+ } catch {
8516
+ }
8517
+ }
8518
+ function identifyUser(privyUserId, props) {
8519
+ if (!isReady() || !privyUserId) return;
8520
+ try {
8521
+ posthog__default.default.identify(privyUserId, sanitizeProps(props));
8522
+ } catch {
8523
+ }
8524
+ }
8525
+ function resolveAnalyticsEnvironment(opts) {
8526
+ const explicit = opts.explicit?.trim();
8527
+ if (explicit) return explicit;
8528
+ const raw = opts.apiBaseUrl ?? "";
8529
+ let host = raw;
8530
+ try {
8531
+ host = new URL(raw).hostname;
8532
+ } catch {
8533
+ }
8534
+ const h = host.toLowerCase();
8535
+ if (h === "" || h.includes("localhost") || h.startsWith("127.")) return "development";
8536
+ if (h.includes("smokebox")) return "smokebox";
8537
+ if (h.includes("sandbox")) return "sandbox";
8538
+ if (h.includes("staging")) return "staging";
8539
+ return "production";
8540
+ }
8541
+ function resetUser() {
8542
+ if (!isReady()) return;
8543
+ try {
8544
+ posthog__default.default.reset();
8545
+ } catch {
8546
+ }
8547
+ }
8548
+
8549
+ // src/analyticsEvents.ts
8550
+ function providerName(state, providerId) {
8551
+ return state.providers.find((p) => p.id === providerId)?.name;
8552
+ }
8553
+ function amountUsd(transfer) {
8554
+ return transfer.amount?.currency === "USD" ? transfer.amount.amount : transfer.amount?.amount;
8555
+ }
8556
+ function sourceChain(transfer) {
8557
+ return transfer.sources?.[0]?.provider?.chainFamily;
8558
+ }
8559
+ function trackAction(action, state, ctx) {
8560
+ const device = ctx.device;
8561
+ switch (action.type) {
8562
+ case "PASSKEY_ACTIVATED":
8563
+ track("auth_succeeded", { method: "passkey", device });
8564
+ break;
8565
+ case "SELECT_PROVIDER":
8566
+ track("wallet_provider_selected", {
8567
+ device,
8568
+ providerId: action.providerId,
8569
+ providerName: providerName(state, action.providerId),
8570
+ transport: device === "desktop" ? "inline" : "deeplink"
8571
+ });
8572
+ break;
8573
+ case "MOBILE_DEEPLINK_READY":
8574
+ track("wallet_deeplink_opened", { device });
8575
+ break;
8576
+ case "SET_SETUP_DEPOSIT_TOKEN":
8577
+ track("token_selected", {
8578
+ device,
8579
+ tokenSymbol: action.symbol,
8580
+ chainName: action.chainName
8581
+ });
8582
+ break;
8583
+ case "FINALIZE_AMOUNT": {
8584
+ const parsed = Number(state.amount);
8585
+ track("amount_entered", {
8586
+ device,
8587
+ amountUsd: Number.isFinite(parsed) ? parsed : void 0
8588
+ });
8589
+ break;
8590
+ }
8591
+ case "PAY_STARTED":
8592
+ track("deposit_clicked", { device });
8593
+ break;
8594
+ case "TRANSFER_CREATED":
8595
+ track("transfer_created", {
8596
+ device,
8597
+ chainFamily: sourceChain(action.transfer)
8598
+ });
8599
+ break;
8600
+ case "TRANSFER_SIGNED":
8601
+ track("transfer_signed", { device });
8602
+ break;
8603
+ case "TRANSFER_COMPLETED":
8604
+ track("transfer_completed", {
8605
+ device,
8606
+ amountUsd: amountUsd(action.transfer),
8607
+ chainFamily: sourceChain(action.transfer)
8608
+ });
8609
+ break;
8610
+ case "CONFIRM_SIGN_SUCCESS":
8611
+ track("confirm_sign_success", { device });
8612
+ break;
8613
+ case "MOBILE_SETUP_COMPLETE":
8614
+ track("wallet_setup_complete", { device });
8615
+ break;
8616
+ case "TRANSFER_FAILED":
8617
+ track("transfer_error", {
8618
+ device,
8619
+ type: "transfer_failed",
8620
+ stage: "processing",
8621
+ message: action.error
8622
+ });
8623
+ break;
8624
+ case "PROCESSING_TIMEOUT":
8625
+ track("transfer_error", {
8626
+ device,
8627
+ type: "processing_timeout",
8628
+ stage: "processing",
8629
+ message: action.error
8630
+ });
8631
+ break;
8632
+ case "SIGN_PAYLOAD_EXPIRED":
8633
+ track("transfer_error", {
8634
+ device,
8635
+ type: "sign_payload_expired",
8636
+ stage: "signing",
8637
+ message: action.error
8638
+ });
8639
+ break;
8640
+ case "PAY_ERROR":
8641
+ track("transfer_error", {
8642
+ device,
8643
+ type: "pay_error",
8644
+ stage: "creation",
8645
+ message: action.error
8646
+ });
8647
+ break;
8648
+ }
8649
+ }
8650
+ function useAnalyticsScreenView(phase, device) {
8651
+ const lastScreenRef = react.useRef(null);
8652
+ const screen = screenForPhase(phase);
8653
+ react.useEffect(() => {
8654
+ if (lastScreenRef.current === screen) return;
8655
+ lastScreenRef.current = screen;
8656
+ track("screen_viewed", { screen, phase: phase.step, device });
8657
+ }, [screen, phase.step, device]);
8658
+ }
8659
+ function usePostHogIdentify() {
8660
+ const { ready, authenticated, user } = reactAuth.usePrivy();
8661
+ const identifiedIdRef = react.useRef(null);
8662
+ react.useEffect(() => {
8663
+ if (!ready) return;
8664
+ if (authenticated && user?.id) {
8665
+ if (identifiedIdRef.current !== user.id) {
8666
+ identifyUser(user.id);
8667
+ identifiedIdRef.current = user.id;
8668
+ }
8669
+ return;
8670
+ }
8671
+ if (identifiedIdRef.current !== null) {
8672
+ resetUser();
8673
+ identifiedIdRef.current = null;
8674
+ }
8675
+ }, [ready, authenticated, user?.id]);
8676
+ }
8466
8677
 
8467
8678
  // src/setupDepositConfirmation.ts
8468
8679
  function deriveEffectiveSetupSource(setupDepositToken, setupSelectedSourceOption) {
@@ -9326,6 +9537,8 @@ var TETHER_LOGO = svgToDataUri(TETHER_SVG);
9326
9537
  var USDH_LOGO = svgToDataUri(USDH_SVG);
9327
9538
  var ETH_LOGO = "https://assets.relay.link/icons/currencies/eth.png";
9328
9539
  var SOL_LOGO = "https://assets.relay.link/icons/currencies/sol.png";
9540
+ var MON_LOGO = "https://assets.relay.link/icons/currencies/mon.png";
9541
+ var BNB_LOGO = "https://assets.relay.link/icons/currencies/bnb.png";
9329
9542
  var KNOWN_LOGOS = {
9330
9543
  metamask: METAMASK_LOGO,
9331
9544
  base: BASE_LOGO,
@@ -9343,7 +9556,9 @@ var TOKEN_LOGOS = {
9343
9556
  USDM: USDM_LOGO,
9344
9557
  USDH: USDH_LOGO,
9345
9558
  ETH: ETH_LOGO,
9346
- SOL: SOL_LOGO
9559
+ SOL: SOL_LOGO,
9560
+ MON: MON_LOGO,
9561
+ BNB: BNB_LOGO
9347
9562
  };
9348
9563
  var CHAIN_LOGOS = {
9349
9564
  base: BASE_CHAIN_LOGO,
@@ -10368,6 +10583,7 @@ function TokenSourceRow({
10368
10583
  chainName,
10369
10584
  tokenLogoUri,
10370
10585
  balance,
10586
+ balanceLabel,
10371
10587
  selected,
10372
10588
  requiresAuth,
10373
10589
  notSupported,
@@ -10376,9 +10592,10 @@ function TokenSourceRow({
10376
10592
  const { tokens } = useBlinkConfig();
10377
10593
  const [hovered, setHovered] = react.useState(false);
10378
10594
  const tokenLogo = tokenLogoUri ?? TOKEN_LOGOS[symbol];
10595
+ const balanceText = balanceLabel ?? (balance != null ? `$${formatUsdTwoDecimals2(balance)}` : null);
10379
10596
  const ariaLabel = [
10380
10597
  `${symbol} on ${chainName}`,
10381
- balance != null ? `$${formatUsdTwoDecimals2(balance)} balance` : null,
10598
+ balanceText != null ? `${balanceText} balance` : null,
10382
10599
  requiresAuth ? "authorisation required" : null,
10383
10600
  notSupported ? NOT_SUPPORTED_LABEL.toLowerCase() : null
10384
10601
  ].filter(Boolean).join(", ");
@@ -10412,15 +10629,12 @@ function TokenSourceRow({
10412
10629
  selected && /* @__PURE__ */ jsxRuntime.jsx(SelectedBadge, { accent: tokens.accent, fill: tokens.textInverse })
10413
10630
  ] }),
10414
10631
  /* @__PURE__ */ jsxRuntime.jsxs("span", { style: textColStyle2, children: [
10415
- notSupported ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: symbolLineStyle, children: [
10416
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: symbolStyle(tokens.textMuted), children: symbol }),
10417
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: notSupportedTagStyle(tokens.bgInput, tokens.border, tokens.textMuted), children: NOT_SUPPORTED_BADGE_TEXT })
10418
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: symbolStyle(tokens.text), children: symbol }),
10632
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: symbolStyle(notSupported ? tokens.textMuted : tokens.text), children: symbol }),
10419
10633
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: chainStyle(tokens.textMuted), children: chainName })
10420
10634
  ] }),
10421
- balance != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: balanceStyle2(tokens.textMuted), children: [
10422
- "$",
10423
- formatUsdTwoDecimals2(balance)
10635
+ (balanceText != null || notSupported) && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: balanceColStyle, children: [
10636
+ balanceText != null && /* @__PURE__ */ jsxRuntime.jsx("span", { style: balanceStyle2(tokens.textMuted), children: balanceText }),
10637
+ notSupported && /* @__PURE__ */ jsxRuntime.jsx("span", { style: notSupportedTagStyle(tokens.bgInput, tokens.border, tokens.textMuted), children: NOT_SUPPORTED_BADGE_TEXT })
10424
10638
  ] })
10425
10639
  ]
10426
10640
  }
@@ -10529,11 +10743,12 @@ var balanceStyle2 = (color) => ({
10529
10743
  whiteSpace: "nowrap",
10530
10744
  flexShrink: 0
10531
10745
  });
10532
- var symbolLineStyle = {
10746
+ var balanceColStyle = {
10533
10747
  display: "flex",
10534
- alignItems: "center",
10535
- gap: 6,
10536
- minWidth: 0
10748
+ flexDirection: "column",
10749
+ alignItems: "flex-end",
10750
+ gap: 4,
10751
+ flexShrink: 0
10537
10752
  };
10538
10753
  var notSupportedTagStyle = (bg, borderColor, color) => ({
10539
10754
  fontSize: 11,
@@ -13117,7 +13332,7 @@ var lockBannerTextStyle = (color) => ({
13117
13332
  function ManualTransferPasskeyScreen({
13118
13333
  onCreatePasskey,
13119
13334
  onNoThanks,
13120
- amountUsd,
13335
+ amountUsd: amountUsd2,
13121
13336
  loading = false,
13122
13337
  error,
13123
13338
  onBack,
@@ -13375,7 +13590,7 @@ function LinkTokensScreen({
13375
13590
  }
13376
13591
  ),
13377
13592
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: contentStyle10, children: [
13378
- /* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle7(t.text), children: "Pick your asset for passkey deposits" }),
13593
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle7(t.text), children: "Pick your stablecoin for passkey deposits" }),
13379
13594
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "blink-link-tokens-list", style: listCardStyle(t.bgRecessed), children: [
13380
13595
  showShimmer ? Array.from({ length: SHIMMER_ROWS }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs(
13381
13596
  "div",
@@ -13398,7 +13613,9 @@ function LinkTokensScreen({
13398
13613
  {
13399
13614
  symbol: entry.tokenSymbol,
13400
13615
  chainName: entry.chainName,
13401
- balance: entry.balanceUsd,
13616
+ tokenLogoUri: entry.tokenLogoUri,
13617
+ balance: entry.balanceLabel == null ? entry.balanceUsd : void 0,
13618
+ balanceLabel: entry.balanceLabel,
13402
13619
  selected: i === selectedIndex,
13403
13620
  notSupported: entry.notSupported,
13404
13621
  onClick: () => onSelect(i)
@@ -17010,6 +17227,14 @@ var genericStackStyle = {
17010
17227
  gap: 14
17011
17228
  };
17012
17229
 
17230
+ // src/feeFormat.ts
17231
+ function formatNativeAmount(value, maxDecimals = 4) {
17232
+ if (!Number.isFinite(value) || value <= 0) return "0";
17233
+ const rounded = Number(value.toFixed(maxDecimals));
17234
+ if (rounded === 0) return `< ${(10 ** -maxDecimals).toFixed(maxDecimals)}`;
17235
+ return rounded.toLocaleString("en-US", { maximumFractionDigits: maxDecimals }).replace(/,/g, "");
17236
+ }
17237
+
17013
17238
  // src/screenViewModels.ts
17014
17239
  function findSelectedWallet(selectedAccount, selectedWalletId) {
17015
17240
  return selectedAccount?.wallets.find((w) => w.id === selectedWalletId);
@@ -17176,7 +17401,11 @@ function buildLinkTokensScreenProps({
17176
17401
  walletId: rawOption?.walletId,
17177
17402
  tokenAddress: rawOption?.tokenAddress,
17178
17403
  chainId: rawOption?.chainId != null ? Number(rawOption.chainId) : void 0,
17179
- notSupported: false
17404
+ notSupported: false,
17405
+ // Server-provided token logo (token_addresses.logo_uri). The component
17406
+ // falls back to the bundled TOKEN_LOGOS map by symbol, so tokens without
17407
+ // a bundled asset (e.g. CASH) rely on this DB-driven URI.
17408
+ tokenLogoUri: t.logoURI ?? void 0
17180
17409
  };
17181
17410
  })
17182
17411
  );
@@ -17186,19 +17415,32 @@ function buildLinkTokensScreenProps({
17186
17415
  symbol: t.tokenSymbol,
17187
17416
  chainName: chain.chainName,
17188
17417
  balanceUsd: t.balance ?? 0,
17189
- walletId: void 0,
17190
- tokenAddress: void 0,
17191
- chainId: void 0,
17192
- notSupported: true
17418
+ notSupported: true,
17419
+ tokenLogoUri: t.logoURI ?? void 0
17193
17420
  }))
17194
17421
  )
17195
17422
  );
17196
- const entries2 = rowContexts.map(({ symbol, chainName, balanceUsd, notSupported }) => ({
17197
- tokenSymbol: symbol,
17198
- chainName,
17199
- balanceUsd,
17200
- notSupported
17201
- }));
17423
+ rowContexts.push(
17424
+ ...derived.selectSourceNativeChoices.map((native) => ({
17425
+ symbol: native.tokenSymbol,
17426
+ chainName: native.chainName,
17427
+ balanceUsd: 0,
17428
+ notSupported: true,
17429
+ tokenLogoUri: native.logoURI ?? void 0,
17430
+ balanceLabel: `${formatNativeAmount(native.amount)} ${native.tokenSymbol}`
17431
+ }))
17432
+ );
17433
+ const entries2 = rowContexts.map(
17434
+ ({ symbol, chainName, balanceUsd, notSupported, tokenLogoUri, balanceLabel }) => ({
17435
+ tokenSymbol: symbol,
17436
+ chainName,
17437
+ balanceUsd,
17438
+ notSupported,
17439
+ // Only present on native rows — keeps stablecoin / WC entries unchanged.
17440
+ ...tokenLogoUri != null ? { tokenLogoUri } : {},
17441
+ ...balanceLabel != null ? { balanceLabel } : {}
17442
+ })
17443
+ );
17202
17444
  const firstSupportedIndex = rowContexts.findIndex((row) => !row.notSupported);
17203
17445
  const selectedTokenSymbol = flow.state.setupDepositToken?.symbol ?? derived.selectSourceRecommended?.tokenSymbol;
17204
17446
  const selectedChainName = flow.state.setupDepositToken?.chainName ?? derived.selectSourceRecommended?.chainName;
@@ -17794,6 +18036,7 @@ function useAuthHandlers(dispatch, apiBaseUrl, popupAuthRef) {
17794
18036
  dispatch({ type: "PASSKEY_ACTIVATED", credentialId: result.credentialId, publicKey: result.publicKey });
17795
18037
  dispatch({ type: "SYNC_PRIVY_SESSION", ready: true, authenticated: true });
17796
18038
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, result.credentialId);
18039
+ track("login_succeeded", { method: "passkey", popup: true });
17797
18040
  } catch (err) {
17798
18041
  captureException(err);
17799
18042
  dispatch({
@@ -17806,6 +18049,7 @@ function useAuthHandlers(dispatch, apiBaseUrl, popupAuthRef) {
17806
18049
  }, [dispatch, popupAuthRef]);
17807
18050
  const { loginWithPasskey, state: loginState } = reactAuth.useLoginWithPasskey({
17808
18051
  onComplete: (params) => {
18052
+ track("login_succeeded", { method: "passkey", popup: false });
17809
18053
  handleAuthComplete(params.user);
17810
18054
  },
17811
18055
  onError: (error) => {
@@ -17834,6 +18078,7 @@ function useAuthHandlers(dispatch, apiBaseUrl, popupAuthRef) {
17834
18078
  dispatch({ type: "PASSKEY_ACTIVATED", credentialId: result.credentialId, publicKey: result.publicKey });
17835
18079
  dispatch({ type: "SYNC_PRIVY_SESSION", ready: true, authenticated: true });
17836
18080
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, result.credentialId);
18081
+ track("signup_succeeded", { method: "passkey", popup: true });
17837
18082
  } catch (err) {
17838
18083
  captureException(err);
17839
18084
  dispatch({
@@ -17846,6 +18091,7 @@ function useAuthHandlers(dispatch, apiBaseUrl, popupAuthRef) {
17846
18091
  }, [dispatch, popupAuthRef]);
17847
18092
  const { signupWithPasskey, state: signupState } = reactAuth.useSignupWithPasskey({
17848
18093
  onComplete: (params) => {
18094
+ track("signup_succeeded", { method: "passkey", popup: false });
17849
18095
  handleAuthComplete(params.user);
17850
18096
  },
17851
18097
  onError: (error) => {
@@ -18201,6 +18447,11 @@ function useSourceSelectionHandlers(_dispatch, orchestrator, options) {
18201
18447
  const unsupportedOptions = pendingSelectSourceAction.metadata?.unsupportedOptions ?? [];
18202
18448
  return buildSelectSourceChoices(unsupportedOptions, minTransferAmountUsd);
18203
18449
  }, [pendingSelectSourceAction, minTransferAmountUsd]);
18450
+ const selectSourceNativeChoices = react.useMemo(() => {
18451
+ if (!pendingSelectSourceAction) return [];
18452
+ const nativeOptions = pendingSelectSourceAction.metadata?.nativeUnsupportedOptions ?? [];
18453
+ return buildNativeUnsupportedEntries(nativeOptions);
18454
+ }, [pendingSelectSourceAction]);
18204
18455
  const selectSourceRecommended = react.useMemo(() => {
18205
18456
  if (!pendingSelectSourceAction) return null;
18206
18457
  return pendingSelectSourceAction.metadata?.recommended ?? null;
@@ -18252,6 +18503,7 @@ function useSourceSelectionHandlers(_dispatch, orchestrator, options) {
18252
18503
  setSelectSourceTokenSymbol,
18253
18504
  selectSourceChoices,
18254
18505
  selectSourceUnsupportedChoices,
18506
+ selectSourceNativeChoices,
18255
18507
  selectSourceRecommended,
18256
18508
  selectSourceAvailableBalance,
18257
18509
  handleSelectSourceChainChange,
@@ -18610,7 +18862,7 @@ function useProviderHandlers(deps) {
18610
18862
  return null;
18611
18863
  }
18612
18864
  const provider = providers.find((p) => p.id === providerId);
18613
- const providerName = provider?.name ?? "Wallet";
18865
+ const providerName2 = provider?.name ?? "Wallet";
18614
18866
  try {
18615
18867
  const token = await getAccessToken();
18616
18868
  if (!token) throw new Error("Not authenticated");
@@ -18618,7 +18870,7 @@ function useProviderHandlers(deps) {
18618
18870
  const accountId = crypto.randomUUID();
18619
18871
  const account = await createAccount(apiBaseUrl, token, {
18620
18872
  id: accountId,
18621
- name: providerName,
18873
+ name: providerName2,
18622
18874
  credentialId: activeCredentialId,
18623
18875
  providerId,
18624
18876
  ...merchantAuthorization ? {
@@ -18667,7 +18919,7 @@ function useProviderHandlers(deps) {
18667
18919
  return;
18668
18920
  }
18669
18921
  const provider = providers.find((p) => p.id === providerId);
18670
- const providerName = provider?.name ?? "Wallet";
18922
+ const providerName2 = provider?.name ?? "Wallet";
18671
18923
  let shouldRestoreDesktopSelectionOnError = shouldSnapshotDesktopSelection;
18672
18924
  try {
18673
18925
  await resetWalletConnect();
@@ -18690,7 +18942,7 @@ function useProviderHandlers(deps) {
18690
18942
  const newAccountId = crypto.randomUUID();
18691
18943
  const account = await createAccount(apiBaseUrl, token, {
18692
18944
  id: newAccountId,
18693
- name: providerName,
18945
+ name: providerName2,
18694
18946
  credentialId: activeCredentialId,
18695
18947
  providerId,
18696
18948
  ...merchantAuthorization ? {
@@ -20783,6 +21035,33 @@ function usePersistAmountToActiveSession({
20783
21035
  });
20784
21036
  }, [apiBaseUrl, sessionId, effectiveDepositAmount]);
20785
21037
  }
21038
+ function useFingerprintFlowEvents(deps) {
21039
+ const { ready, authenticated, merchantId } = deps;
21040
+ const { getData } = react$1.useVisitorData({ immediate: false });
21041
+ const openedSentRef = react.useRef(false);
21042
+ const authenticatedSentRef = react.useRef(false);
21043
+ react.useEffect(() => {
21044
+ if (openedSentRef.current) return;
21045
+ openedSentRef.current = true;
21046
+ void getData({
21047
+ tag: { event: "blink_opened", ...merchantId ? { merchantId } : {} },
21048
+ ...merchantId ? { linkedId: merchantId } : {}
21049
+ }).catch((error) => {
21050
+ console.error("Fingerprint blink_opened event failed", error);
21051
+ });
21052
+ }, [getData, merchantId]);
21053
+ react.useEffect(() => {
21054
+ if (authenticatedSentRef.current) return;
21055
+ if (!ready || !authenticated) return;
21056
+ authenticatedSentRef.current = true;
21057
+ void getData({
21058
+ tag: { event: "blink_authenticated", ...merchantId ? { merchantId } : {} },
21059
+ ...merchantId ? { linkedId: merchantId } : {}
21060
+ }).catch((error) => {
21061
+ console.error("Fingerprint blink_authenticated event failed", error);
21062
+ });
21063
+ }, [getData, ready, authenticated, merchantId]);
21064
+ }
20786
21065
  var NoMatchingExtensionError = class extends Error {
20787
21066
  constructor() {
20788
21067
  super("No installed EIP-6963 extension matches the selected wallet");
@@ -20821,6 +21100,11 @@ function BlinkPaymentInner({
20821
21100
  return true;
20822
21101
  })();
20823
21102
  const effectiveAuthenticated = authenticated || popupAuthValid;
21103
+ useFingerprintFlowEvents({
21104
+ ready,
21105
+ authenticated: effectiveAuthenticated,
21106
+ merchantId: merchantAuthorization?.merchantId
21107
+ });
20824
21108
  const effectiveGetAccessToken = react.useCallback(async () => {
20825
21109
  if (popupAuthRef.current) {
20826
21110
  if (isPopupAuthExpired(popupAuthRef.current.accessToken)) {
@@ -20836,7 +21120,7 @@ function BlinkPaymentInner({
20836
21120
  useWalletConnector: useWalletConnectorProp,
20837
21121
  userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
20838
21122
  });
20839
- const [state, dispatch] = react.useReducer(
21123
+ const [state, rawDispatch] = react.useReducer(
20840
21124
  paymentReducer,
20841
21125
  {
20842
21126
  depositAmount,
@@ -20846,6 +21130,30 @@ function BlinkPaymentInner({
20846
21130
  },
20847
21131
  createInitialState
20848
21132
  );
21133
+ const device = isDesktop ? "desktop" : "mobile";
21134
+ const stateRef = react.useRef(state);
21135
+ stateRef.current = state;
21136
+ const dispatch = react.useCallback(
21137
+ (action) => {
21138
+ trackAction(action, stateRef.current, { device });
21139
+ rawDispatch(action);
21140
+ },
21141
+ [device]
21142
+ );
21143
+ usePostHogIdentify();
21144
+ useAnalyticsScreenView(state.phase, device);
21145
+ const flowOpenedRef = react.useRef(false);
21146
+ react.useEffect(() => {
21147
+ if (flowOpenedRef.current) return;
21148
+ flowOpenedRef.current = true;
21149
+ registerSuperProps({ device });
21150
+ track("flow_opened", {
21151
+ device,
21152
+ isMobileApp: isMobileApp ?? false,
21153
+ fullWidget: enableFullWidget ?? false,
21154
+ hasAmount: depositAmount != null
21155
+ });
21156
+ }, []);
20849
21157
  const polling = useTransferPolling(3e3, effectiveGetAccessToken);
20850
21158
  const transferSigning = useTransferSigning(2e3, { getAccessToken: effectiveGetAccessToken });
20851
21159
  const mobileFlowRefs = {
@@ -21429,6 +21737,7 @@ function BlinkPaymentInner({
21429
21737
  selectedSource: derived.selectedSource,
21430
21738
  selectSourceChoices: sourceSelection.selectSourceChoices,
21431
21739
  selectSourceUnsupportedChoices: sourceSelection.selectSourceUnsupportedChoices,
21740
+ selectSourceNativeChoices: sourceSelection.selectSourceNativeChoices,
21432
21741
  selectSourceRecommended: sourceSelection.selectSourceRecommended,
21433
21742
  selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance,
21434
21743
  walletConnectChainIdsByAccount
@@ -21499,6 +21808,7 @@ exports.WalletPickerScreen = WalletPickerScreen;
21499
21808
  exports.WelcomeBackScreen = WelcomeBackScreen;
21500
21809
  exports.appendDebug = appendDebug;
21501
21810
  exports.blinkApi = api_exports;
21811
+ exports.buildNativeUnsupportedEntries = buildNativeUnsupportedEntries;
21502
21812
  exports.clearDebugEntries = clearDebugEntries;
21503
21813
  exports.createInitialState = createInitialState;
21504
21814
  exports.credentialIdBase64ToBytes = credentialIdBase64ToBytes;
@@ -21510,12 +21820,14 @@ exports.deviceHasPasskey = deviceHasPasskey;
21510
21820
  exports.encodePermit2ApproveCalldata = encodePermit2ApproveCalldata;
21511
21821
  exports.findDevicePasskey = findDevicePasskey;
21512
21822
  exports.findDevicePasskeyViaPopup = findDevicePasskeyViaPopup;
21823
+ exports.formatNativeAmount = formatNativeAmount;
21513
21824
  exports.getAtomicBatchSupportDebugInfo = getAtomicBatchSupportDebugInfo;
21514
21825
  exports.getDebugEntries = getDebugEntries;
21515
21826
  exports.getDeviceBiometricUnlockText = getDeviceBiometricUnlockText;
21516
21827
  exports.getTheme = getTheme;
21517
21828
  exports.getThemeBase = getThemeBase;
21518
21829
  exports.getWalletCapabilities = getWalletCapabilities;
21830
+ exports.identifyUser = identifyUser;
21519
21831
  exports.isAuthorizationSessionCancelled = isAuthorizationSessionCancelled;
21520
21832
  exports.isExpectedAuthorizationCancellation = isExpectedAuthorizationCancellation;
21521
21833
  exports.isTerminalTransferStatus = isTerminalTransferStatus;
@@ -21529,11 +21841,15 @@ exports.lightTransparentTheme = lightTransparentTheme;
21529
21841
  exports.lightTransparentThemeNew = lightTransparentThemeNew;
21530
21842
  exports.mapGuestPickerEntries = mapGuestPickerEntries;
21531
21843
  exports.replaceOpenProviderForAccountSwitch = replaceOpenProviderForAccountSwitch;
21844
+ exports.resetUser = resetUser;
21845
+ exports.resolveAnalyticsEnvironment = resolveAnalyticsEnvironment;
21532
21846
  exports.resolvePasskeyRpId = resolvePasskeyRpId;
21847
+ exports.sanitizeProps = sanitizeProps;
21533
21848
  exports.screenForPhase = screenForPhase;
21534
21849
  exports.subscribeDebug = subscribeDebug;
21535
21850
  exports.supportsAtomicBatch = supportsAtomicBatch;
21536
21851
  exports.supportsPaymasterService = supportsPaymasterService;
21852
+ exports.track = track;
21537
21853
  exports.useAuthorizationExecutor = useAuthorizationExecutor;
21538
21854
  exports.useAuthorizationOrchestrator = useAuthorizationOrchestrator;
21539
21855
  exports.useBlinkConfig = useBlinkConfig;