@swype-org/react-sdk 0.1.301 → 0.1.333

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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createContext, useRef, useState, useCallback, useMemo, useContext, useEffect, useReducer, Component } from 'react';
2
2
  import { PrivyProvider, usePrivy, useLoginWithOAuth, useLoginWithEmail, useLoginWithSms } from '@privy-io/react-auth';
3
3
  import { createConfig, http, WagmiProvider, useConfig, useConnect, useSwitchChain } from 'wagmi';
4
- import { mainnet, arbitrum, base, polygon, bsc } from 'wagmi/chains';
4
+ import { mainnet, arbitrum, base, polygon, bsc, baseSepolia } from 'wagmi/chains';
5
5
  import { injected } from 'wagmi/connectors';
6
6
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -75,14 +75,16 @@ function getTheme(mode) {
75
75
  }
76
76
  var BLINK_PRIVY_APP_ID = "cmlil87uv004n0ck0blwumwek";
77
77
  var wagmiConfig = createConfig({
78
- chains: [mainnet, arbitrum, base, polygon, bsc],
78
+ // baseSepolia: guest/testnet flows (e.g. smokebox e2e) call switchChain to the source chain from the API.
79
+ chains: [mainnet, arbitrum, base, polygon, bsc, baseSepolia],
79
80
  connectors: [injected({ shimDisconnect: true, unstable_shimAsyncInject: 2e3 })],
80
81
  transports: {
81
82
  [mainnet.id]: http(),
82
83
  [arbitrum.id]: http(),
83
84
  [base.id]: http(),
84
85
  [polygon.id]: http(),
85
- [bsc.id]: http()
86
+ [bsc.id]: http(),
87
+ [baseSepolia.id]: http()
86
88
  }
87
89
  });
88
90
  var BlinkContext = createContext(null);
@@ -492,6 +494,7 @@ __export(api_exports, {
492
494
  getGuestTransfer: () => getGuestTransfer,
493
495
  getTransferByGuestToken: () => getTransferByGuestToken,
494
496
  postGuestTransferFeeQuote: () => postGuestTransferFeeQuote,
497
+ postTransferQuote: () => postTransferQuote,
495
498
  putGuestTransferSender: () => putGuestTransferSender,
496
499
  registerPasskey: () => registerPasskey,
497
500
  reportActionCompletion: () => reportActionCompletion,
@@ -607,7 +610,8 @@ async function createTransfer(apiBaseUrl, token, params) {
607
610
  amount: {
608
611
  amount: params.amount,
609
612
  currency: params.currency ?? "USD"
610
- }
613
+ },
614
+ ...params.quoteId ? { quoteId: params.quoteId } : {}
611
615
  };
612
616
  const res = await fetch(`${apiBaseUrl}/v1/transfers`, {
613
617
  method: "POST",
@@ -620,6 +624,28 @@ async function createTransfer(apiBaseUrl, token, params) {
620
624
  if (!res.ok) await throwApiError(res);
621
625
  return await res.json();
622
626
  }
627
+ async function postTransferQuote(apiBaseUrl, bearerToken, params) {
628
+ const body = {
629
+ walletId: params.walletId,
630
+ ...params.sourceTokenAddress ? { sourceTokenAddress: params.sourceTokenAddress } : {},
631
+ destination: {
632
+ chainId: params.destination.chainId,
633
+ token: { address: params.destination.token.address },
634
+ address: params.destination.address
635
+ },
636
+ amount: params.amount
637
+ };
638
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/quotes`, {
639
+ method: "POST",
640
+ headers: {
641
+ "Content-Type": "application/json",
642
+ Authorization: `Bearer ${bearerToken}`
643
+ },
644
+ body: JSON.stringify(body)
645
+ });
646
+ if (!res.ok) await throwApiError(res);
647
+ return await res.json();
648
+ }
623
649
  async function fetchMerchantPublicKey(apiBaseUrl, merchantId) {
624
650
  const res = await fetch(
625
651
  `${apiBaseUrl}/v1/merchants/${encodeURIComponent(merchantId)}/public-key`
@@ -961,6 +987,23 @@ function normalizeSignature(sig) {
961
987
  );
962
988
  }
963
989
 
990
+ // src/authorizationErrors.ts
991
+ var AuthorizationSessionCancelledError = class extends Error {
992
+ constructor() {
993
+ super("Authorization session cancelled");
994
+ this.name = "AuthorizationSessionCancelledError";
995
+ }
996
+ };
997
+ function isAuthorizationSessionCancelled(err) {
998
+ if (err instanceof AuthorizationSessionCancelledError) return true;
999
+ return typeof err === "object" && err !== null && "name" in err && err.name === "AuthorizationSessionCancelledError";
1000
+ }
1001
+ function isUserDismissedAuthorizationError(err) {
1002
+ if (!(err instanceof Error)) return false;
1003
+ const m = err.message.toLowerCase();
1004
+ return m.includes("authorization session aborted") || m.includes("aborted by user");
1005
+ }
1006
+
964
1007
  // src/hooks/authorizationExecutor.ts
965
1008
  var WALLET_CLIENT_MAX_ATTEMPTS = 25;
966
1009
  var WALLET_CLIENT_POLL_MS = 400;
@@ -1274,39 +1317,80 @@ function useAuthorizationExecutor(options) {
1274
1317
  const [error, setError] = useState(null);
1275
1318
  const [currentAction, setCurrentAction] = useState(null);
1276
1319
  const executingRef = useRef(false);
1320
+ const oneTapPauseActiveRef = useRef(false);
1321
+ const sessionStackRef = useRef([]);
1322
+ const [authorizationSessionStackDepth, setAuthorizationSessionStackDepth] = useState(0);
1277
1323
  const [pendingSelectSource, setPendingSelectSource] = useState(null);
1278
1324
  const selectSourceResolverRef = useRef(null);
1325
+ const selectSourceRejectRef = useRef(null);
1279
1326
  const sessionIdRef = useRef(null);
1280
1327
  const resolveSelectSource = useCallback((selection) => {
1281
1328
  if (selectSourceResolverRef.current) {
1282
1329
  selectSourceResolverRef.current(selection);
1283
1330
  selectSourceResolverRef.current = null;
1331
+ selectSourceRejectRef.current = null;
1284
1332
  setPendingSelectSource(null);
1285
1333
  }
1286
1334
  }, []);
1287
1335
  const waitForSelection = useCallback(
1288
- (action) => new Promise((resolve) => {
1289
- selectSourceResolverRef.current = resolve;
1336
+ (action) => new Promise((resolve, reject) => {
1337
+ selectSourceResolverRef.current = (selection) => {
1338
+ resolve(selection);
1339
+ selectSourceResolverRef.current = null;
1340
+ selectSourceRejectRef.current = null;
1341
+ };
1342
+ selectSourceRejectRef.current = reject;
1290
1343
  setPendingSelectSource(action);
1291
1344
  }),
1292
1345
  []
1293
1346
  );
1294
1347
  const [pendingOneTapSetup, setPendingOneTapSetup] = useState(null);
1295
1348
  const oneTapSetupResolverRef = useRef(null);
1349
+ const oneTapSetupRejectRef = useRef(null);
1296
1350
  const resolveOneTapSetup = useCallback(() => {
1297
1351
  if (oneTapSetupResolverRef.current) {
1298
1352
  oneTapSetupResolverRef.current();
1299
1353
  oneTapSetupResolverRef.current = null;
1354
+ oneTapSetupRejectRef.current = null;
1300
1355
  setPendingOneTapSetup(null);
1301
1356
  }
1302
1357
  }, []);
1303
1358
  const waitForOneTapSetup = useCallback(
1304
- (action) => new Promise((resolve) => {
1305
- oneTapSetupResolverRef.current = resolve;
1359
+ (action) => new Promise((resolve, reject) => {
1360
+ oneTapPauseActiveRef.current = true;
1361
+ oneTapSetupResolverRef.current = () => {
1362
+ oneTapPauseActiveRef.current = false;
1363
+ resolve();
1364
+ oneTapSetupResolverRef.current = null;
1365
+ oneTapSetupRejectRef.current = null;
1366
+ };
1367
+ oneTapSetupRejectRef.current = (reason) => {
1368
+ oneTapPauseActiveRef.current = false;
1369
+ reject(reason);
1370
+ };
1306
1371
  setPendingOneTapSetup(action);
1307
1372
  }),
1308
1373
  []
1309
1374
  );
1375
+ const cancelPendingExecution = useCallback(() => {
1376
+ if (selectSourceRejectRef.current) {
1377
+ selectSourceRejectRef.current(new AuthorizationSessionCancelledError());
1378
+ selectSourceRejectRef.current = null;
1379
+ selectSourceResolverRef.current = null;
1380
+ setPendingSelectSource(null);
1381
+ }
1382
+ if (oneTapSetupRejectRef.current) {
1383
+ oneTapPauseActiveRef.current = false;
1384
+ oneTapSetupRejectRef.current(new AuthorizationSessionCancelledError());
1385
+ oneTapSetupRejectRef.current = null;
1386
+ oneTapSetupResolverRef.current = null;
1387
+ setPendingOneTapSetup(null);
1388
+ }
1389
+ setError(null);
1390
+ setCurrentAction(null);
1391
+ setExecuting(false);
1392
+ executingRef.current = false;
1393
+ }, []);
1310
1394
  const dispatchAction = useCallback(
1311
1395
  async (action) => {
1312
1396
  setCurrentAction(action);
@@ -1341,20 +1425,26 @@ function useAuthorizationExecutor(options) {
1341
1425
  );
1342
1426
  const executeSessionById = useCallback(
1343
1427
  async (sessionId) => {
1344
- if (executingRef.current) return;
1345
- executingRef.current = true;
1346
1428
  if (!sessionId) {
1347
- executingRef.current = false;
1348
1429
  throw new Error("No authorization session id provided.");
1349
1430
  }
1350
1431
  if (!apiBaseUrl) {
1351
- executingRef.current = false;
1352
1432
  throw new Error("Missing apiBaseUrl. Provide useAuthorizationExecutor({ apiBaseUrl }) or wrap in <BlinkProvider>.");
1353
1433
  }
1354
- sessionIdRef.current = sessionId;
1355
- setExecuting(true);
1434
+ const allowNested = executingRef.current && oneTapPauseActiveRef.current;
1435
+ if (executingRef.current && !allowNested) {
1436
+ return;
1437
+ }
1438
+ const isNestedRun = allowNested;
1439
+ if (!isNestedRun) {
1440
+ executingRef.current = true;
1441
+ setExecuting(true);
1442
+ setResults([]);
1443
+ }
1356
1444
  setError(null);
1357
- setResults([]);
1445
+ sessionStackRef.current.push(sessionId);
1446
+ setAuthorizationSessionStackDepth(sessionStackRef.current.length);
1447
+ sessionIdRef.current = sessionId;
1358
1448
  try {
1359
1449
  let session = await fetchAuthorizationSession(apiBaseUrl, sessionId);
1360
1450
  const allResults = [];
@@ -1390,13 +1480,23 @@ function useAuthorizationExecutor(options) {
1390
1480
  pending = getPendingActions(session, completedIds);
1391
1481
  }
1392
1482
  } catch (err) {
1393
- const msg = err instanceof Error ? err.message : "Authorization failed";
1394
- setError(msg);
1483
+ if (isAuthorizationSessionCancelled(err)) {
1484
+ setError(null);
1485
+ } else {
1486
+ const msg = err instanceof Error ? err.message : "Authorization failed";
1487
+ setError(msg);
1488
+ }
1395
1489
  throw err;
1396
1490
  } finally {
1491
+ sessionStackRef.current.pop();
1492
+ const depth = sessionStackRef.current.length;
1493
+ setAuthorizationSessionStackDepth(depth);
1494
+ sessionIdRef.current = depth > 0 ? sessionStackRef.current[depth - 1] : null;
1397
1495
  setCurrentAction(null);
1398
- setExecuting(false);
1399
- executingRef.current = false;
1496
+ if (depth === 0) {
1497
+ setExecuting(false);
1498
+ executingRef.current = false;
1499
+ }
1400
1500
  }
1401
1501
  },
1402
1502
  [apiBaseUrl, dispatchAction]
@@ -1410,7 +1510,9 @@ function useAuthorizationExecutor(options) {
1410
1510
  resolveSelectSource,
1411
1511
  pendingOneTapSetup,
1412
1512
  resolveOneTapSetup,
1413
- executeSessionById
1513
+ executeSessionById,
1514
+ cancelPendingExecution,
1515
+ authorizationSessionStackDepth
1414
1516
  };
1415
1517
  }
1416
1518
  var TRANSFER_SIGN_MAX_POLLS = 60;
@@ -1640,6 +1742,37 @@ function getPreferredDepositWallet(account, transferAmount) {
1640
1742
  function getDepositEligibleAccounts(accounts) {
1641
1743
  return accounts.filter((account) => getAddressableWallets(account).length > 0);
1642
1744
  }
1745
+ function resolveDepositSelectionAfterRefresh(accounts, transferAmount, prev) {
1746
+ const { selectedAccountId, selectedWalletId, selectedTokenSymbol } = prev;
1747
+ if (selectedAccountId && selectedWalletId) {
1748
+ const acct = accounts.find((a) => a.id === selectedAccountId);
1749
+ const wallet = acct?.wallets.find((w) => w.id === selectedWalletId);
1750
+ if (wallet) {
1751
+ if (selectedTokenSymbol) {
1752
+ const hasToken = wallet.sources.some((s) => s.token.symbol === selectedTokenSymbol);
1753
+ if (hasToken) {
1754
+ return {
1755
+ defaults: { accountId: selectedAccountId, walletId: selectedWalletId },
1756
+ resetSelectedTokenSymbol: false
1757
+ };
1758
+ }
1759
+ const fallback = resolveDepositSelection(accounts, transferAmount, selectedAccountId);
1760
+ return {
1761
+ defaults: fallback,
1762
+ resetSelectedTokenSymbol: true
1763
+ };
1764
+ }
1765
+ return {
1766
+ defaults: { accountId: selectedAccountId, walletId: selectedWalletId },
1767
+ resetSelectedTokenSymbol: false
1768
+ };
1769
+ }
1770
+ }
1771
+ return {
1772
+ defaults: resolveDepositSelection(accounts, transferAmount, selectedAccountId),
1773
+ resetSelectedTokenSymbol: false
1774
+ };
1775
+ }
1643
1776
  function resolveDepositSelection(accounts, transferAmount, selectedAccountId) {
1644
1777
  const eligibleAccounts = getDepositEligibleAccounts(accounts);
1645
1778
  if (eligibleAccounts.length === 0) return null;
@@ -1706,6 +1839,32 @@ function buildSelectSourceChoices(options) {
1706
1839
  tokens: chain.tokens.filter((t) => t.balance > 0).sort((a, b) => b.balance - a.balance)
1707
1840
  })).filter((chain) => chain.tokens.length > 0).sort((a, b) => b.balance - a.balance);
1708
1841
  }
1842
+ function resolveSelectSourceAvailableBalance(choices, options, chainName, tokenSymbol, recommended) {
1843
+ const chain = chainName.trim();
1844
+ const token = tokenSymbol.trim();
1845
+ if (chain && token) {
1846
+ const chainChoice = choices.find((c) => c.chainName === chain);
1847
+ const row = chainChoice?.tokens.find((t) => t.tokenSymbol === token);
1848
+ if (row !== void 0) return row.balance;
1849
+ const direct = options.find(
1850
+ (opt) => opt.chainName === chain && opt.tokenSymbol === token
1851
+ );
1852
+ if (direct) return parseRawBalance(direct.rawBalance, direct.decimals);
1853
+ return 0;
1854
+ }
1855
+ if (recommended) {
1856
+ const match = options.find(
1857
+ (opt) => opt.chainName === recommended.chainName && opt.tokenSymbol === recommended.tokenSymbol
1858
+ );
1859
+ if (match) return parseRawBalance(match.rawBalance, match.decimals);
1860
+ }
1861
+ let max = 0;
1862
+ for (const opt of options) {
1863
+ const bal = parseRawBalance(opt.rawBalance, opt.decimals);
1864
+ if (bal > max) max = bal;
1865
+ }
1866
+ return max;
1867
+ }
1709
1868
 
1710
1869
  // src/walletFlow.ts
1711
1870
  var MOBILE_USER_AGENT_PATTERN = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
@@ -1789,11 +1948,12 @@ function resolvePhase(state) {
1789
1948
  const isFundingSourceSubflow = !state.loginRequested && (currentPhase.step === "token-picker" || currentPhase.step === "one-tap-setup" || currentPhase.step === "select-source" || currentPhase.step === "confirm-sign" || currentPhase.step === "guest-token-picker" && guestTokenPickerEligible);
1790
1949
  const walletPickerSwitchEligible = currentPhase.step === "wallet-picker" && currentPhase.reason === "switch" && !state.creatingTransfer && !(state.mobileFlow && state.deeplinkUri);
1791
1950
  const missingActivePasskeyCredential = state.passkeyConfigLoaded && !state.activeCredentialId;
1792
- const shouldPromptPasskeyVerification = missingActivePasskeyCredential && state.knownCredentialIds.length > 0 && state.passkeyPopupNeeded;
1951
+ const shouldPromptPasskeyVerification = missingActivePasskeyCredential && state.knownCredentialIds.length > 0;
1952
+ const guestPreauthClaimPending = state.guestPreauthAccountId != null && state.guestSessionToken != null && state.privyAuthenticated && state.activeCredentialId != null && !state.guestPreauthSetupCompletePending && !state.error;
1793
1953
  const branchGuestSetupComplete = state.guestPreauthSetupCompletePending && state.privyReady && state.privyAuthenticated;
1794
1954
  const branchKeepGuestPreauthPin = !branchGuestSetupComplete && guestPreauthPinsCurrentPhase;
1795
1955
  const branchGuestPostPayLogin = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && guestPostPayLogin;
1796
- const branchCompleted = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && transferCompleted && !state.verificationTarget && !needsPasskeyBootstrap;
1956
+ const branchCompleted = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && transferCompleted && !state.verificationTarget && !needsPasskeyBootstrap && !guestPreauthClaimPending && !state.loginRequested;
1797
1957
  const branchFailed = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && state.transfer?.status === "FAILED";
1798
1958
  const branchProcessing = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && (state.creatingTransfer || isTransferAwaitingCompletion(state.transfer));
1799
1959
  const branchStandardDesktopInlineOpenWallet = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && state.standardDesktopInlineOpenWallet && state.privyAuthenticated && state.activeCredentialId != null && state.selectedAccountId != null && !state.loginRequested && !state.guestPreauthorizing;
@@ -1809,7 +1969,7 @@ function resolvePhase(state) {
1809
1969
  const branchLoginRequested = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && !branchKeepFundingSubflow && !branchMobileWalletSetup && !branchStandardDesktopInlineOpenWallet && !branchKeepGuestPreauthDesktopOpenWallet && !branchKeepGuestWalletSetup && !branchGuestTokenPicker && !branchKeepWalletPickerSwitch && !branchInitializingPrivy && !branchInitializingPasskeyConfig && !branchOtpVerify && state.loginRequested;
1810
1970
  const branchPasskeyVerify = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && !branchKeepFundingSubflow && !branchMobileWalletSetup && !branchStandardDesktopInlineOpenWallet && !branchKeepGuestPreauthDesktopOpenWallet && !branchKeepGuestWalletSetup && !branchGuestTokenPicker && !branchKeepWalletPickerSwitch && !branchInitializingPrivy && !branchInitializingPasskeyConfig && !branchOtpVerify && !branchLoginRequested && shouldPromptPasskeyVerification;
1811
1971
  const branchPasskeyCreate = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && !branchKeepFundingSubflow && !branchMobileWalletSetup && !branchStandardDesktopInlineOpenWallet && !branchKeepGuestPreauthDesktopOpenWallet && !branchKeepGuestWalletSetup && !branchGuestTokenPicker && !branchKeepWalletPickerSwitch && !branchInitializingPrivy && !branchInitializingPasskeyConfig && !branchOtpVerify && !branchLoginRequested && !branchPasskeyVerify && missingActivePasskeyCredential;
1812
- const branchGuestPreauthClaiming = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && !branchKeepFundingSubflow && !branchMobileWalletSetup && !branchStandardDesktopInlineOpenWallet && !branchKeepGuestPreauthDesktopOpenWallet && !branchKeepGuestWalletSetup && !branchGuestTokenPicker && !branchKeepWalletPickerSwitch && !branchInitializingPrivy && !branchInitializingPasskeyConfig && !branchOtpVerify && !branchLoginRequested && !branchPasskeyVerify && !branchPasskeyCreate && state.guestPreauthAccountId != null && state.guestSessionToken != null && state.privyAuthenticated && state.activeCredentialId != null && !state.guestPreauthSetupCompletePending && !state.error;
1972
+ const branchGuestPreauthClaiming = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && !branchKeepFundingSubflow && !branchMobileWalletSetup && !branchStandardDesktopInlineOpenWallet && !branchKeepGuestPreauthDesktopOpenWallet && !branchKeepGuestWalletSetup && !branchGuestTokenPicker && !branchKeepWalletPickerSwitch && !branchInitializingPrivy && !branchInitializingPasskeyConfig && !branchOtpVerify && !branchLoginRequested && !branchPasskeyVerify && !branchPasskeyCreate && guestPreauthClaimPending;
1813
1973
  const branchDataLoading = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && !branchKeepFundingSubflow && !branchMobileWalletSetup && !branchStandardDesktopInlineOpenWallet && !branchKeepGuestPreauthDesktopOpenWallet && !branchKeepGuestWalletSetup && !branchGuestTokenPicker && !branchKeepWalletPickerSwitch && !branchInitializingPrivy && !branchInitializingPasskeyConfig && !branchOtpVerify && !branchLoginRequested && !branchPasskeyVerify && !branchPasskeyCreate && !branchGuestPreauthClaiming && state.loadingData && state.activeCredentialId != null && hasActiveWallet(state.accounts);
1814
1974
  const branchWalletPickerLink = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && !branchKeepFundingSubflow && !branchMobileWalletSetup && !branchStandardDesktopInlineOpenWallet && !branchKeepGuestPreauthDesktopOpenWallet && !branchKeepGuestWalletSetup && !branchGuestTokenPicker && !branchKeepWalletPickerSwitch && !branchInitializingPrivy && !branchInitializingPasskeyConfig && !branchOtpVerify && !branchLoginRequested && !branchPasskeyVerify && !branchPasskeyCreate && !branchGuestPreauthClaiming && !branchDataLoading && state.activeCredentialId != null && !hasActiveWallet(state.accounts) && !state.mobileFlow;
1815
1975
  const branchDeposit = !branchGuestSetupComplete && !branchKeepGuestPreauthPin && !branchGuestPostPayLogin && !branchCompleted && !branchFailed && !branchProcessing && !branchKeepFundingSubflow && !branchMobileWalletSetup && !branchStandardDesktopInlineOpenWallet && !branchKeepGuestPreauthDesktopOpenWallet && !branchKeepGuestWalletSetup && !branchGuestTokenPicker && !branchKeepWalletPickerSwitch && !branchInitializingPrivy && !branchInitializingPasskeyConfig && !branchOtpVerify && !branchLoginRequested && !branchPasskeyVerify && !branchPasskeyCreate && !branchGuestPreauthClaiming && !branchDataLoading && !branchWalletPickerLink && state.activeCredentialId != null && hasActiveWallet(state.accounts) && !state.loadingData;
@@ -1980,6 +2140,7 @@ function createInitialState(config) {
1980
2140
  selectedAccountId: null,
1981
2141
  selectedWalletId: null,
1982
2142
  selectedTokenSymbol: null,
2143
+ savedSelection: null,
1983
2144
  amount: config.depositAmount != null ? config.depositAmount.toString() : "",
1984
2145
  transfer: null,
1985
2146
  creatingTransfer: false,
@@ -2006,7 +2167,8 @@ function createInitialState(config) {
2006
2167
  standardDesktopInlineOpenWallet: false,
2007
2168
  guestPreauthSetupCompletePending: false,
2008
2169
  privyReady: false,
2009
- privyAuthenticated: false
2170
+ privyAuthenticated: false,
2171
+ lastResumedAt: 0
2010
2172
  };
2011
2173
  }
2012
2174
  function paymentReducer(state, action) {
@@ -2104,6 +2266,9 @@ function applyAction(state, action) {
2104
2266
  next.mobileFlow = false;
2105
2267
  next.deeplinkUri = null;
2106
2268
  }
2269
+ if (action.resetSelectedTokenSymbol) {
2270
+ next.selectedTokenSymbol = null;
2271
+ }
2107
2272
  return next;
2108
2273
  }
2109
2274
  case "DATA_LOAD_END":
@@ -2118,8 +2283,43 @@ function applyAction(state, action) {
2118
2283
  next.selectedAccountId = action.defaults.accountId;
2119
2284
  next.selectedWalletId = action.defaults.walletId;
2120
2285
  }
2286
+ if (action.resetSelectedTokenSymbol) {
2287
+ next.selectedTokenSymbol = null;
2288
+ }
2121
2289
  return next;
2122
2290
  }
2291
+ case "SAVE_SELECTION":
2292
+ return {
2293
+ ...state,
2294
+ savedSelection: {
2295
+ selectedProviderId: state.selectedProviderId,
2296
+ selectedAccountId: state.selectedAccountId,
2297
+ selectedWalletId: state.selectedWalletId,
2298
+ selectedTokenSymbol: state.selectedTokenSymbol
2299
+ }
2300
+ };
2301
+ case "RESTORE_SELECTION": {
2302
+ const snap = state.savedSelection;
2303
+ if (!snap) {
2304
+ return {
2305
+ ...state,
2306
+ error: null,
2307
+ increasingLimit: false
2308
+ };
2309
+ }
2310
+ return {
2311
+ ...state,
2312
+ selectedProviderId: snap.selectedProviderId,
2313
+ selectedAccountId: snap.selectedAccountId,
2314
+ selectedWalletId: snap.selectedWalletId,
2315
+ selectedTokenSymbol: snap.selectedTokenSymbol,
2316
+ savedSelection: null,
2317
+ error: null,
2318
+ increasingLimit: false
2319
+ };
2320
+ }
2321
+ case "DISCARD_SAVED_SELECTION":
2322
+ return { ...state, savedSelection: null };
2123
2323
  // ── Source selection ──────────────────────────────────────────
2124
2324
  case "SELECT_PROVIDER":
2125
2325
  return {
@@ -2414,7 +2614,8 @@ function applyAction(state, action) {
2414
2614
  oneTapLimitSavedDuringSetup: false,
2415
2615
  guestPreauthorizing: false,
2416
2616
  guestPreauthSetupCompletePending: false,
2417
- standardDesktopInlineOpenWallet: false
2617
+ standardDesktopInlineOpenWallet: false,
2618
+ savedSelection: null
2418
2619
  };
2419
2620
  case "LOGOUT":
2420
2621
  return {
@@ -2437,6 +2638,8 @@ function applyAction(state, action) {
2437
2638
  };
2438
2639
  case "SYNC_AMOUNT":
2439
2640
  return { ...state, amount: action.amount };
2641
+ case "PAGE_RESUMED":
2642
+ return { ...state, lastResumedAt: Date.now() };
2440
2643
  default:
2441
2644
  return state;
2442
2645
  }
@@ -2526,6 +2729,41 @@ function screenForPhase(phase) {
2526
2729
  return "guest-preauth-linking";
2527
2730
  }
2528
2731
  }
2732
+
2733
+ // src/depositTokenSelection.ts
2734
+ function tokenOptionsForLinkedAccount(selectedAccount, chains) {
2735
+ if (!selectedAccount) return [];
2736
+ return selectedAccount.wallets.flatMap((w) => {
2737
+ const evmChainId = chains.find((c) => c.name === w.chain.name)?.commonId ?? void 0;
2738
+ return w.sources.filter((s) => s.balance.total.amount > 0).map((s) => ({
2739
+ symbol: s.token.symbol,
2740
+ chainName: w.chain.name,
2741
+ balance: s.balance.available.amount,
2742
+ walletId: w.id,
2743
+ status: s.token.status,
2744
+ tokenAddress: s.address,
2745
+ chainId: evmChainId
2746
+ }));
2747
+ });
2748
+ }
2749
+ function handleInlineTokenSelection(handlers, chains, selectedAccount, symbol, chainName, walletId) {
2750
+ if (walletId && selectedAccount) {
2751
+ const wallet = selectedAccount.wallets.find((w) => w.id === walletId);
2752
+ if (wallet && wallet.chain.name === chainName) {
2753
+ const source = wallet.sources.find((s) => s.token.symbol === symbol);
2754
+ const evmChainId = chains.find((c) => c.name === chainName)?.commonId ?? void 0;
2755
+ const authorized = !source?.token.status || source.token.status === "AUTHORIZED";
2756
+ if (source && !authorized && source.address && evmChainId != null) {
2757
+ void handlers.onAuthorizeToken(walletId, source.address, evmChainId, symbol);
2758
+ return;
2759
+ }
2760
+ }
2761
+ handlers.onSelectAuthorizedToken(walletId, symbol);
2762
+ return;
2763
+ }
2764
+ handlers.onSelectSourceChainChange(chainName);
2765
+ handlers.onSetSelectSourceTokenSymbol(symbol);
2766
+ }
2529
2767
  var MUTED = "#7fa4b0";
2530
2768
  var LOGO_SIZE = 48;
2531
2769
  function BlinkLoadingScreen() {
@@ -3519,16 +3757,33 @@ function PasskeyScreen({
3519
3757
  creating,
3520
3758
  error,
3521
3759
  popupFallback = false,
3522
- onCreatePasskeyViaPopup
3760
+ onCreatePasskeyViaPopup,
3761
+ onCreateNewPasskey,
3762
+ onCreateNewPasskeyViaPopup,
3763
+ createNewPopupFallback,
3764
+ creatingNewPasskey
3523
3765
  }) {
3524
3766
  const { tokens } = useBlinkConfig();
3525
3767
  const handleCreate = popupFallback && onCreatePasskeyViaPopup ? onCreatePasskeyViaPopup : onCreatePasskey;
3526
3768
  const buttonLabel = popupFallback ? "Open Passkey Window" : "Verify Passkey";
3769
+ const showCreateNewLink = onCreateNewPasskey != null;
3770
+ const usePopupForNew = createNewPopupFallback ?? popupFallback;
3771
+ const handleCreateNew = usePopupForNew && onCreateNewPasskeyViaPopup ? onCreateNewPasskeyViaPopup : onCreateNewPasskey;
3527
3772
  return /* @__PURE__ */ jsxs(
3528
3773
  ScreenLayout,
3529
3774
  {
3530
3775
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
3531
- /* @__PURE__ */ jsx(PrimaryButton, { onClick: handleCreate, disabled: creating, loading: creating, children: buttonLabel }),
3776
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: handleCreate, disabled: creating || creatingNewPasskey, loading: creating, children: buttonLabel }),
3777
+ showCreateNewLink && /* @__PURE__ */ jsx(
3778
+ "button",
3779
+ {
3780
+ type: "button",
3781
+ onClick: handleCreateNew,
3782
+ disabled: creatingNewPasskey || creating,
3783
+ style: createNewLinkStyle(tokens.textMuted),
3784
+ children: creatingNewPasskey ? "Creating passkey\u2026" : "Create a new passkey for this device"
3785
+ }
3786
+ ),
3532
3787
  /* @__PURE__ */ jsx(PoweredByFooter, {})
3533
3788
  ] }),
3534
3789
  children: [
@@ -3563,6 +3818,17 @@ var subtitleStyle3 = (color) => ({
3563
3818
  margin: "0 0 20px",
3564
3819
  lineHeight: 1.5
3565
3820
  });
3821
+ var createNewLinkStyle = (color) => ({
3822
+ background: "none",
3823
+ border: "none",
3824
+ color,
3825
+ fontSize: "0.85rem",
3826
+ cursor: "pointer",
3827
+ padding: "8px 16px",
3828
+ textDecoration: "underline",
3829
+ fontFamily: "inherit",
3830
+ width: "100%"
3831
+ });
3566
3832
  var errorBannerStyle2 = (tokens) => ({
3567
3833
  background: tokens.errorBg,
3568
3834
  border: `1px solid ${tokens.error}66`,
@@ -4078,6 +4344,22 @@ var loginButtonStyle = (accentColor) => ({
4078
4344
  fontFamily: "inherit",
4079
4345
  textDecoration: "underline"
4080
4346
  });
4347
+
4348
+ // src/setupScreenSelection.ts
4349
+ function matchesSetupTokenSelection(opt, selectedTokenSymbol, selectedChainName, allOptions) {
4350
+ if (!selectedTokenSymbol || opt.symbol !== selectedTokenSymbol) {
4351
+ return false;
4352
+ }
4353
+ const chain = selectedChainName?.trim();
4354
+ if (chain) {
4355
+ return opt.chainName === chain;
4356
+ }
4357
+ const sameSymbol = allOptions.filter((o) => o.symbol === selectedTokenSymbol);
4358
+ if (sameSymbol.length === 1) {
4359
+ return opt.chainName === sameSymbol[0].chainName;
4360
+ }
4361
+ return false;
4362
+ }
4081
4363
  var DEFAULT_MAX = 1e7;
4082
4364
  var ABSOLUTE_MIN = 0.01;
4083
4365
  var PRESETS = [100, 250, 1e3];
@@ -4093,13 +4375,16 @@ function SetupScreen({
4093
4375
  loading,
4094
4376
  error,
4095
4377
  selectedTokenSymbol,
4378
+ selectedChainName,
4096
4379
  tokenOptions,
4097
4380
  onSelectToken
4098
4381
  }) {
4099
4382
  const { tokens } = useBlinkConfig();
4100
4383
  const effectiveMax = DEFAULT_MAX;
4101
4384
  const effectiveMin = Math.min(ABSOLUTE_MIN, effectiveMax);
4102
- const [limit, setLimit] = useState(() => Math.min(availableBalance, effectiveMax));
4385
+ const autoLimit = Math.min(Math.max(availableBalance, 0), effectiveMax);
4386
+ const [userChosenLimit, setUserChosenLimit] = useState(null);
4387
+ const limit = userChosenLimit ?? autoLimit;
4103
4388
  const [activePreset, setActivePreset] = useState(null);
4104
4389
  const [showAdvanced, setShowAdvanced] = useState(false);
4105
4390
  const [editing, setEditing] = useState(false);
@@ -4138,20 +4423,22 @@ function SetupScreen({
4138
4423
  const commitEdit = useCallback(() => {
4139
4424
  const parsed = parseFloat(inputValue);
4140
4425
  if (!isNaN(parsed)) {
4141
- setLimit(Math.min(effectiveMax, Math.max(effectiveMin, Math.round(parsed * 100) / 100)));
4426
+ setUserChosenLimit(
4427
+ Math.min(effectiveMax, Math.max(effectiveMin, Math.round(parsed * 100) / 100))
4428
+ );
4142
4429
  }
4143
4430
  setActivePreset(null);
4144
4431
  setEditing(false);
4145
4432
  }, [inputValue, effectiveMax, effectiveMin]);
4146
4433
  const selectPreset = (value) => {
4147
- setLimit(Math.min(value, effectiveMax));
4434
+ setUserChosenLimit(Math.min(value, effectiveMax));
4148
4435
  setActivePreset(value);
4149
4436
  };
4150
4437
  const selectMax = () => {
4151
- setLimit(Math.min(availableBalance, effectiveMax));
4438
+ setUserChosenLimit(autoLimit);
4152
4439
  setActivePreset("max");
4153
4440
  };
4154
- const selectedOption = tokenOptions?.find((o) => o.symbol === selectedTokenSymbol);
4441
+ const options = tokenOptions ?? [];
4155
4442
  return /* @__PURE__ */ jsxs(
4156
4443
  ScreenLayout,
4157
4444
  {
@@ -4184,12 +4471,7 @@ function SetupScreen({
4184
4471
  children: [
4185
4472
  /* @__PURE__ */ jsx("span", { style: tokenRowLabelStyle(tokens.text), children: "Token for one tap" }),
4186
4473
  /* @__PURE__ */ jsxs("div", { style: tokenRowRightStyle, children: [
4187
- selectedOption && /* @__PURE__ */ jsxs("span", { style: tokenRowSymbolStyle(tokens.textSecondary), children: [
4188
- selectedOption.symbol,
4189
- " \xB7 ",
4190
- selectedOption.chainName
4191
- ] }),
4192
- /* @__PURE__ */ jsx("div", { style: tokenIconWrapStyle, children: selectedTokenSymbol && TOKEN_LOGOS[selectedTokenSymbol] ? /* @__PURE__ */ jsx("img", { src: TOKEN_LOGOS[selectedTokenSymbol], alt: selectedTokenSymbol, width: 36, height: 36, style: { borderRadius: "50%" } }) : /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 36 36", fill: "none", children: [
4474
+ /* @__PURE__ */ jsx("div", { style: tokenIconWrapStyle, children: selectedTokenSymbol && TOKEN_LOGOS[selectedTokenSymbol] ? /* @__PURE__ */ jsx("img", { src: TOKEN_LOGOS[selectedTokenSymbol], alt: "", width: 36, height: 36, style: { borderRadius: "50%" } }) : /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 36 36", fill: "none", children: [
4193
4475
  /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "18", fill: "#2DB84B" }),
4194
4476
  /* @__PURE__ */ jsx("text", { x: "18", y: "23", textAnchor: "middle", fontSize: "18", fill: "#fff", fontWeight: "700", children: "$" })
4195
4477
  ] }) }),
@@ -4201,14 +4483,21 @@ function SetupScreen({
4201
4483
  tokenDropdownOpen && tokenOptions && tokenOptions.length > 0 && /* @__PURE__ */ jsxs("div", { style: dropdownOuterStyle(tokens), children: [
4202
4484
  /* @__PURE__ */ jsx("div", { style: dropdownLabelStyle(tokens.textMuted), children: "Choose token" }),
4203
4485
  /* @__PURE__ */ jsx("div", { style: dropdownInnerStyle(tokens), children: tokenOptions.map((opt, index) => {
4204
- const selected = opt.symbol === selectedTokenSymbol;
4486
+ const selected = matchesSetupTokenSelection(
4487
+ opt,
4488
+ selectedTokenSymbol,
4489
+ selectedChainName,
4490
+ options
4491
+ );
4205
4492
  const isLast = index === tokenOptions.length - 1;
4493
+ const authorized = !opt.status || opt.status === "AUTHORIZED";
4206
4494
  return /* @__PURE__ */ jsxs(
4207
4495
  "button",
4208
4496
  {
4209
4497
  type: "button",
4210
4498
  onClick: () => handlePickToken(opt),
4211
4499
  style: dropdownRowStyle(tokens, selected, isLast),
4500
+ "aria-label": opt.balance != null ? `${opt.symbol} on ${opt.chainName}, $${opt.balance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })} balance${!authorized ? ", not authorized" : ""}` : `${opt.symbol} on ${opt.chainName}${!authorized ? ", not authorized" : ""}`,
4212
4501
  children: [
4213
4502
  /* @__PURE__ */ jsxs("div", { style: dropdownRowLeftStyle, children: [
4214
4503
  /* @__PURE__ */ jsx("div", { style: dropdownTokenIconStyle(tokens, !!TOKEN_LOGOS[opt.symbol]), children: TOKEN_LOGOS[opt.symbol] ? /* @__PURE__ */ jsx("img", { src: TOKEN_LOGOS[opt.symbol], alt: opt.symbol, style: dropdownTokenLogoStyle }) : /* @__PURE__ */ jsx("span", { style: dropdownTokenFallbackStyle(tokens.textMuted), children: "$" }) }),
@@ -4218,9 +4507,12 @@ function SetupScreen({
4218
4507
  /* @__PURE__ */ jsx("span", { style: dropdownTokenDotStyle(tokens.textMuted), children: "\xB7" }),
4219
4508
  /* @__PURE__ */ jsx("span", { style: dropdownTokenChainStyle(tokens.textMuted), children: opt.chainName })
4220
4509
  ] }),
4221
- opt.balance != null && /* @__PURE__ */ jsxs("span", { style: dropdownTokenBalanceStyle(tokens.textMuted), children: [
4222
- "$",
4223
- opt.balance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
4510
+ /* @__PURE__ */ jsxs("div", { style: dropdownTokenBalanceRowStyle, children: [
4511
+ opt.balance != null && /* @__PURE__ */ jsxs("span", { style: dropdownTokenBalanceStyle(tokens.textMuted), children: [
4512
+ "$",
4513
+ opt.balance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
4514
+ ] }),
4515
+ !authorized && /* @__PURE__ */ jsx("span", { style: dropdownNotAuthorizedStyle(tokens.textMuted), children: "Not authorized" })
4224
4516
  ] })
4225
4517
  ] })
4226
4518
  ] }),
@@ -4340,11 +4632,6 @@ var tokenRowRightStyle = {
4340
4632
  gap: 6,
4341
4633
  flexShrink: 0
4342
4634
  };
4343
- var tokenRowSymbolStyle = (color) => ({
4344
- fontSize: "0.84rem",
4345
- fontWeight: 500,
4346
- color
4347
- });
4348
4635
  var advancedToggleStyle = (accentColor) => ({
4349
4636
  display: "block",
4350
4637
  margin: "4px auto 24px",
@@ -4492,10 +4779,20 @@ var dropdownTokenChainStyle = (color) => ({
4492
4779
  fontWeight: 400,
4493
4780
  color
4494
4781
  });
4782
+ var dropdownTokenBalanceRowStyle = {
4783
+ display: "flex",
4784
+ alignItems: "center",
4785
+ gap: 8
4786
+ };
4495
4787
  var dropdownTokenBalanceStyle = (color) => ({
4496
4788
  fontSize: "0.78rem",
4497
4789
  color
4498
4790
  });
4791
+ var dropdownNotAuthorizedStyle = (color) => ({
4792
+ fontSize: "0.7rem",
4793
+ fontWeight: 500,
4794
+ color
4795
+ });
4499
4796
  var dropdownRadioEmptyStyle = (borderColor) => ({
4500
4797
  width: 22,
4501
4798
  height: 22,
@@ -4610,6 +4907,38 @@ var waitHintStyle = (color) => ({
4610
4907
  color,
4611
4908
  margin: 0
4612
4909
  });
4910
+
4911
+ // src/feeFormat.ts
4912
+ function isPreciseMoneyNonPositive(fee) {
4913
+ const raw = fee.value.trim();
4914
+ if (!/^-?\d+(\.\d*)?$/.test(raw)) return false;
4915
+ const n = Number(raw);
4916
+ return Number.isFinite(n) && n <= 0;
4917
+ }
4918
+ function formatNonPositiveFeeDisplay(fee) {
4919
+ if (fee.currency === "USD") return "Under $0.01";
4920
+ return `Less than 0.01 ${fee.currency}`;
4921
+ }
4922
+ function formatPreciseMoneyForDisplay(fee) {
4923
+ const raw = fee.value.trim();
4924
+ if (fee.currency === "USD") {
4925
+ if (!/^\d+(\.\d*)?$/.test(raw)) {
4926
+ return `$${raw}`;
4927
+ }
4928
+ const [whole, frac = ""] = raw.split(".");
4929
+ const dec = `${frac}00`.slice(0, 2);
4930
+ const intFmt = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
4931
+ return `$${intFmt}.${dec}`;
4932
+ }
4933
+ return `${raw} ${fee.currency}`;
4934
+ }
4935
+ function formatUsdTwoDecimals(value) {
4936
+ const n = Number(value);
4937
+ return (Number.isFinite(n) ? n : 0).toLocaleString("en-US", {
4938
+ minimumFractionDigits: 2,
4939
+ maximumFractionDigits: 2
4940
+ });
4941
+ }
4613
4942
  function DepositScreen({
4614
4943
  merchantName,
4615
4944
  availableBalance,
@@ -4617,6 +4946,8 @@ function DepositScreen({
4617
4946
  tokenCount,
4618
4947
  initialAmount,
4619
4948
  minDepositFloor,
4949
+ quoteFee,
4950
+ quoteLoading,
4620
4951
  processing,
4621
4952
  error,
4622
4953
  onDeposit,
@@ -4631,13 +4962,19 @@ function DepositScreen({
4631
4962
  onAuthorizeAccount,
4632
4963
  onAddProvider,
4633
4964
  onSelectToken,
4965
+ tokenOptions,
4966
+ onPickToken,
4634
4967
  selectedSourceLabel,
4635
- selectedTokenSymbol
4968
+ selectedTokenSymbol,
4969
+ selectedChainName
4636
4970
  }) {
4637
4971
  const { tokens } = useBlinkConfig();
4638
4972
  const amount = initialAmount;
4639
4973
  const [accountPickerOpen, setAccountPickerOpen] = useState(false);
4974
+ const [tokenPickerOpen, setTokenPickerOpen] = useState(false);
4640
4975
  const pickerRef = useRef(null);
4976
+ const tokenPickerRef = useRef(null);
4977
+ const hasTokenDropdown = tokenOptions != null && tokenOptions.length > 0 && onPickToken != null;
4641
4978
  useEffect(() => {
4642
4979
  if (!accountPickerOpen) return;
4643
4980
  const handleClick = (e) => {
@@ -4648,47 +4985,129 @@ function DepositScreen({
4648
4985
  document.addEventListener("mousedown", handleClick);
4649
4986
  return () => document.removeEventListener("mousedown", handleClick);
4650
4987
  }, [accountPickerOpen]);
4988
+ useEffect(() => {
4989
+ if (!tokenPickerOpen) return;
4990
+ const handleMouseDown = (e) => {
4991
+ if (tokenPickerRef.current && !tokenPickerRef.current.contains(e.target)) {
4992
+ setTokenPickerOpen(false);
4993
+ }
4994
+ };
4995
+ document.addEventListener("mousedown", handleMouseDown);
4996
+ return () => document.removeEventListener("mousedown", handleMouseDown);
4997
+ }, [tokenPickerOpen]);
4998
+ const handleTokenBadgeClick = useCallback(() => {
4999
+ if (hasTokenDropdown) {
5000
+ setTokenPickerOpen((v) => !v);
5001
+ setAccountPickerOpen(false);
5002
+ } else {
5003
+ onSelectToken?.();
5004
+ }
5005
+ }, [hasTokenDropdown, onSelectToken]);
5006
+ const handlePickToken = useCallback((opt) => {
5007
+ onPickToken?.(opt.symbol, opt.chainName, opt.walletId);
5008
+ setTokenPickerOpen(false);
5009
+ }, [onPickToken]);
4651
5010
  const selectedAccount = accounts?.find((a) => a.id === selectedAccountId);
4652
5011
  const selectedProviderName = selectedAccount?.name ?? "Wallet";
4653
5012
  const selectedProviderLogo = KNOWN_LOGOS[selectedProviderName.toLowerCase()];
4654
5013
  const totalAccountBalance = selectedAccount ? selectedAccount.wallets.reduce((sum, w) => sum + w.balance.available.amount, 0) : availableBalance;
4655
5014
  const isLowBalance = availableBalance < minDepositFloor;
5015
+ const insufficientFunds = availableBalance < amount;
4656
5016
  const exceedsLimit = remainingLimit != null && amount > remainingLimit && !isLowBalance;
4657
- const canDeposit = amount >= minDepositFloor && !exceedsLimit && !isLowBalance && !processing;
5017
+ const canDeposit = amount >= minDepositFloor && !exceedsLimit && !isLowBalance && !insufficientFunds && !processing;
4658
5018
  return /* @__PURE__ */ jsxs(
4659
5019
  ScreenLayout,
4660
5020
  {
4661
5021
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
4662
- !accountPickerOpen && (exceedsLimit && onIncreaseLimit ? /* @__PURE__ */ jsx(PrimaryButton, { onClick: onIncreaseLimit, loading: increasingLimit, children: "Increase limit" }) : /* @__PURE__ */ jsx(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: "Confirm" })),
5022
+ !accountPickerOpen && !tokenPickerOpen && (exceedsLimit && onIncreaseLimit ? /* @__PURE__ */ jsx(PrimaryButton, { onClick: onIncreaseLimit, loading: increasingLimit, children: "Increase limit" }) : /* @__PURE__ */ jsx(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: insufficientFunds ? "Insufficient Funds" : "Confirm" })),
4663
5023
  /* @__PURE__ */ jsx(PoweredByFooter, {})
4664
5024
  ] }),
4665
5025
  children: [
4666
5026
  /* @__PURE__ */ jsx(ScreenHeader, { onBack, onLogout }),
4667
5027
  /* @__PURE__ */ jsxs("div", { ref: pickerRef, style: depositCardWrapStyle, children: [
4668
- /* @__PURE__ */ jsxs("div", { children: [
5028
+ /* @__PURE__ */ jsxs("div", { style: depositCardStyle(tokens), children: [
4669
5029
  /* @__PURE__ */ jsx("div", { style: depositLabelStyle(tokens.textMuted), children: "Depositing" }),
4670
- /* @__PURE__ */ jsxs("div", { style: amountRowStyle, children: [
4671
- /* @__PURE__ */ jsxs("div", { style: amountValueStyle(tokens.text), children: [
4672
- "$",
4673
- amount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
5030
+ /* @__PURE__ */ jsxs("div", { ref: tokenPickerRef, children: [
5031
+ /* @__PURE__ */ jsxs("div", { style: amountRowStyle, children: [
5032
+ /* @__PURE__ */ jsxs("div", { style: amountValueStyle(tokens.text), children: [
5033
+ "$",
5034
+ formatUsdTwoDecimals(amount)
5035
+ ] }),
5036
+ /* @__PURE__ */ jsxs(
5037
+ "button",
5038
+ {
5039
+ type: "button",
5040
+ "data-testid": "deposit-token-badge",
5041
+ onClick: handleTokenBadgeClick,
5042
+ style: tokenIconButtonStyle(hasTokenDropdown || !!onSelectToken),
5043
+ "aria-expanded": hasTokenDropdown ? tokenPickerOpen : void 0,
5044
+ "aria-haspopup": hasTokenDropdown ? "listbox" : void 0,
5045
+ children: [
5046
+ /* @__PURE__ */ jsx("div", { style: tokenIconWrapStyle2, children: selectedTokenSymbol && TOKEN_LOGOS[selectedTokenSymbol] ? /* @__PURE__ */ jsx("img", { src: TOKEN_LOGOS[selectedTokenSymbol], alt: selectedTokenSymbol, width: 36, height: 36, style: { borderRadius: "50%" } }) : /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 36 36", fill: "none", children: [
5047
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "18", fill: "#2DB84B" }),
5048
+ /* @__PURE__ */ jsx("text", { x: "18", y: "23", textAnchor: "middle", fontSize: "18", fill: "#fff", fontWeight: "700", children: "$" })
5049
+ ] }) }),
5050
+ /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", style: { opacity: 0.5 }, children: tokenPickerOpen ? /* @__PURE__ */ jsx("path", { d: "M18 15l-6-6-6 6", stroke: tokens.textMuted, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) : /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6", stroke: tokens.textMuted, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
5051
+ ]
5052
+ }
5053
+ )
4674
5054
  ] }),
4675
- /* @__PURE__ */ jsxs(
4676
- "button",
4677
- {
4678
- type: "button",
4679
- onClick: onSelectToken,
4680
- style: tokenIconButtonStyle(!!onSelectToken),
4681
- children: [
4682
- /* @__PURE__ */ jsx("div", { style: tokenIconWrapStyle2, children: selectedTokenSymbol && TOKEN_LOGOS[selectedTokenSymbol] ? /* @__PURE__ */ jsx("img", { src: TOKEN_LOGOS[selectedTokenSymbol], alt: selectedTokenSymbol, width: 36, height: 36, style: { borderRadius: "50%" } }) : /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 36 36", fill: "none", children: [
4683
- /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "18", fill: "#2DB84B" }),
4684
- /* @__PURE__ */ jsx("text", { x: "18", y: "23", textAnchor: "middle", fontSize: "18", fill: "#fff", fontWeight: "700", children: "$" })
4685
- ] }) }),
4686
- /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", style: { opacity: 0.5 }, children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6", stroke: tokens.textMuted, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
4687
- ]
4688
- }
4689
- )
5055
+ tokenPickerOpen && tokenOptions && tokenOptions.length > 0 && /* @__PURE__ */ jsxs("div", { style: tokenDropdownStyle(tokens), children: [
5056
+ /* @__PURE__ */ jsx("div", { style: tokenDropdownLabelStyle(tokens.textMuted), children: "Choose token" }),
5057
+ /* @__PURE__ */ jsx("div", { style: tokenDropdownInnerStyle(tokens), children: tokenOptions.map((opt, index) => {
5058
+ const selected = opt.symbol === selectedTokenSymbol && (!selectedChainName || opt.chainName === selectedChainName);
5059
+ const isLast = index === tokenOptions.length - 1;
5060
+ const authorized = !opt.status || opt.status === "AUTHORIZED";
5061
+ return /* @__PURE__ */ jsxs(
5062
+ "button",
5063
+ {
5064
+ type: "button",
5065
+ onClick: () => handlePickToken(opt),
5066
+ style: tokenDropdownRowStyle(tokens, selected, isLast),
5067
+ "aria-label": opt.balance != null ? `${opt.symbol} on ${opt.chainName}, $${formatUsdTwoDecimals(opt.balance)} balance${!authorized ? ", not authorized" : ""}` : `${opt.symbol} on ${opt.chainName}${!authorized ? ", not authorized" : ""}`,
5068
+ children: [
5069
+ /* @__PURE__ */ jsxs("div", { style: tokenDropdownRowLeftStyle, children: [
5070
+ /* @__PURE__ */ jsx("div", { style: tokenDropdownIconStyle(tokens, !!TOKEN_LOGOS[opt.symbol]), children: TOKEN_LOGOS[opt.symbol] ? /* @__PURE__ */ jsx("img", { src: TOKEN_LOGOS[opt.symbol], alt: opt.symbol, style: tokenDropdownLogoStyle }) : /* @__PURE__ */ jsx("span", { style: tokenDropdownFallbackStyle(tokens.textMuted), children: "$" }) }),
5071
+ /* @__PURE__ */ jsxs("div", { style: tokenDropdownInfoStyle, children: [
5072
+ /* @__PURE__ */ jsxs("div", { style: tokenDropdownNameRowStyle, children: [
5073
+ /* @__PURE__ */ jsx("span", { style: tokenDropdownSymbolStyle(tokens.text), children: opt.symbol }),
5074
+ /* @__PURE__ */ jsx("span", { style: tokenDropdownDotStyle(tokens.textMuted), children: "\xB7" }),
5075
+ /* @__PURE__ */ jsx("span", { style: tokenDropdownChainStyle(tokens.textMuted), children: opt.chainName })
5076
+ ] }),
5077
+ /* @__PURE__ */ jsxs("div", { style: tokenDropdownBalanceRowStyle, children: [
5078
+ opt.balance != null && /* @__PURE__ */ jsxs("span", { style: tokenDropdownBalanceStyle(tokens.textMuted), children: [
5079
+ "$",
5080
+ formatUsdTwoDecimals(opt.balance)
5081
+ ] }),
5082
+ !authorized && /* @__PURE__ */ jsx("span", { style: tokenDropdownNotAuthStyle(tokens.textMuted), children: "Not authorized" })
5083
+ ] })
5084
+ ] })
5085
+ ] }),
5086
+ selected ? /* @__PURE__ */ jsxs("svg", { width: "22", height: "22", viewBox: "0 0 22 22", fill: "none", children: [
5087
+ /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "11", fill: tokens.success }),
5088
+ /* @__PURE__ */ jsx("path", { d: "M7 11l3 3 5-5", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
5089
+ ] }) : /* @__PURE__ */ jsx("div", { style: tokenDropdownRadioStyle(tokens.border) })
5090
+ ]
5091
+ },
5092
+ `${opt.chainName}-${opt.symbol}`
5093
+ );
5094
+ }) })
5095
+ ] })
4690
5096
  ] }),
4691
- !accountPickerOpen && /* @__PURE__ */ jsxs(
5097
+ !accountPickerOpen && !tokenPickerOpen && (() => {
5098
+ if (quoteLoading) {
5099
+ return /* @__PURE__ */ jsx("div", { style: feeRowContainerStyle, "aria-live": "polite", children: /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle(tokens.textMuted), children: "Getting fee estimate\u2026" }) });
5100
+ }
5101
+ if (quoteFee) {
5102
+ const feeText = isPreciseMoneyNonPositive(quoteFee) ? formatNonPositiveFeeDisplay(quoteFee) : formatPreciseMoneyForDisplay(quoteFee);
5103
+ return /* @__PURE__ */ jsxs("div", { style: feeRowContainerStyle, "aria-live": "polite", children: [
5104
+ /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle(tokens.textMuted), children: "Fee estimate: " }),
5105
+ /* @__PURE__ */ jsx("span", { style: feeRowAmountStyle(tokens.textSecondary), children: feeText })
5106
+ ] });
5107
+ }
5108
+ return null;
5109
+ })(),
5110
+ !accountPickerOpen && !tokenPickerOpen && /* @__PURE__ */ jsxs(
4692
5111
  "button",
4693
5112
  {
4694
5113
  type: "button",
@@ -4698,7 +5117,7 @@ function DepositScreen({
4698
5117
  selectedProviderLogo ? /* @__PURE__ */ jsx("img", { src: selectedProviderLogo, alt: selectedProviderName, style: providerLogoStyle }) : /* @__PURE__ */ jsx("div", { style: providerFallbackStyle(tokens.textMuted), children: selectedProviderName.charAt(0) }),
4699
5118
  /* @__PURE__ */ jsxs("span", { style: walletBalanceStyle(tokens.text), children: [
4700
5119
  "$",
4701
- totalAccountBalance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
5120
+ formatUsdTwoDecimals(totalAccountBalance)
4702
5121
  ] }),
4703
5122
  /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", style: { opacity: 0.4 }, children: /* @__PURE__ */ jsx("path", { d: "M7 10l5-5 5 5M7 14l5 5 5-5", stroke: tokens.textMuted, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
4704
5123
  ]
@@ -4739,7 +5158,7 @@ function DepositScreen({
4739
5158
  /* @__PURE__ */ jsx("span", { style: accountAddressStyle(tokens.text), children: truncatedAddress ?? account.nickname ?? account.name }),
4740
5159
  /* @__PURE__ */ jsxs("span", { style: accountBalanceTextStyle(tokens.textMuted), children: [
4741
5160
  "$",
4742
- accountBalance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
5161
+ formatUsdTwoDecimals(accountBalance)
4743
5162
  ] })
4744
5163
  ] })
4745
5164
  ] }),
@@ -4775,21 +5194,21 @@ function DepositScreen({
4775
5194
  " ",
4776
5195
  /* @__PURE__ */ jsxs("strong", { style: { color: tokens.text }, children: [
4777
5196
  "$",
4778
- remainingLimit.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
5197
+ formatUsdTwoDecimals(remainingLimit)
4779
5198
  ] }),
4780
5199
  exceedsLimit && /* @__PURE__ */ jsxs("p", { style: limitExceededHintStyle(tokens.warning), children: [
4781
5200
  "Your deposit of $",
4782
- amount.toFixed(2),
5201
+ formatUsdTwoDecimals(amount),
4783
5202
  " exceeds your One-Tap limit of $",
4784
- remainingLimit?.toFixed(2) ?? "0.00",
5203
+ remainingLimit != null ? formatUsdTwoDecimals(remainingLimit) : "0.00",
4785
5204
  ". Increase your limit to continue."
4786
5205
  ] })
4787
5206
  ] }),
4788
5207
  !accountPickerOpen && isLowBalance && /* @__PURE__ */ jsxs(WarningBanner, { title: "Not enough funds", children: [
4789
5208
  "Your wallet balance is $",
4790
- availableBalance.toFixed(2),
5209
+ formatUsdTwoDecimals(availableBalance),
4791
5210
  " \u2014 you need at least $",
4792
- minDepositFloor.toFixed(2),
5211
+ formatUsdTwoDecimals(minDepositFloor),
4793
5212
  " to deposit via One-Tap."
4794
5213
  ] }),
4795
5214
  error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle6(tokens), children: error })
@@ -4801,6 +5220,11 @@ var depositCardWrapStyle = {
4801
5220
  position: "relative",
4802
5221
  marginBottom: 20
4803
5222
  };
5223
+ var depositCardStyle = (tokens) => ({
5224
+ border: `1px solid ${tokens.border}`,
5225
+ borderRadius: tokens.radiusLg,
5226
+ padding: "16px 20px"
5227
+ });
4804
5228
  var depositLabelStyle = (color) => ({
4805
5229
  fontSize: "0.75rem",
4806
5230
  fontWeight: 500,
@@ -4834,104 +5258,214 @@ var tokenIconWrapStyle2 = {
4834
5258
  width: 36,
4835
5259
  height: 36
4836
5260
  };
4837
- var walletBalanceRowStyle = {
4838
- display: "flex",
4839
- alignItems: "center",
4840
- justifyContent: "center",
4841
- gap: 8,
4842
- background: "transparent",
4843
- border: "none",
4844
- padding: 0,
4845
- width: "100%",
4846
- cursor: "pointer",
4847
- fontFamily: "inherit",
4848
- outline: "none"
4849
- };
4850
- var providerLogoStyle = {
4851
- width: 18,
4852
- height: 18,
4853
- borderRadius: "50%",
4854
- objectFit: "contain"
4855
- };
4856
- var providerFallbackStyle = (color) => ({
4857
- width: 18,
4858
- height: 18,
4859
- borderRadius: "50%",
4860
- display: "flex",
4861
- alignItems: "center",
4862
- justifyContent: "center",
4863
- fontSize: "0.65rem",
4864
- fontWeight: 700,
4865
- color,
4866
- flexShrink: 0
4867
- });
4868
- var walletBalanceStyle = (color) => ({
4869
- fontSize: "0.9rem",
4870
- fontWeight: 600,
4871
- color
4872
- });
4873
- var accountDropdownOuterStyle = (tokens) => ({
5261
+ var tokenDropdownStyle = (t) => ({
4874
5262
  marginTop: 4,
4875
- background: tokens.bgCard,
4876
- border: `1px solid ${tokens.border}`,
4877
- borderRadius: tokens.radiusLg,
4878
- boxShadow: tokens.shadowLg,
5263
+ marginBottom: 12,
5264
+ background: t.bgCard,
5265
+ border: `1px solid ${t.border}`,
5266
+ borderRadius: t.radiusLg,
5267
+ boxShadow: t.shadowLg,
4879
5268
  padding: "12px 14px 14px"
4880
5269
  });
4881
- var accountDropdownLabelStyle = (color) => ({
5270
+ var tokenDropdownLabelStyle = (color) => ({
4882
5271
  fontSize: "0.78rem",
4883
5272
  fontWeight: 500,
4884
5273
  color,
4885
5274
  marginBottom: 8
4886
5275
  });
4887
- var accountDropdownInnerStyle = (tokens) => ({
4888
- background: tokens.bgInput,
4889
- border: `1px solid ${tokens.border}`,
4890
- borderRadius: tokens.radiusLg,
5276
+ var tokenDropdownInnerStyle = (t) => ({
5277
+ background: t.bgInput,
5278
+ border: `1px solid ${t.border}`,
5279
+ borderRadius: t.radiusLg,
4891
5280
  overflow: "hidden"
4892
5281
  });
4893
- var accountRowStyle = (tokens, isSelected) => ({
5282
+ var tokenDropdownRowStyle = (t, isSelected, isLast) => ({
4894
5283
  display: "flex",
4895
5284
  alignItems: "center",
4896
5285
  justifyContent: "space-between",
4897
5286
  width: "100%",
4898
5287
  padding: "14px 16px",
4899
- background: isSelected ? `${tokens.accent}10` : "transparent",
5288
+ background: isSelected ? `${t.accent}18` : "transparent",
4900
5289
  border: "none",
4901
- borderBottom: `1px solid ${tokens.border}`,
5290
+ borderBottom: isLast ? "none" : `1px solid ${t.border}`,
4902
5291
  cursor: "pointer",
4903
5292
  fontFamily: "inherit",
4904
5293
  textAlign: "left",
4905
5294
  outline: "none"
4906
5295
  });
4907
- var accountRowLeftStyle = {
5296
+ var tokenDropdownRowLeftStyle = {
4908
5297
  display: "flex",
4909
5298
  alignItems: "center",
4910
5299
  gap: 12,
4911
5300
  minWidth: 0,
4912
5301
  flex: 1
4913
5302
  };
4914
- var accountLogoStyle = {
4915
- width: 28,
4916
- height: 28,
4917
- borderRadius: "50%",
4918
- objectFit: "contain",
4919
- flexShrink: 0
4920
- };
4921
- var accountFallbackIconStyle = (color) => ({
4922
- width: 28,
4923
- height: 28,
5303
+ var tokenDropdownIconStyle = (t, hasLogo) => ({
5304
+ width: 36,
5305
+ height: 36,
4924
5306
  borderRadius: "50%",
5307
+ border: hasLogo ? "none" : `1.5px solid ${t.border}`,
4925
5308
  display: "flex",
4926
5309
  alignItems: "center",
4927
5310
  justifyContent: "center",
4928
- fontSize: "0.75rem",
4929
- fontWeight: 700,
4930
- color,
4931
- flexShrink: 0
5311
+ flexShrink: 0,
5312
+ overflow: "hidden"
4932
5313
  });
4933
- var accountInfoStyle = {
4934
- display: "flex",
5314
+ var tokenDropdownLogoStyle = {
5315
+ width: 36,
5316
+ height: 36,
5317
+ borderRadius: "50%",
5318
+ objectFit: "cover"
5319
+ };
5320
+ var tokenDropdownFallbackStyle = (color) => ({
5321
+ fontSize: "1rem",
5322
+ fontWeight: 700,
5323
+ color
5324
+ });
5325
+ var tokenDropdownInfoStyle = {
5326
+ display: "flex",
5327
+ flexDirection: "column",
5328
+ gap: 2,
5329
+ minWidth: 0
5330
+ };
5331
+ var tokenDropdownNameRowStyle = {
5332
+ display: "flex",
5333
+ alignItems: "center",
5334
+ gap: 4
5335
+ };
5336
+ var tokenDropdownSymbolStyle = (color) => ({
5337
+ fontSize: "0.92rem",
5338
+ fontWeight: 600,
5339
+ color
5340
+ });
5341
+ var tokenDropdownDotStyle = (color) => ({
5342
+ fontSize: "0.8rem",
5343
+ color
5344
+ });
5345
+ var tokenDropdownChainStyle = (color) => ({
5346
+ fontSize: "0.84rem",
5347
+ fontWeight: 400,
5348
+ color
5349
+ });
5350
+ var tokenDropdownBalanceRowStyle = {
5351
+ display: "flex",
5352
+ alignItems: "center",
5353
+ gap: 8
5354
+ };
5355
+ var tokenDropdownBalanceStyle = (color) => ({
5356
+ fontSize: "0.78rem",
5357
+ color
5358
+ });
5359
+ var tokenDropdownNotAuthStyle = (color) => ({
5360
+ fontSize: "0.7rem",
5361
+ fontWeight: 500,
5362
+ color
5363
+ });
5364
+ var tokenDropdownRadioStyle = (borderColor) => ({
5365
+ width: 22,
5366
+ height: 22,
5367
+ borderRadius: "50%",
5368
+ border: `2px solid ${borderColor}`,
5369
+ flexShrink: 0
5370
+ });
5371
+ var walletBalanceRowStyle = {
5372
+ display: "flex",
5373
+ alignItems: "center",
5374
+ justifyContent: "center",
5375
+ gap: 8,
5376
+ background: "transparent",
5377
+ border: "none",
5378
+ padding: 0,
5379
+ width: "100%",
5380
+ cursor: "pointer",
5381
+ fontFamily: "inherit",
5382
+ outline: "none"
5383
+ };
5384
+ var providerLogoStyle = {
5385
+ width: 18,
5386
+ height: 18,
5387
+ borderRadius: "50%",
5388
+ objectFit: "contain"
5389
+ };
5390
+ var providerFallbackStyle = (color) => ({
5391
+ width: 18,
5392
+ height: 18,
5393
+ borderRadius: "50%",
5394
+ display: "flex",
5395
+ alignItems: "center",
5396
+ justifyContent: "center",
5397
+ fontSize: "0.65rem",
5398
+ fontWeight: 700,
5399
+ color,
5400
+ flexShrink: 0
5401
+ });
5402
+ var walletBalanceStyle = (color) => ({
5403
+ fontSize: "0.9rem",
5404
+ fontWeight: 600,
5405
+ color
5406
+ });
5407
+ var accountDropdownOuterStyle = (tokens) => ({
5408
+ marginTop: 4,
5409
+ background: tokens.bgCard,
5410
+ border: `1px solid ${tokens.border}`,
5411
+ borderRadius: tokens.radiusLg,
5412
+ boxShadow: tokens.shadowLg,
5413
+ padding: "12px 14px 14px"
5414
+ });
5415
+ var accountDropdownLabelStyle = (color) => ({
5416
+ fontSize: "0.78rem",
5417
+ fontWeight: 500,
5418
+ color,
5419
+ marginBottom: 8
5420
+ });
5421
+ var accountDropdownInnerStyle = (tokens) => ({
5422
+ background: tokens.bgInput,
5423
+ border: `1px solid ${tokens.border}`,
5424
+ borderRadius: tokens.radiusLg,
5425
+ overflow: "hidden"
5426
+ });
5427
+ var accountRowStyle = (tokens, isSelected) => ({
5428
+ display: "flex",
5429
+ alignItems: "center",
5430
+ justifyContent: "space-between",
5431
+ width: "100%",
5432
+ padding: "14px 16px",
5433
+ background: isSelected ? `${tokens.accent}10` : "transparent",
5434
+ border: "none",
5435
+ borderBottom: `1px solid ${tokens.border}`,
5436
+ cursor: "pointer",
5437
+ fontFamily: "inherit",
5438
+ textAlign: "left",
5439
+ outline: "none"
5440
+ });
5441
+ var accountRowLeftStyle = {
5442
+ display: "flex",
5443
+ alignItems: "center",
5444
+ gap: 12,
5445
+ minWidth: 0,
5446
+ flex: 1
5447
+ };
5448
+ var accountLogoStyle = {
5449
+ width: 28,
5450
+ height: 28,
5451
+ borderRadius: "50%",
5452
+ objectFit: "contain",
5453
+ flexShrink: 0
5454
+ };
5455
+ var accountFallbackIconStyle = (color) => ({
5456
+ width: 28,
5457
+ height: 28,
5458
+ borderRadius: "50%",
5459
+ display: "flex",
5460
+ alignItems: "center",
5461
+ justifyContent: "center",
5462
+ fontSize: "0.75rem",
5463
+ fontWeight: 700,
5464
+ color,
5465
+ flexShrink: 0
5466
+ });
5467
+ var accountInfoStyle = {
5468
+ display: "flex",
4935
5469
  flexDirection: "column",
4936
5470
  gap: 2,
4937
5471
  minWidth: 0
@@ -4995,9 +5529,20 @@ var limitExceededHintStyle = (color) => ({
4995
5529
  margin: "12px 0 2px",
4996
5530
  lineHeight: 1.5
4997
5531
  });
5532
+ var feeRowContainerStyle = {
5533
+ fontSize: "0.84rem",
5534
+ fontWeight: 500,
5535
+ marginTop: 6,
5536
+ marginBottom: 4
5537
+ };
5538
+ var feeRowLabelStyle = (color) => ({ color });
5539
+ var feeRowAmountStyle = (color) => ({
5540
+ color,
5541
+ fontVariantNumeric: "tabular-nums"
5542
+ });
4998
5543
  function SuccessScreen({
4999
5544
  amount,
5000
- currency,
5545
+ currency: _currency,
5001
5546
  succeeded,
5002
5547
  error,
5003
5548
  merchantName,
@@ -5010,22 +5555,30 @@ function SuccessScreen({
5010
5555
  onPreauthorize
5011
5556
  }) {
5012
5557
  const { tokens } = useBlinkConfig();
5558
+ const isGuestDepositSuccess = succeeded && onPreauthorize != null;
5013
5559
  return /* @__PURE__ */ jsxs(
5014
5560
  ScreenLayout,
5015
5561
  {
5016
5562
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
5017
- succeeded && onPreauthorize ? /* @__PURE__ */ jsxs(Fragment, { children: [
5018
- /* @__PURE__ */ jsx(PrimaryButton, { onClick: onPreauthorize, children: "Preauthorize future transfers" }),
5019
- /* @__PURE__ */ jsx("button", { type: "button", onClick: onDone, style: skipButtonStyle(tokens.textMuted), children: "Skip this time" })
5563
+ isGuestDepositSuccess ? /* @__PURE__ */ jsxs(Fragment, { children: [
5564
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onPreauthorize, children: "Set up one tap" }),
5565
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: onDone, style: skipButtonStyle(tokens.textMuted), children: "Return to app" })
5020
5566
  ] }) : /* @__PURE__ */ jsx(PrimaryButton, { onClick: onDone, children: succeeded ? "Done" : "Try again" }),
5021
5567
  onManageAccount && /* @__PURE__ */ jsx("button", { type: "button", onClick: onManageAccount, style: manageStyle(tokens.textMuted), children: "Manage Blink account \u2192" }),
5022
5568
  /* @__PURE__ */ jsx(PoweredByFooter, {})
5023
5569
  ] }),
5024
5570
  children: [
5025
5571
  /* @__PURE__ */ jsx(ScreenHeader, { onLogout }),
5026
- /* @__PURE__ */ jsxs("div", { style: contentStyle6, children: [
5027
- succeeded ? /* @__PURE__ */ jsxs(Fragment, { children: [
5028
- /* @__PURE__ */ jsx(IconCircle, { variant: "success", size: 64, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z", fill: tokens.success }) }) }),
5572
+ /* @__PURE__ */ jsxs("div", { style: screenContentStyle, children: [
5573
+ isGuestDepositSuccess ? /* @__PURE__ */ jsxs("div", { style: contentStyleCompact, children: [
5574
+ /* @__PURE__ */ jsxs("h2", { style: headingStyle7(tokens.text), children: [
5575
+ "$",
5576
+ amount.toFixed(2),
5577
+ " deposited"
5578
+ ] }),
5579
+ /* @__PURE__ */ jsx("p", { style: { ...subtitleStyle7(tokens.text), fontWeight: 600, margin: "0 0 8px" }, children: "Next time, do it in one tap" }),
5580
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle7(tokens.textSecondary), children: "Set up one tap for this wallet and skip the extra steps." })
5581
+ ] }) : succeeded ? /* @__PURE__ */ jsxs("div", { style: contentStyleCompact, children: [
5029
5582
  /* @__PURE__ */ jsxs("h2", { style: headingStyle7(tokens.text), children: [
5030
5583
  "$",
5031
5584
  amount.toFixed(2),
@@ -5037,10 +5590,10 @@ function SuccessScreen({
5037
5590
  ] })
5038
5591
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5039
5592
  /* @__PURE__ */ jsx(IconCircle, { variant: "error", size: 64, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z", fill: tokens.error }) }) }),
5040
- /* @__PURE__ */ jsx("h2", { style: headingStyle7(tokens.text), children: "Transfer failed" }),
5041
- error && /* @__PURE__ */ jsx("p", { style: subtitleStyle7(tokens.error), children: error })
5593
+ /* @__PURE__ */ jsx("h2", { style: failureHeadingStyle(tokens.text), children: "Transfer failed" }),
5594
+ error && /* @__PURE__ */ jsx("p", { style: failureSubtitleStyle(tokens.error), children: error })
5042
5595
  ] }),
5043
- /* @__PURE__ */ jsxs("div", { style: summaryCardStyle(tokens), children: [
5596
+ !isGuestDepositSuccess && /* @__PURE__ */ jsxs("div", { style: summaryCardStyle(tokens), children: [
5044
5597
  sourceName && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
5045
5598
  /* @__PURE__ */ jsx("span", { style: summaryLabelStyle(tokens.textMuted), children: "From" }),
5046
5599
  /* @__PURE__ */ jsx("span", { style: summaryValueStyle(tokens.text), children: sourceName })
@@ -5057,7 +5610,7 @@ function SuccessScreen({
5057
5610
  ] })
5058
5611
  ] })
5059
5612
  ] }),
5060
- succeeded && onIncreaseLimits && /* @__PURE__ */ jsxs("div", { style: upsellCardStyle(tokens), children: [
5613
+ succeeded && onIncreaseLimits && !isGuestDepositSuccess && /* @__PURE__ */ jsxs("div", { style: upsellCardStyle(tokens), children: [
5061
5614
  /* @__PURE__ */ jsxs("div", { style: upsellHeaderStyle, children: [
5062
5615
  /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { marginRight: 6 }, children: /* @__PURE__ */ jsx("path", { d: "M7 14l5-5 5 5", stroke: tokens.accent, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
5063
5616
  /* @__PURE__ */ jsx("strong", { children: "Want higher limits?" })
@@ -5070,21 +5623,42 @@ function SuccessScreen({
5070
5623
  }
5071
5624
  );
5072
5625
  }
5073
- var contentStyle6 = {
5626
+ var screenContentStyle = {
5074
5627
  flex: 1,
5075
5628
  display: "flex",
5076
5629
  flexDirection: "column",
5077
5630
  alignItems: "center",
5078
5631
  paddingTop: 16
5079
5632
  };
5633
+ var contentStyleCompact = {
5634
+ textAlign: "center",
5635
+ display: "flex",
5636
+ flexDirection: "column",
5637
+ alignItems: "center",
5638
+ width: "100%"
5639
+ };
5080
5640
  var headingStyle7 = (color) => ({
5641
+ fontSize: "1.45rem",
5642
+ fontWeight: 700,
5643
+ letterSpacing: "-0.02em",
5644
+ color,
5645
+ margin: "20px 0 8px"
5646
+ });
5647
+ var subtitleStyle7 = (color) => ({
5648
+ fontSize: "0.9rem",
5649
+ color,
5650
+ margin: "0 0 28px",
5651
+ lineHeight: 1.5,
5652
+ maxWidth: 280
5653
+ });
5654
+ var failureHeadingStyle = (color) => ({
5081
5655
  fontSize: "1.5rem",
5082
5656
  fontWeight: 700,
5083
5657
  letterSpacing: "-0.02em",
5084
5658
  color,
5085
5659
  margin: "20px 0 4px"
5086
5660
  });
5087
- var subtitleStyle7 = (color) => ({
5661
+ var failureSubtitleStyle = (color) => ({
5088
5662
  fontSize: "0.9rem",
5089
5663
  color,
5090
5664
  margin: "0 0 20px"
@@ -5600,7 +6174,7 @@ function TransferStatusScreen({
5600
6174
  const steps = buildSteps(phase);
5601
6175
  return /* @__PURE__ */ jsxs(ScreenLayout, { footer: /* @__PURE__ */ jsx(PoweredByFooter, {}), children: [
5602
6176
  /* @__PURE__ */ jsx(ScreenHeader, { onLogout }),
5603
- /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
6177
+ /* @__PURE__ */ jsxs("div", { style: contentStyle6, children: [
5604
6178
  /* @__PURE__ */ jsx(Spinner, { size: 64 }),
5605
6179
  /* @__PURE__ */ jsx("h2", { style: headingStyle9(tokens.text), children: "Depositing your money..." }),
5606
6180
  error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle7(tokens), children: error }),
@@ -5608,7 +6182,7 @@ function TransferStatusScreen({
5608
6182
  ] })
5609
6183
  ] });
5610
6184
  }
5611
- var contentStyle7 = {
6185
+ var contentStyle6 = {
5612
6186
  flex: 1,
5613
6187
  display: "flex",
5614
6188
  flexDirection: "column",
@@ -5678,7 +6252,7 @@ function OpenWalletScreen({
5678
6252
  ] }),
5679
6253
  children: [
5680
6254
  /* @__PURE__ */ jsx(ScreenHeader, { onLogout }),
5681
- /* @__PURE__ */ jsxs("div", { style: contentStyle8, children: [
6255
+ /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
5682
6256
  /* @__PURE__ */ jsx("div", { style: logoCircleStyle(tokens.bgInput), children: logoSrc ? /* @__PURE__ */ jsx("img", { src: logoSrc, alt: displayName, style: logoStyle2 }) : /* @__PURE__ */ jsx(Spinner, { size: 32 }) }),
5683
6257
  /* @__PURE__ */ jsxs("h2", { style: headingStyle10(tokens.text), children: [
5684
6258
  "Setting up ",
@@ -5711,7 +6285,7 @@ function OpenWalletScreen({
5711
6285
  ] }),
5712
6286
  children: [
5713
6287
  /* @__PURE__ */ jsx(ScreenHeader, { onBack, onLogout }),
5714
- /* @__PURE__ */ jsxs("div", { style: contentStyle8, children: [
6288
+ /* @__PURE__ */ jsxs("div", { style: contentStyle7, children: [
5715
6289
  /* @__PURE__ */ jsx("div", { style: logoCircleStyle(tokens.bgInput), children: logoSrc ? /* @__PURE__ */ jsx("img", { src: logoSrc, alt: displayName, style: logoStyle2 }) : /* @__PURE__ */ jsx(Spinner, { size: 32 }) }),
5716
6290
  /* @__PURE__ */ jsx("h2", { style: headingStyle10(tokens.text), children: loading ? "Connecting..." : `Open ${displayName}` }),
5717
6291
  /* @__PURE__ */ jsx("p", { style: subtitleStyle10(tokens.textSecondary), children: loading ? "Creating transfer and preparing your wallet link..." : `Continue in ${displayName} to authorize this connection.` }),
@@ -5724,7 +6298,7 @@ function OpenWalletScreen({
5724
6298
  }
5725
6299
  );
5726
6300
  }
5727
- var contentStyle8 = {
6301
+ var contentStyle7 = {
5728
6302
  flex: 1,
5729
6303
  display: "flex",
5730
6304
  flexDirection: "column",
@@ -5810,7 +6384,7 @@ function ConfirmSignScreen({
5810
6384
  ] }),
5811
6385
  children: [
5812
6386
  /* @__PURE__ */ jsx(ScreenHeader, { onLogout }),
5813
- /* @__PURE__ */ jsxs("div", { style: contentStyle9, children: [
6387
+ /* @__PURE__ */ jsxs("div", { style: contentStyle8, children: [
5814
6388
  logoSrc ? /* @__PURE__ */ jsx("img", { src: logoSrc, alt: displayName, style: logoStyle3 }) : /* @__PURE__ */ jsx(Spinner, { size: 48 }),
5815
6389
  /* @__PURE__ */ jsx("h2", { style: headingStyle11(tokens.text), children: "Wallet authorized" }),
5816
6390
  /* @__PURE__ */ jsxs("p", { style: subtitleStyle11(tokens.textSecondary), children: [
@@ -5826,7 +6400,7 @@ function ConfirmSignScreen({
5826
6400
  }
5827
6401
  );
5828
6402
  }
5829
- var contentStyle9 = {
6403
+ var contentStyle8 = {
5830
6404
  flex: 1,
5831
6405
  display: "flex",
5832
6406
  flexDirection: "column",
@@ -6121,29 +6695,6 @@ var selectCircleSelectedStyle = (color) => ({
6121
6695
  function entryKey(entry) {
6122
6696
  return `${entry.sourceChainId}-${entry.tokenAddress.toLowerCase()}`;
6123
6697
  }
6124
- function isPreciseMoneyNonPositive(fee) {
6125
- const raw = fee.value.trim();
6126
- if (!/^-?\d+(\.\d*)?$/.test(raw)) return false;
6127
- const n = Number(raw);
6128
- return Number.isFinite(n) && n <= 0;
6129
- }
6130
- function formatNonPositiveFeeDisplay(fee) {
6131
- if (fee.currency === "USD") return "Under $0.01";
6132
- return `Less than 0.01 ${fee.currency}`;
6133
- }
6134
- function formatPreciseMoneyForDisplay(fee) {
6135
- const raw = fee.value.trim();
6136
- if (fee.currency === "USD") {
6137
- if (!/^\d+(\.\d*)?$/.test(raw)) {
6138
- return `$${raw}`;
6139
- }
6140
- const [whole, frac = ""] = raw.split(".");
6141
- const dec = `${frac}00`.slice(0, 2);
6142
- const intFmt = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
6143
- return `$${intFmt}.${dec}`;
6144
- }
6145
- return `${raw} ${fee.currency}`;
6146
- }
6147
6698
  function GuestTokenPickerScreen({
6148
6699
  entries,
6149
6700
  loading,
@@ -6183,13 +6734,13 @@ function GuestTokenPickerScreen({
6183
6734
  const canConfirm = Boolean(quoteFee && pendingEntry && !quoteLoading);
6184
6735
  const feeLine = (() => {
6185
6736
  if (quoteLoading && pendingEntry) {
6186
- return /* @__PURE__ */ jsx("div", { style: feeRowContainerStyle, "aria-live": "polite", children: /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle(t.textMuted), children: "Getting fee estimate\u2026" }) });
6737
+ return /* @__PURE__ */ jsx("div", { style: feeRowContainerStyle2, "aria-live": "polite", children: /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle2(t.textMuted), children: "Getting fee estimate\u2026" }) });
6187
6738
  }
6188
6739
  if (quoteFee) {
6189
6740
  const feeText = isPreciseMoneyNonPositive(quoteFee) ? formatNonPositiveFeeDisplay(quoteFee) : formatPreciseMoneyForDisplay(quoteFee);
6190
- return /* @__PURE__ */ jsxs("div", { style: feeRowContainerStyle, "aria-live": "polite", children: [
6191
- /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle(t.textMuted), children: "Fee estimate: " }),
6192
- /* @__PURE__ */ jsx("span", { style: feeRowAmountStyle(t.textSecondary), children: feeText })
6741
+ return /* @__PURE__ */ jsxs("div", { style: feeRowContainerStyle2, "aria-live": "polite", children: [
6742
+ /* @__PURE__ */ jsx("span", { style: feeRowLabelStyle2(t.textMuted), children: "Fee estimate: " }),
6743
+ /* @__PURE__ */ jsx("span", { style: feeRowAmountStyle2(t.textSecondary), children: feeText })
6193
6744
  ] });
6194
6745
  }
6195
6746
  return null;
@@ -6211,7 +6762,7 @@ function GuestTokenPickerScreen({
6211
6762
  depositAmount != null && /* @__PURE__ */ jsxs("div", { style: depositAmountStyle2(t.text), children: [
6212
6763
  "$",
6213
6764
  depositAmount.toLocaleString("en-US", {
6214
- minimumFractionDigits: 0,
6765
+ minimumFractionDigits: 2,
6215
6766
  maximumFractionDigits: 2
6216
6767
  })
6217
6768
  ] }),
@@ -6293,7 +6844,7 @@ function GuestTokenPickerScreen({
6293
6844
  ] }),
6294
6845
  tokenListOpen && entries.length > 0 && /* @__PURE__ */ jsxs("div", { style: tokenDropdownOuterStyle(t), children: [
6295
6846
  /* @__PURE__ */ jsx("div", { style: accountDropdownLabelStyle2(t.textMuted), children: "Choose token" }),
6296
- /* @__PURE__ */ jsx("div", { style: tokenDropdownInnerStyle(t), children: entries.map((entry, index) => {
6847
+ /* @__PURE__ */ jsx("div", { style: tokenDropdownInnerStyle2(t), children: entries.map((entry, index) => {
6297
6848
  const selected = pendingKey === entryKey(entry);
6298
6849
  const isLast = index === entries.length - 1;
6299
6850
  return /* @__PURE__ */ jsxs(
@@ -6394,13 +6945,13 @@ var depositAmountStyle2 = (color) => ({
6394
6945
  color,
6395
6946
  lineHeight: 1.05
6396
6947
  });
6397
- var feeRowContainerStyle = {
6948
+ var feeRowContainerStyle2 = {
6398
6949
  fontSize: "0.84rem",
6399
6950
  fontWeight: 500,
6400
6951
  marginTop: 6
6401
6952
  };
6402
- var feeRowLabelStyle = (color) => ({ color });
6403
- var feeRowAmountStyle = (color) => ({
6953
+ var feeRowLabelStyle2 = (color) => ({ color });
6954
+ var feeRowAmountStyle2 = (color) => ({
6404
6955
  color,
6405
6956
  fontVariantNumeric: "tabular-nums"
6406
6957
  });
@@ -6446,7 +6997,7 @@ var accountDropdownLabelStyle2 = (color) => ({
6446
6997
  color,
6447
6998
  marginBottom: 8
6448
6999
  });
6449
- var tokenDropdownInnerStyle = (tokens) => ({
7000
+ var tokenDropdownInnerStyle2 = (tokens) => ({
6450
7001
  background: tokens.bgInput,
6451
7002
  border: `1px solid ${tokens.border}`,
6452
7003
  borderRadius: tokens.radiusLg,
@@ -6558,7 +7109,7 @@ function GuestPreauthSetupCompleteScreen({
6558
7109
  ] }),
6559
7110
  children: [
6560
7111
  /* @__PURE__ */ jsx(ScreenHeader, { onLogout }),
6561
- /* @__PURE__ */ jsxs("div", { style: contentStyle10, children: [
7112
+ /* @__PURE__ */ jsxs("div", { style: contentStyle9, children: [
6562
7113
  /* @__PURE__ */ jsx(IconCircle, { variant: "success", size: 64, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
6563
7114
  "path",
6564
7115
  {
@@ -6567,13 +7118,13 @@ function GuestPreauthSetupCompleteScreen({
6567
7118
  }
6568
7119
  ) }) }),
6569
7120
  /* @__PURE__ */ jsx("h2", { style: headingStyle12(tokens.text), children: "Setup complete" }),
6570
- /* @__PURE__ */ jsx("p", { style: subtitleStyle12(tokens.textSecondary), children: "Your account is linked and ready. You can close this window or make another deposit." })
7121
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle12(tokens.textSecondary), children: "Your account is linked and ready. You can close this window." })
6571
7122
  ] })
6572
7123
  ]
6573
7124
  }
6574
7125
  );
6575
7126
  }
6576
- var contentStyle10 = {
7127
+ var contentStyle9 = {
6577
7128
  display: "flex",
6578
7129
  flexDirection: "column",
6579
7130
  alignItems: "center",
@@ -6602,14 +7153,14 @@ function GuestPreauthLinkingScreen({ onLogout }) {
6602
7153
  const { tokens } = useBlinkConfig();
6603
7154
  return /* @__PURE__ */ jsxs(ScreenLayout, { children: [
6604
7155
  /* @__PURE__ */ jsx(ScreenHeader, { onLogout }),
6605
- /* @__PURE__ */ jsxs("div", { style: contentStyle11, children: [
7156
+ /* @__PURE__ */ jsxs("div", { style: contentStyle10, children: [
6606
7157
  /* @__PURE__ */ jsx(Spinner, { size: 48 }),
6607
7158
  /* @__PURE__ */ jsx("h2", { style: headingStyle13(tokens.text), children: "Setting up your account..." }),
6608
7159
  /* @__PURE__ */ jsx("p", { style: subtitleStyle13(tokens.textSecondary), children: "Linking your wallet to your Blink account. This usually takes a few seconds." })
6609
7160
  ] })
6610
7161
  ] });
6611
7162
  }
6612
- var contentStyle11 = {
7163
+ var contentStyle10 = {
6613
7164
  flex: 1,
6614
7165
  display: "flex",
6615
7166
  flexDirection: "column",
@@ -6786,13 +7337,15 @@ function StepRendererContent({
6786
7337
  return /* @__PURE__ */ jsx(
6787
7338
  PasskeyScreen,
6788
7339
  {
6789
- onCreatePasskey: handlers.onRegisterPasskey,
7340
+ onCreatePasskey: handlers.onVerifyPasskey,
6790
7341
  onBack: handlers.onLogout,
6791
7342
  onLogout: handlers.onLogout,
6792
- creating: state.verifyingPasskeyPopup,
7343
+ creating: state.registeringPasskey,
6793
7344
  error: state.error,
6794
- popupFallback: true,
6795
- onCreatePasskeyViaPopup: handlers.onVerifyPasskeyViaPopup
7345
+ onCreateNewPasskey: handlers.onCreateNewPasskey,
7346
+ onCreateNewPasskeyViaPopup: handlers.onCreateNewPasskeyViaPopup,
7347
+ createNewPopupFallback: state.passkeyPopupNeeded,
7348
+ creatingNewPasskey: state.registeringPasskey
6796
7349
  }
6797
7350
  );
6798
7351
  case "wallet-picker": {
@@ -6849,15 +7402,11 @@ function StepRendererContent({
6849
7402
  0
6850
7403
  );
6851
7404
  const effectiveTokenCount = tokenCount > 0 ? tokenCount : selectSourceTokenCount;
6852
- const effectiveSourceLabel = selectedSourceLabel ?? (selectSourceChainName && selectSourceTokenSymbol ? `${selectSourceTokenSymbol} on ${selectSourceChainName}` : void 0);
6853
- const setupTokenOptions = selectedAccount ? selectedAccount.wallets.flatMap(
6854
- (w) => w.sources.filter((s) => s.balance.total.amount > 0).map((s) => ({
6855
- symbol: s.token.symbol,
6856
- chainName: w.chain.name,
6857
- balance: s.balance.available.amount,
6858
- walletId: w.id
6859
- }))
6860
- ) : selectSourceChoices.flatMap(
7405
+ const setupFromPendingSelectSource = pendingSelectSource != null;
7406
+ const setupSelectedTokenSymbol = setupFromPendingSelectSource ? selectSourceTokenSymbol || selectSourceRecommended?.tokenSymbol || "" : selectedSource?.token.symbol ?? selectSourceTokenSymbol;
7407
+ const setupSelectedChainName = setupFromPendingSelectSource ? selectSourceChainName || selectSourceRecommended?.chainName || "" : selectedWallet?.chain.name ?? selectSourceChainName;
7408
+ const effectiveSourceLabel = setupFromPendingSelectSource ? setupSelectedTokenSymbol && setupSelectedChainName ? `${setupSelectedTokenSymbol} on ${setupSelectedChainName}` : void 0 : selectedSourceLabel ?? (selectSourceChainName && selectSourceTokenSymbol ? `${selectSourceTokenSymbol} on ${selectSourceChainName}` : void 0);
7409
+ const setupTokenOptions = selectedAccount ? tokenOptionsForLinkedAccount(selectedAccount, state.chains) : selectSourceChoices.flatMap(
6861
7410
  (chain) => chain.tokens.map((t) => ({
6862
7411
  symbol: t.tokenSymbol,
6863
7412
  chainName: chain.chainName,
@@ -6865,9 +7414,8 @@ function StepRendererContent({
6865
7414
  }))
6866
7415
  );
6867
7416
  const handleSetupSelectToken = (symbol, chainName, walletId) => {
6868
- if (walletId) {
6869
- handlers.onSelectAuthorizedToken(walletId, symbol);
6870
- } else {
7417
+ handleInlineTokenSelection(handlers, state.chains, selectedAccount, symbol, chainName, walletId);
7418
+ if (pendingSelectSource) {
6871
7419
  handlers.onSelectSourceChainChange(chainName);
6872
7420
  handlers.onSetSelectSourceTokenSymbol(symbol);
6873
7421
  }
@@ -6875,17 +7423,18 @@ function StepRendererContent({
6875
7423
  return /* @__PURE__ */ jsx(
6876
7424
  SetupScreen,
6877
7425
  {
6878
- availableBalance: selectedSource ? selectedSource.balance.available.amount : selectSourceAvailableBalance > 0 ? selectSourceAvailableBalance : selectedAccount ? selectedAccount.wallets.reduce((sum, w) => sum + w.balance.available.amount, 0) : maxSourceBalance,
7426
+ availableBalance: selectedSource ? selectedSource.balance.available.amount : setupFromPendingSelectSource ? selectSourceAvailableBalance : selectSourceAvailableBalance > 0 ? selectSourceAvailableBalance : selectedAccount ? selectedAccount.wallets.reduce((sum, w) => sum + w.balance.available.amount, 0) : maxSourceBalance,
6879
7427
  tokenCount: effectiveTokenCount,
6880
7428
  sourceName,
6881
7429
  onSetupOneTap: handlers.onSetupOneTap,
6882
- onBack: () => handlers.onSetPhase({ step: "deposit" }),
7430
+ onBack: handlers.onBackFromSubflow,
6883
7431
  onLogout: handlers.onLogout,
6884
7432
  onAdvanced: handlers.onSelectToken,
6885
7433
  selectedSourceLabel: effectiveSourceLabel,
6886
7434
  loading: savingOneTapLimit,
6887
7435
  error: state.error,
6888
- selectedTokenSymbol: selectedSource?.token.symbol ?? selectSourceTokenSymbol,
7436
+ selectedTokenSymbol: setupSelectedTokenSymbol,
7437
+ selectedChainName: setupSelectedChainName,
6889
7438
  tokenOptions: setupTokenOptions,
6890
7439
  onSelectToken: handleSetupSelectToken
6891
7440
  }
@@ -6907,6 +7456,7 @@ function StepRendererContent({
6907
7456
  case "deposit": {
6908
7457
  const parsedAmt = depositAmount != null ? depositAmount : 5;
6909
7458
  const minDepositFloor = depositAmount != null ? depositAmount : DEFAULT_MIN_DEPOSIT_USD;
7459
+ const depositTokenOptions = tokenOptionsForLinkedAccount(selectedAccount, state.chains);
6910
7460
  return /* @__PURE__ */ jsx(
6911
7461
  DepositScreen,
6912
7462
  {
@@ -6915,6 +7465,8 @@ function StepRendererContent({
6915
7465
  remainingLimit: selectedSource != null ? selectedSource.remainingAllowance ?? null : selectedAccount?.remainingAllowance ?? null,
6916
7466
  tokenCount,
6917
7467
  initialAmount: parsedAmt,
7468
+ quoteFee: forms.depositQuoteFee,
7469
+ quoteLoading: forms.depositQuoteLoading,
6918
7470
  processing: state.creatingTransfer,
6919
7471
  error: state.error,
6920
7472
  onDeposit: handlers.onPay,
@@ -6929,8 +7481,13 @@ function StepRendererContent({
6929
7481
  onAuthorizeAccount: handlers.onContinueConnection,
6930
7482
  onAddProvider: () => handlers.onSetPhase({ step: "wallet-picker", reason: "switch" }),
6931
7483
  onSelectToken: handlers.onSelectToken,
7484
+ tokenOptions: depositTokenOptions,
7485
+ onPickToken: (symbol, chainName, walletId) => {
7486
+ handleInlineTokenSelection(handlers, state.chains, selectedAccount, symbol, chainName, walletId);
7487
+ },
6932
7488
  selectedSourceLabel,
6933
7489
  selectedTokenSymbol: selectedSource?.token.symbol,
7490
+ selectedChainName: selectedWallet?.chain.name,
6934
7491
  minDepositFloor
6935
7492
  }
6936
7493
  );
@@ -6971,7 +7528,7 @@ function StepRendererContent({
6971
7528
  chains: state.chains,
6972
7529
  onSelectAuthorized: handlers.onSelectAuthorizedToken,
6973
7530
  onAuthorizeToken: handlers.onAuthorizeToken,
6974
- onBack: () => handlers.onSetPhase({ step: "deposit" }),
7531
+ onBack: handlers.onBackFromSubflow,
6975
7532
  onLogout: handlers.onLogout,
6976
7533
  depositAmount: depositAmount ?? void 0,
6977
7534
  selectedTokenSymbol: selectedSource?.token.symbol,
@@ -7050,7 +7607,7 @@ function StepRendererContent({
7050
7607
  })() : void 0,
7051
7608
  onDone: onDismiss ?? handlers.onNewPayment,
7052
7609
  onLogout: authenticated ? handlers.onLogout : void 0,
7053
- onPreauthorize: state.isGuestFlow ? handlers.onPreauthorize : void 0
7610
+ onPreauthorize: state.isGuestFlow && isDesktop ? handlers.onPreauthorize : void 0
7054
7611
  }
7055
7612
  );
7056
7613
  }
@@ -7338,6 +7895,53 @@ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds)
7338
7895
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
7339
7896
  }
7340
7897
  }, [user, knownCredentialIds, activateExistingCredential, completePasskeyRegistration, dispatch]);
7898
+ const handleVerifyPasskey = useCallback(async () => {
7899
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
7900
+ dispatch({ type: "SET_ERROR", error: null });
7901
+ try {
7902
+ const matched = await findDevicePasskey(knownCredentialIds);
7903
+ if (matched) {
7904
+ await activateExistingCredential(matched);
7905
+ } else {
7906
+ dispatch({
7907
+ type: "SET_ERROR",
7908
+ error: "No matching passkey found on this device. Please try again."
7909
+ });
7910
+ }
7911
+ } catch (err) {
7912
+ captureException(err);
7913
+ dispatch({
7914
+ type: "SET_ERROR",
7915
+ error: err instanceof Error ? err.message : "Passkey verification failed."
7916
+ });
7917
+ } finally {
7918
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
7919
+ }
7920
+ }, [knownCredentialIds, activateExistingCredential, dispatch]);
7921
+ const handleCreateNewPasskey = useCallback(async () => {
7922
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
7923
+ dispatch({ type: "SET_ERROR", error: null });
7924
+ try {
7925
+ const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Blink User";
7926
+ const { credentialId, publicKey } = await createPasskeyCredential({
7927
+ userId: user?.id ?? "unknown",
7928
+ displayName: passkeyDisplayName
7929
+ });
7930
+ await completePasskeyRegistration(credentialId, publicKey);
7931
+ } catch (err) {
7932
+ if (err instanceof PasskeyIframeBlockedError) {
7933
+ dispatch({ type: "SET_PASSKEY_POPUP_NEEDED", needed: true });
7934
+ } else {
7935
+ captureException(err);
7936
+ dispatch({
7937
+ type: "SET_ERROR",
7938
+ error: err instanceof Error ? err.message : "Failed to register passkey"
7939
+ });
7940
+ }
7941
+ } finally {
7942
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
7943
+ }
7944
+ }, [user, completePasskeyRegistration, dispatch]);
7341
7945
  const handleCreatePasskeyViaPopup = useCallback(async () => {
7342
7946
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
7343
7947
  dispatch({ type: "SET_ERROR", error: null });
@@ -7384,6 +7988,35 @@ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds)
7384
7988
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
7385
7989
  }
7386
7990
  }, [user, knownCredentialIds, getAccessToken, apiBaseUrl, activateExistingCredential, dispatch]);
7991
+ const handleCreateNewPasskeyViaPopup = useCallback(async () => {
7992
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
7993
+ dispatch({ type: "SET_ERROR", error: null });
7994
+ try {
7995
+ const token = await getAccessToken();
7996
+ const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Blink User";
7997
+ const popupOptions = buildPasskeyPopupOptions({
7998
+ userId: user?.id ?? "unknown",
7999
+ displayName: passkeyDisplayName,
8000
+ authToken: token ?? void 0,
8001
+ apiBaseUrl
8002
+ });
8003
+ const { credentialId, publicKey } = await createPasskeyViaPopup(popupOptions);
8004
+ dispatch({ type: "PASSKEY_ACTIVATED", credentialId, publicKey });
8005
+ localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
8006
+ if (token) {
8007
+ reportPasskeyActivity(apiBaseUrl, token, credentialId).catch(() => {
8008
+ });
8009
+ }
8010
+ } catch (err) {
8011
+ captureException(err);
8012
+ dispatch({
8013
+ type: "SET_ERROR",
8014
+ error: err instanceof Error ? err.message : "Failed to register passkey"
8015
+ });
8016
+ } finally {
8017
+ dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
8018
+ }
8019
+ }, [user, getAccessToken, apiBaseUrl, dispatch]);
7387
8020
  const handleVerifyPasskeyViaPopup = useCallback(async () => {
7388
8021
  dispatch({ type: "SET_VERIFYING_PASSKEY", value: true });
7389
8022
  dispatch({ type: "SET_ERROR", error: null });
@@ -7426,7 +8059,10 @@ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds)
7426
8059
  }, [knownCredentialIds, getAccessToken, apiBaseUrl, dispatch]);
7427
8060
  return {
7428
8061
  handleRegisterPasskey,
8062
+ handleVerifyPasskey,
8063
+ handleCreateNewPasskey,
7429
8064
  handleCreatePasskeyViaPopup,
8065
+ handleCreateNewPasskeyViaPopup,
7430
8066
  handleVerifyPasskeyViaPopup,
7431
8067
  checkingPasskeyRef
7432
8068
  };
@@ -7449,6 +8085,9 @@ function useTransferHandlers(deps) {
7449
8085
  sourceTokenAddress,
7450
8086
  activeCredentialId,
7451
8087
  selectedAccountId,
8088
+ selectedWalletId,
8089
+ selectedTokenSymbol,
8090
+ quoteId,
7452
8091
  transfer,
7453
8092
  accounts
7454
8093
  } = deps;
@@ -7462,9 +8101,32 @@ function useTransferHandlers(deps) {
7462
8101
  fetchProviders(apiBaseUrl, token)
7463
8102
  ]);
7464
8103
  const parsedAmt = depositAmount != null ? depositAmount : 0;
7465
- const defaults = resolveDepositSelection(accts, parsedAmt, selectedAccountId);
7466
- dispatch({ type: "ACCOUNTS_RELOADED", accounts: accts, providers: prov, defaults });
7467
- }, [getAccessToken, activeCredentialId, selectedAccountId, apiBaseUrl, depositAmount, dispatch]);
8104
+ const { defaults, resetSelectedTokenSymbol } = resolveDepositSelectionAfterRefresh(
8105
+ accts,
8106
+ parsedAmt,
8107
+ {
8108
+ selectedAccountId,
8109
+ selectedWalletId,
8110
+ selectedTokenSymbol
8111
+ }
8112
+ );
8113
+ dispatch({
8114
+ type: "ACCOUNTS_RELOADED",
8115
+ accounts: accts,
8116
+ providers: prov,
8117
+ defaults,
8118
+ resetSelectedTokenSymbol
8119
+ });
8120
+ }, [
8121
+ getAccessToken,
8122
+ activeCredentialId,
8123
+ selectedAccountId,
8124
+ selectedWalletId,
8125
+ selectedTokenSymbol,
8126
+ apiBaseUrl,
8127
+ depositAmount,
8128
+ dispatch
8129
+ ]);
7468
8130
  const handlePay = useCallback(async (payAmount, sourceOverrides) => {
7469
8131
  const minUsd = effectiveMinTransferAmountUsd(depositAmount);
7470
8132
  if (isNaN(payAmount) || payAmount < minUsd) {
@@ -7508,7 +8170,8 @@ function useTransferHandlers(deps) {
7508
8170
  sourceId: effectiveSourceId,
7509
8171
  sourceTokenAddress,
7510
8172
  destination,
7511
- amount: payAmount
8173
+ amount: payAmount,
8174
+ ...quoteId ? { quoteId } : {}
7512
8175
  });
7513
8176
  dispatch({ type: "TRANSFER_CREATED", transfer: t });
7514
8177
  if (t.status === "COMPLETED") {
@@ -7540,6 +8203,7 @@ function useTransferHandlers(deps) {
7540
8203
  accounts,
7541
8204
  destination,
7542
8205
  apiBaseUrl,
8206
+ quoteId,
7543
8207
  getAccessToken,
7544
8208
  transferSigning,
7545
8209
  polling,
@@ -7590,20 +8254,20 @@ function useSourceSelectionHandlers(dispatch, authExecutor, options) {
7590
8254
  const selectSourceAvailableBalance = useMemo(() => {
7591
8255
  if (!pendingSelectSourceAction) return 0;
7592
8256
  const options2 = pendingSelectSourceAction.metadata?.options ?? [];
7593
- const recommended = selectSourceRecommended;
7594
- if (recommended) {
7595
- const match = options2.find(
7596
- (opt) => opt.chainName === recommended.chainName && opt.tokenSymbol === recommended.tokenSymbol
7597
- );
7598
- if (match) return Number(match.rawBalance) / Math.pow(10, match.decimals);
7599
- }
7600
- let max = 0;
7601
- for (const opt of options2) {
7602
- const bal = Number(opt.rawBalance) / Math.pow(10, opt.decimals);
7603
- if (bal > max) max = bal;
7604
- }
7605
- return max;
7606
- }, [pendingSelectSourceAction, selectSourceRecommended]);
8257
+ return resolveSelectSourceAvailableBalance(
8258
+ selectSourceChoices,
8259
+ options2,
8260
+ selectSourceChainName,
8261
+ selectSourceTokenSymbol,
8262
+ selectSourceRecommended
8263
+ );
8264
+ }, [
8265
+ pendingSelectSourceAction,
8266
+ selectSourceChoices,
8267
+ selectSourceChainName,
8268
+ selectSourceTokenSymbol,
8269
+ selectSourceRecommended
8270
+ ]);
7607
8271
  const handleSelectSourceChainChange = useCallback(
7608
8272
  (chainName) => {
7609
8273
  setSelectSourceChainName(chainName);
@@ -7654,7 +8318,7 @@ function useSourceSelectionHandlers(dispatch, authExecutor, options) {
7654
8318
  initializedSelectSourceActionRef
7655
8319
  };
7656
8320
  }
7657
- function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs, guestCheckout, onComplete) {
8321
+ function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs, guestCheckout, onComplete, lastResumedAt) {
7658
8322
  const {
7659
8323
  mobileSetupFlowRef,
7660
8324
  handlingMobileReturnRef,
@@ -7665,6 +8329,8 @@ function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransfe
7665
8329
  onCompleteRef.current = onComplete;
7666
8330
  const guestPollingActiveRef = useRef(false);
7667
8331
  const guestPollingCleanupRef = useRef(null);
8332
+ const mobileFlowRef = useRef(guestCheckout.mobileFlow);
8333
+ mobileFlowRef.current = guestCheckout.mobileFlow;
7668
8334
  const guestTransferIdRef = useRef(guestCheckout.guestTransferId);
7669
8335
  guestTransferIdRef.current = guestCheckout.guestTransferId;
7670
8336
  const guestSessionTokenRef = useRef(guestCheckout.guestSessionToken);
@@ -7720,27 +8386,15 @@ function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransfe
7720
8386
  startGuestPolling
7721
8387
  ]);
7722
8388
  useEffect(() => {
7723
- const tryStartPolling = () => {
7724
- if (guestPollingActiveRef.current) return;
7725
- const transferId = guestTransferIdRef.current;
7726
- const token = guestSessionTokenRef.current;
7727
- if (transferId && token) {
7728
- startGuestPolling(transferId, token);
7729
- }
7730
- };
7731
- const handleVisibility = () => {
7732
- if (document.visibilityState === "visible") tryStartPolling();
7733
- };
7734
- const handlePageShow = (e) => {
7735
- if (e.persisted) tryStartPolling();
7736
- };
7737
- document.addEventListener("visibilitychange", handleVisibility);
7738
- window.addEventListener("pageshow", handlePageShow);
7739
- return () => {
7740
- document.removeEventListener("visibilitychange", handleVisibility);
7741
- window.removeEventListener("pageshow", handlePageShow);
7742
- };
7743
- }, [startGuestPolling]);
8389
+ if (!lastResumedAt) return;
8390
+ if (guestPollingActiveRef.current) return;
8391
+ if (!mobileFlowRef.current) return;
8392
+ const transferId = guestTransferIdRef.current;
8393
+ const token = guestSessionTokenRef.current;
8394
+ if (transferId && token) {
8395
+ startGuestPolling(transferId, token);
8396
+ }
8397
+ }, [lastResumedAt, startGuestPolling]);
7744
8398
  const handleAuthorizedMobileReturn = useCallback(async (authorizedTransfer, isSetup) => {
7745
8399
  if (handlingMobileReturnRef.current) return;
7746
8400
  handlingMobileReturnRef.current = true;
@@ -7974,6 +8628,9 @@ function useProviderHandlers(deps) {
7974
8628
  await reloadAccounts();
7975
8629
  }
7976
8630
  } catch (err) {
8631
+ if (isAuthorizationSessionCancelled(err) || isUserDismissedAuthorizationError(err)) {
8632
+ return;
8633
+ }
7977
8634
  captureException(err);
7978
8635
  const msg = err instanceof Error ? err.message : "Failed to set up wallet";
7979
8636
  dispatch({ type: "PAY_ERROR", error: msg });
@@ -8040,7 +8697,12 @@ function useProviderHandlers(deps) {
8040
8697
  }
8041
8698
  const acct = accounts.find((a) => a.id === selectedAccountId);
8042
8699
  const matchedProvider = acct ? providers.find((p) => p.name === acct.name) : void 0;
8043
- if (matchedProvider) {
8700
+ const isMobile = !shouldUseWalletConnector({
8701
+ useWalletConnector: useWalletConnectorProp,
8702
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
8703
+ });
8704
+ if (matchedProvider && isMobile) {
8705
+ dispatch({ type: "SAVE_SELECTION" });
8044
8706
  dispatch({ type: "SELECT_PROVIDER", providerId: matchedProvider.id });
8045
8707
  }
8046
8708
  dispatch({ type: "SET_ERROR", error: null });
@@ -8060,10 +8722,6 @@ function useProviderHandlers(deps) {
8060
8722
  activeCredentialId,
8061
8723
  { tokenAddress: source?.address, chainId: evmChainId }
8062
8724
  );
8063
- const isMobile = !shouldUseWalletConnector({
8064
- useWalletConnector: useWalletConnectorProp,
8065
- userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
8066
- });
8067
8725
  if (isMobile) {
8068
8726
  handlingMobileReturnRef.current = false;
8069
8727
  mobileSetupFlowRef.current = true;
@@ -8080,12 +8738,20 @@ function useProviderHandlers(deps) {
8080
8738
  });
8081
8739
  dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: session.uri });
8082
8740
  triggerDeeplink(session.uri);
8741
+ dispatch({ type: "DISCARD_SAVED_SELECTION" });
8083
8742
  } else {
8084
8743
  await authExecutor.executeSessionById(session.id);
8085
8744
  await reloadAccounts();
8745
+ dispatch({ type: "DISCARD_SAVED_SELECTION" });
8086
8746
  }
8087
8747
  } catch (err) {
8748
+ if (isAuthorizationSessionCancelled(err) || isUserDismissedAuthorizationError(err)) {
8749
+ return;
8750
+ }
8088
8751
  captureException(err);
8752
+ if (isMobile) {
8753
+ dispatch({ type: "RESTORE_SELECTION" });
8754
+ }
8089
8755
  const msg = err instanceof Error ? err.message : "Failed to increase limit";
8090
8756
  dispatch({ type: "SET_ERROR", error: msg });
8091
8757
  onError?.(msg);
@@ -8130,7 +8796,12 @@ function useProviderHandlers(deps) {
8130
8796
  }
8131
8797
  const acct = accounts.find((a) => a.id === selectedAccountId);
8132
8798
  const matchedProvider = acct ? providers.find((p) => p.name === acct.name) : void 0;
8133
- if (matchedProvider) {
8799
+ const isMobile = !shouldUseWalletConnector({
8800
+ useWalletConnector: useWalletConnectorProp,
8801
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
8802
+ });
8803
+ if (matchedProvider && isMobile) {
8804
+ dispatch({ type: "SAVE_SELECTION" });
8134
8805
  dispatch({ type: "SELECT_PROVIDER", providerId: matchedProvider.id });
8135
8806
  }
8136
8807
  dispatch({ type: "SET_ERROR", error: null });
@@ -8145,10 +8816,6 @@ function useProviderHandlers(deps) {
8145
8816
  activeCredentialId,
8146
8817
  { tokenAddress, chainId }
8147
8818
  );
8148
- const isMobile = !shouldUseWalletConnector({
8149
- useWalletConnector: useWalletConnectorProp,
8150
- userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
8151
- });
8152
8819
  if (isMobile) {
8153
8820
  handlingMobileReturnRef.current = false;
8154
8821
  mobileSetupFlowRef.current = true;
@@ -8166,13 +8833,21 @@ function useProviderHandlers(deps) {
8166
8833
  });
8167
8834
  dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: session.uri });
8168
8835
  triggerDeeplink(session.uri);
8836
+ dispatch({ type: "DISCARD_SAVED_SELECTION" });
8169
8837
  } else {
8170
8838
  await authExecutor.executeSessionById(session.id);
8171
8839
  await reloadAccounts();
8172
8840
  dispatch({ type: "SELECT_TOKEN", walletId: _walletId, tokenSymbol });
8841
+ dispatch({ type: "DISCARD_SAVED_SELECTION" });
8173
8842
  }
8174
8843
  } catch (err) {
8844
+ if (isAuthorizationSessionCancelled(err) || isUserDismissedAuthorizationError(err)) {
8845
+ return;
8846
+ }
8175
8847
  captureException(err);
8848
+ if (isMobile) {
8849
+ dispatch({ type: "RESTORE_SELECTION" });
8850
+ }
8176
8851
  const msg = err instanceof Error ? err.message : "Failed to authorize token";
8177
8852
  dispatch({ type: "SET_ERROR", error: msg });
8178
8853
  onError?.(msg);
@@ -9005,28 +9680,6 @@ function usePasskeyCheckEffect(deps) {
9005
9680
  await restoreState(activeCredentialId, token);
9006
9681
  return;
9007
9682
  }
9008
- if (cancelled) return;
9009
- const credentialIds = allPasskeys.map((p) => p.credentialId);
9010
- let matched = null;
9011
- if (isSafari() && isInCrossOriginIframe()) {
9012
- matched = await findDevicePasskeyViaPopup({
9013
- credentialIds,
9014
- rpId: resolvePasskeyRpId(),
9015
- authToken: token ?? void 0,
9016
- apiBaseUrl
9017
- });
9018
- } else {
9019
- matched = await findDevicePasskey(credentialIds);
9020
- }
9021
- if (cancelled) return;
9022
- if (matched) {
9023
- const publicKey = allPasskeys.find((p) => p.credentialId === matched)?.publicKey;
9024
- dispatch({ type: "PASSKEY_ACTIVATED", credentialId: matched, publicKey });
9025
- window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
9026
- reportPasskeyActivity(apiBaseUrl, token, matched).catch(() => {
9027
- });
9028
- await restoreState(matched, token);
9029
- }
9030
9683
  } catch (err) {
9031
9684
  dispatch({
9032
9685
  type: "PASSKEY_CONFIG_LOADED",
@@ -9109,7 +9762,15 @@ function useDataLoadEffect(deps) {
9109
9762
  ]);
9110
9763
  if (cancelled) return;
9111
9764
  const parsedAmt = depositAmount != null ? depositAmount : 0;
9112
- const defaults = resolveDepositSelection(accts, parsedAmt, state.selectedAccountId);
9765
+ const { defaults, resetSelectedTokenSymbol } = resolveDepositSelectionAfterRefresh(
9766
+ accts,
9767
+ parsedAmt,
9768
+ {
9769
+ selectedAccountId: state.selectedAccountId,
9770
+ selectedWalletId: state.selectedWalletId,
9771
+ selectedTokenSymbol: state.selectedTokenSymbol
9772
+ }
9773
+ );
9113
9774
  const persisted = loadMobileFlowState();
9114
9775
  const clearMobile = persisted?.isSetup && accts.some((a) => a.wallets.some((w) => w.status === "ACTIVE"));
9115
9776
  dispatch({
@@ -9118,7 +9779,8 @@ function useDataLoadEffect(deps) {
9118
9779
  accounts: accts,
9119
9780
  chains: chn,
9120
9781
  defaults,
9121
- clearMobileState: clearMobile
9782
+ clearMobileState: clearMobile,
9783
+ resetSelectedTokenSymbol
9122
9784
  });
9123
9785
  if (clearMobile) clearMobileFlowState();
9124
9786
  } catch (err) {
@@ -9147,6 +9809,8 @@ function useDataLoadEffect(deps) {
9147
9809
  apiBaseUrl,
9148
9810
  state.activeCredentialId,
9149
9811
  state.selectedAccountId,
9812
+ state.selectedWalletId,
9813
+ state.selectedTokenSymbol,
9150
9814
  depositAmount
9151
9815
  ]);
9152
9816
  useEffect(() => {
@@ -9375,25 +10039,16 @@ function useMobilePollingEffect(deps) {
9375
10039
  const poll = isReauth ? pollReauthorization : pollWalletActive;
9376
10040
  poll();
9377
10041
  const intervalId = window.setInterval(poll, POLL_INTERVAL_MS);
9378
- const handleVisibility = () => {
9379
- if (document.visibilityState === "visible" && !cancelled) poll();
9380
- };
9381
- const handlePageShow = (e) => {
9382
- if (e.persisted && !cancelled) poll();
9383
- };
9384
- document.addEventListener("visibilitychange", handleVisibility);
9385
- window.addEventListener("pageshow", handlePageShow);
9386
10042
  return () => {
9387
10043
  cancelled = true;
9388
10044
  window.clearInterval(intervalId);
9389
- document.removeEventListener("visibilitychange", handleVisibility);
9390
- window.removeEventListener("pageshow", handlePageShow);
9391
10045
  };
9392
10046
  }, [
9393
10047
  state.mobileFlow,
9394
10048
  state.isGuestFlow,
9395
10049
  state.guestPreauthSessionId,
9396
10050
  state.activeCredentialId,
10051
+ state.lastResumedAt,
9397
10052
  apiBaseUrl,
9398
10053
  reloadAccounts,
9399
10054
  dispatch,
@@ -9410,28 +10065,13 @@ function useMobilePollingEffect(deps) {
9410
10065
  const transferIdToResume = pollingTransferIdRef.current ?? state.transfer?.id;
9411
10066
  if (!transferIdToResume) return;
9412
10067
  if (!polling.isPolling) polling.startPolling(transferIdToResume);
9413
- const handleVisibility = () => {
9414
- if (document.visibilityState === "visible" && !handlingMobileReturnRef.current) {
9415
- polling.startPolling(transferIdToResume);
9416
- }
9417
- };
9418
- const handlePageShow = (e) => {
9419
- if (e.persisted && !handlingMobileReturnRef.current) {
9420
- polling.startPolling(transferIdToResume);
9421
- }
9422
- };
9423
- document.addEventListener("visibilitychange", handleVisibility);
9424
- window.addEventListener("pageshow", handlePageShow);
9425
- return () => {
9426
- document.removeEventListener("visibilitychange", handleVisibility);
9427
- window.removeEventListener("pageshow", handlePageShow);
9428
- };
9429
10068
  }, [
9430
10069
  state.mobileFlow,
9431
10070
  state.transfer?.id,
9432
10071
  state.isGuestFlow,
9433
10072
  state.guestPreauthSessionId,
9434
10073
  state.guestPreauthAccountId,
10074
+ state.lastResumedAt,
9435
10075
  polling.isPolling,
9436
10076
  polling.startPolling,
9437
10077
  handlingMobileReturnRef,
@@ -9442,6 +10082,7 @@ function useGuestPreauthMobileRestoreEffect(deps) {
9442
10082
  const {
9443
10083
  dispatch,
9444
10084
  privyReady,
10085
+ lastResumedAt,
9445
10086
  mobileSetupFlowRef,
9446
10087
  setupAccountIdRef,
9447
10088
  startGuestAccountPolling
@@ -9452,68 +10093,43 @@ function useGuestPreauthMobileRestoreEffect(deps) {
9452
10093
  console.info("[blink-sdk] guestPreauthMobileRestore: skipping, privyReady=false");
9453
10094
  return;
9454
10095
  }
9455
- const tryStart = (trigger) => {
9456
- if (startedRef.current) {
9457
- console.info("[blink-sdk] guestPreauthMobileRestore.tryStart: already started", { trigger });
9458
- return;
9459
- }
9460
- const persisted = loadMobileFlowState();
9461
- console.info("[blink-sdk] guestPreauthMobileRestore.tryStart", {
9462
- trigger,
9463
- hasPersistedState: !!persisted,
9464
- isGuestPreauth: persisted?.isGuestPreauth ?? false,
9465
- hasGuestSessionToken: !!persisted?.guestSessionToken,
9466
- hasSessionId: !!persisted?.sessionId,
9467
- accountId: persisted?.accountId ?? null
9468
- });
9469
- if (!persisted?.isGuestPreauth || !persisted.guestSessionToken || !persisted.sessionId) {
9470
- return;
9471
- }
9472
- startedRef.current = true;
9473
- mobileSetupFlowRef.current = true;
9474
- if (persisted.accountId) {
9475
- setupAccountIdRef.current = persisted.accountId;
9476
- }
9477
- if (persisted.accountId) {
9478
- dispatch({
9479
- type: "GUEST_PREAUTH_DETECTED",
9480
- accountId: persisted.accountId,
9481
- sessionId: persisted.sessionId
9482
- });
9483
- }
10096
+ if (startedRef.current) {
10097
+ console.info("[blink-sdk] guestPreauthMobileRestore: already started");
10098
+ return;
10099
+ }
10100
+ const persisted = loadMobileFlowState();
10101
+ console.info("[blink-sdk] guestPreauthMobileRestore.tryStart", {
10102
+ trigger: lastResumedAt ? "page-resume" : "initial",
10103
+ hasPersistedState: !!persisted,
10104
+ isGuestPreauth: persisted?.isGuestPreauth ?? false,
10105
+ hasGuestSessionToken: !!persisted?.guestSessionToken,
10106
+ hasSessionId: !!persisted?.sessionId,
10107
+ accountId: persisted?.accountId ?? null
10108
+ });
10109
+ if (!persisted?.isGuestPreauth || !persisted.guestSessionToken || !persisted.sessionId) {
10110
+ return;
10111
+ }
10112
+ startedRef.current = true;
10113
+ mobileSetupFlowRef.current = true;
10114
+ if (persisted.accountId) {
10115
+ setupAccountIdRef.current = persisted.accountId;
10116
+ }
10117
+ if (persisted.accountId) {
9484
10118
  dispatch({
9485
- type: "MOBILE_DEEPLINK_READY",
9486
- deeplinkUri: persisted.deeplinkUri
9487
- });
9488
- console.info("[blink-sdk] guestPreauthMobileRestore: starting guest account polling", {
9489
- trigger,
10119
+ type: "GUEST_PREAUTH_DETECTED",
10120
+ accountId: persisted.accountId,
9490
10121
  sessionId: persisted.sessionId
9491
10122
  });
9492
- startGuestAccountPolling(persisted.guestSessionToken, persisted.sessionId);
9493
- };
9494
- const onVisibility = () => {
9495
- console.info("[blink-sdk] guestPreauthMobileRestore: visibilitychange fired", {
9496
- visibilityState: document.visibilityState,
9497
- startedRef: startedRef.current
9498
- });
9499
- if (document.visibilityState === "visible") tryStart("visibilitychange");
9500
- };
9501
- const onPageShow = (e) => {
9502
- console.info("[blink-sdk] guestPreauthMobileRestore: pageshow fired", {
9503
- persisted: e.persisted,
9504
- visibilityState: document.visibilityState,
9505
- startedRef: startedRef.current
9506
- });
9507
- if (document.visibilityState === "visible") tryStart("pageshow");
9508
- };
9509
- tryStart("initial");
9510
- document.addEventListener("visibilitychange", onVisibility);
9511
- window.addEventListener("pageshow", onPageShow);
9512
- return () => {
9513
- document.removeEventListener("visibilitychange", onVisibility);
9514
- window.removeEventListener("pageshow", onPageShow);
9515
- };
9516
- }, [privyReady, dispatch, mobileSetupFlowRef, setupAccountIdRef, startGuestAccountPolling]);
10123
+ }
10124
+ dispatch({
10125
+ type: "MOBILE_DEEPLINK_READY",
10126
+ deeplinkUri: persisted.deeplinkUri
10127
+ });
10128
+ console.info("[blink-sdk] guestPreauthMobileRestore: starting guest account polling", {
10129
+ sessionId: persisted.sessionId
10130
+ });
10131
+ startGuestAccountPolling(persisted.guestSessionToken, persisted.sessionId);
10132
+ }, [privyReady, lastResumedAt, dispatch, mobileSetupFlowRef, setupAccountIdRef, startGuestAccountPolling]);
9517
10133
  }
9518
10134
  function useSelectSourceEffect(deps) {
9519
10135
  const {
@@ -9817,7 +10433,7 @@ function useStandardDesktopInlineOpenWalletEffect(deps) {
9817
10433
  useEffect(() => {
9818
10434
  if (!isDesktop || state.guestPreauthorizing) return;
9819
10435
  if (!state.privyAuthenticated || !state.activeCredentialId || !state.selectedAccountId) return;
9820
- const shouldPin = authExecutor.executing && !authExecutor.pendingSelectSource && !authExecutor.pendingOneTapSetup;
10436
+ const shouldPin = authExecutor.executing && !authExecutor.pendingSelectSource && (!authExecutor.pendingOneTapSetup || authExecutor.authorizationSessionStackDepth > 1);
9821
10437
  if (shouldPin && !state.standardDesktopInlineOpenWallet) {
9822
10438
  dispatch({ type: "SET_STANDARD_DESKTOP_INLINE_OPEN_WALLET", value: true });
9823
10439
  return;
@@ -9835,6 +10451,7 @@ function useStandardDesktopInlineOpenWalletEffect(deps) {
9835
10451
  authExecutor.executing,
9836
10452
  authExecutor.pendingSelectSource,
9837
10453
  authExecutor.pendingOneTapSetup,
10454
+ authExecutor.authorizationSessionStackDepth,
9838
10455
  dispatch
9839
10456
  ]);
9840
10457
  }
@@ -9853,7 +10470,84 @@ function useGuestAccountAutoPollingEffect(deps) {
9853
10470
  startPolling(guestSessionToken);
9854
10471
  }, [mobileFlow, isGuestFlow, guestSessionToken, isPolling, guestAccount, startPolling]);
9855
10472
  }
9856
- function useGuestAccountPolling(intervalMs = 3e3) {
10473
+ var WATCHDOG_INTERVAL_MS = 1e3;
10474
+ var WATCHDOG_THRESHOLD_MS = 3e3;
10475
+ var DEDUP_COOLDOWN_MS = 500;
10476
+ function usePageResume(callback) {
10477
+ const callbackRef = useRef(callback);
10478
+ callbackRef.current = callback;
10479
+ useEffect(() => {
10480
+ let lastTickAt = Date.now();
10481
+ let lastFiredAt = 0;
10482
+ const fire = (source, frozenDurationMs) => {
10483
+ const now = Date.now();
10484
+ if (now - lastFiredAt < DEDUP_COOLDOWN_MS) return;
10485
+ lastFiredAt = now;
10486
+ callbackRef.current({ frozenDurationMs, source });
10487
+ };
10488
+ const watchdogId = window.setInterval(() => {
10489
+ const now = Date.now();
10490
+ const elapsed = now - lastTickAt;
10491
+ lastTickAt = now;
10492
+ if (elapsed > WATCHDOG_THRESHOLD_MS) {
10493
+ fire("watchdog", elapsed);
10494
+ }
10495
+ }, WATCHDOG_INTERVAL_MS);
10496
+ const handleVisibility = () => {
10497
+ const now = Date.now();
10498
+ if (document.visibilityState === "visible") {
10499
+ fire("visibilitychange", now - lastTickAt);
10500
+ }
10501
+ lastTickAt = now;
10502
+ };
10503
+ const handlePageShow = (_e) => {
10504
+ const now = Date.now();
10505
+ if (document.visibilityState === "visible") {
10506
+ fire("pageshow", now - lastTickAt);
10507
+ }
10508
+ lastTickAt = now;
10509
+ };
10510
+ const handleFocus = () => {
10511
+ const now = Date.now();
10512
+ const elapsed = now - lastTickAt;
10513
+ lastTickAt = now;
10514
+ if (elapsed > WATCHDOG_THRESHOLD_MS) {
10515
+ fire("focus", elapsed);
10516
+ }
10517
+ };
10518
+ document.addEventListener("visibilitychange", handleVisibility);
10519
+ window.addEventListener("pageshow", handlePageShow);
10520
+ window.addEventListener("focus", handleFocus);
10521
+ return () => {
10522
+ window.clearInterval(watchdogId);
10523
+ document.removeEventListener("visibilitychange", handleVisibility);
10524
+ window.removeEventListener("pageshow", handlePageShow);
10525
+ window.removeEventListener("focus", handleFocus);
10526
+ };
10527
+ }, []);
10528
+ }
10529
+ var STUCK_REF_THRESHOLD_MS = 5e3;
10530
+ function usePageResumeEffect(deps) {
10531
+ const { dispatch, handlingMobileReturnRef } = deps;
10532
+ const dispatchRef = useRef(dispatch);
10533
+ dispatchRef.current = dispatch;
10534
+ usePageResume((info) => {
10535
+ console.info("[blink-sdk] PAGE_RESUMED", {
10536
+ source: info.source,
10537
+ frozenDurationMs: info.frozenDurationMs
10538
+ });
10539
+ dispatchRef.current({ type: "PAGE_RESUMED", frozenDurationMs: info.frozenDurationMs });
10540
+ if (info.frozenDurationMs > STUCK_REF_THRESHOLD_MS) {
10541
+ if (handlingMobileReturnRef.current) {
10542
+ console.info("[blink-sdk] PAGE_RESUMED: clearing stuck handlingMobileReturnRef", {
10543
+ frozenDurationMs: info.frozenDurationMs
10544
+ });
10545
+ handlingMobileReturnRef.current = false;
10546
+ }
10547
+ }
10548
+ });
10549
+ }
10550
+ function useGuestAccountPolling(intervalMs = 3e3, lastResumedAt = 0) {
9857
10551
  const { apiBaseUrl } = useBlinkConfig();
9858
10552
  const [guestAccount, setGuestAccount] = useState(null);
9859
10553
  const [isPolling, setIsPolling] = useState(false);
@@ -9951,36 +10645,71 @@ function useGuestAccountPolling(intervalMs = 3e3) {
9951
10645
  [poll, intervalMs, stopPolling]
9952
10646
  );
9953
10647
  useEffect(() => {
9954
- const handleVisibility = () => {
9955
- console.info("[blink-sdk] useGuestAccountPolling: visibilitychange fired", {
9956
- visibilityState: document.visibilityState,
9957
- hasToken: !!guestTokenRef.current,
9958
- hasSessionId: !!sessionIdRef.current
9959
- });
9960
- if (document.visibilityState === "visible" && guestTokenRef.current) {
9961
- void poll();
9962
- }
9963
- };
9964
- const handlePageShow = (e) => {
9965
- console.info("[blink-sdk] useGuestAccountPolling: pageshow fired", {
9966
- persisted: e.persisted,
9967
- visibilityState: document.visibilityState,
9968
- hasToken: !!guestTokenRef.current,
9969
- hasSessionId: !!sessionIdRef.current
10648
+ if (!lastResumedAt || !guestTokenRef.current) return;
10649
+ console.info("[blink-sdk] useGuestAccountPolling: page resumed, triggering poll", {
10650
+ lastResumedAt,
10651
+ hasToken: !!guestTokenRef.current,
10652
+ hasSessionId: !!sessionIdRef.current
10653
+ });
10654
+ void poll();
10655
+ }, [lastResumedAt, poll]);
10656
+ useEffect(() => () => stopPolling(), [stopPolling]);
10657
+ return { guestAccount, error, isPolling, startPolling, stopPolling };
10658
+ }
10659
+ function useDepositFeeEstimate({
10660
+ apiBaseUrl,
10661
+ getAccessToken,
10662
+ walletId,
10663
+ sourceTokenAddress,
10664
+ destination,
10665
+ amount,
10666
+ enabled
10667
+ }) {
10668
+ const [quoteId, setQuoteId] = useState(null);
10669
+ const [quoteFee, setQuoteFee] = useState(null);
10670
+ const [quoteLoading, setQuoteLoading] = useState(false);
10671
+ const abortRef = useRef(null);
10672
+ const fetchQuote = useCallback(async () => {
10673
+ if (!enabled || !walletId || !sourceTokenAddress) {
10674
+ setQuoteId(null);
10675
+ setQuoteFee(null);
10676
+ setQuoteLoading(false);
10677
+ return;
10678
+ }
10679
+ abortRef.current?.abort();
10680
+ const controller = new AbortController();
10681
+ abortRef.current = controller;
10682
+ setQuoteLoading(true);
10683
+ try {
10684
+ const token = await getAccessToken();
10685
+ if (!token || controller.signal.aborted) return;
10686
+ const quote = await postTransferQuote(apiBaseUrl, token, {
10687
+ walletId,
10688
+ sourceTokenAddress,
10689
+ destination,
10690
+ amount: { amount, currency: "USD" }
9970
10691
  });
9971
- if (document.visibilityState === "visible" && guestTokenRef.current) {
9972
- void poll();
10692
+ if (controller.signal.aborted) return;
10693
+ setQuoteId(quote.id);
10694
+ setQuoteFee(quote.fee);
10695
+ } catch (err) {
10696
+ if (controller.signal.aborted) return;
10697
+ console.warn("[blink-sdk] Fee quote failed:", err);
10698
+ setQuoteId(null);
10699
+ setQuoteFee(null);
10700
+ } finally {
10701
+ if (!controller.signal.aborted) {
10702
+ setQuoteLoading(false);
9973
10703
  }
9974
- };
9975
- document.addEventListener("visibilitychange", handleVisibility);
9976
- window.addEventListener("pageshow", handlePageShow);
10704
+ }
10705
+ }, [enabled, walletId, sourceTokenAddress, destination, amount, apiBaseUrl, getAccessToken]);
10706
+ useEffect(() => {
10707
+ fetchQuote();
9977
10708
  return () => {
9978
- document.removeEventListener("visibilitychange", handleVisibility);
9979
- window.removeEventListener("pageshow", handlePageShow);
10709
+ abortRef.current?.abort();
9980
10710
  };
9981
- }, [poll]);
9982
- useEffect(() => () => stopPolling(), [stopPolling]);
9983
- return { guestAccount, error, isPolling, startPolling, stopPolling };
10711
+ }, [fetchQuote]);
10712
+ return { quoteId, quoteFee, quoteLoading };
9984
10713
  }
9985
10714
  function BlinkPayment(props) {
9986
10715
  const resetKey = useRef(0);
@@ -10013,14 +10742,14 @@ function BlinkPaymentInner({
10013
10742
  paymentReducer,
10014
10743
  {
10015
10744
  depositAmount,
10016
- passkeyPopupNeeded: isSafari() && isInCrossOriginIframe(),
10745
+ passkeyPopupNeeded: isSafari() && isInCrossOriginIframe() && !isDesktop,
10017
10746
  activeCredentialId: typeof window === "undefined" ? null : window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY)
10018
10747
  },
10019
10748
  createInitialState
10020
10749
  );
10021
10750
  const authExecutor = useAuthorizationExecutor();
10022
10751
  const polling = useTransferPolling();
10023
- const guestAccountPolling = useGuestAccountPolling();
10752
+ const guestAccountPolling = useGuestAccountPolling(3e3, state.lastResumedAt);
10024
10753
  const transferSigning = useTransferSigning();
10025
10754
  const mobileFlowRefs = {
10026
10755
  mobileSetupFlowRef: useRef(false),
@@ -10038,6 +10767,15 @@ function BlinkPaymentInner({
10038
10767
  state.accounts,
10039
10768
  state.knownCredentialIds
10040
10769
  );
10770
+ const depositFee = useDepositFeeEstimate({
10771
+ apiBaseUrl,
10772
+ getAccessToken,
10773
+ walletId: state.selectedWalletId,
10774
+ sourceTokenAddress: derived.selectedSource?.address,
10775
+ destination,
10776
+ amount: depositAmount ?? 5,
10777
+ enabled: state.phase.step === "deposit" && !state.isGuestFlow && authenticated
10778
+ });
10041
10779
  const transfer = useTransferHandlers({
10042
10780
  dispatch,
10043
10781
  getAccessToken,
@@ -10055,6 +10793,9 @@ function BlinkPaymentInner({
10055
10793
  sourceTokenAddress: derived.selectedSource?.address,
10056
10794
  activeCredentialId: state.activeCredentialId,
10057
10795
  selectedAccountId: state.selectedAccountId,
10796
+ selectedWalletId: state.selectedWalletId,
10797
+ selectedTokenSymbol: state.selectedTokenSymbol,
10798
+ quoteId: depositFee.quoteId,
10058
10799
  transfer: state.transfer,
10059
10800
  accounts: state.accounts
10060
10801
  });
@@ -10071,7 +10812,8 @@ function BlinkPaymentInner({
10071
10812
  guestTransferId: state.guestTransferId,
10072
10813
  guestSessionToken: state.guestSessionToken
10073
10814
  },
10074
- onComplete
10815
+ onComplete,
10816
+ state.lastResumedAt
10075
10817
  );
10076
10818
  const sourceSelection = useSourceSelectionHandlers(dispatch, authExecutor, {
10077
10819
  guestPreauthSessionId: state.guestPreauthSessionId,
@@ -10167,10 +10909,15 @@ function BlinkPaymentInner({
10167
10909
  dispatch({ type: "SYNC_AMOUNT", amount: depositAmount.toString() });
10168
10910
  }
10169
10911
  }, [depositAmount, dispatch]);
10912
+ usePageResumeEffect({
10913
+ dispatch,
10914
+ handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef
10915
+ });
10170
10916
  usePrivySessionSyncEffect({ dispatch, ready, authenticated });
10171
10917
  useGuestPreauthMobileRestoreEffect({
10172
10918
  dispatch,
10173
10919
  privyReady: state.privyReady,
10920
+ lastResumedAt: state.lastResumedAt,
10174
10921
  mobileSetupFlowRef: mobileFlowRefs.mobileSetupFlowRef,
10175
10922
  setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
10176
10923
  startGuestAccountPolling: guestAccountPolling.startPolling
@@ -10183,25 +10930,24 @@ function BlinkPaymentInner({
10183
10930
  guestAccount: guestAccountPolling.guestAccount,
10184
10931
  startPolling: guestAccountPolling.startPolling
10185
10932
  });
10186
- const guestSessionTokenRef = useRef(state.guestSessionToken);
10187
- guestSessionTokenRef.current = state.guestSessionToken;
10188
- const guestPreauthSessionIdRef = useRef(state.guestPreauthSessionId);
10189
- guestPreauthSessionIdRef.current = state.guestPreauthSessionId;
10190
10933
  useEffect(() => {
10191
- const handleVisibility = () => {
10192
- if (document.visibilityState !== "visible") return;
10193
- const token = guestSessionTokenRef.current;
10194
- const sessionId = guestPreauthSessionIdRef.current;
10195
- if (!token) return;
10196
- if (guestAccountPolling.isPolling || guestAccountPolling.guestAccount) return;
10197
- console.info("[blink-sdk] warm-return: restarting guest account polling from React state", {
10198
- sessionId: sessionId ?? "(none \u2014 account-only mode)"
10199
- });
10200
- guestAccountPolling.startPolling(token, sessionId ?? void 0);
10201
- };
10202
- document.addEventListener("visibilitychange", handleVisibility);
10203
- return () => document.removeEventListener("visibilitychange", handleVisibility);
10204
- }, [guestAccountPolling.isPolling, guestAccountPolling.guestAccount, guestAccountPolling.startPolling]);
10934
+ if (!state.lastResumedAt) return;
10935
+ const token = state.guestSessionToken;
10936
+ const sessionId = state.guestPreauthSessionId;
10937
+ if (!token) return;
10938
+ if (guestAccountPolling.isPolling || guestAccountPolling.guestAccount) return;
10939
+ console.info("[blink-sdk] warm-return: restarting guest account polling from React state", {
10940
+ sessionId: sessionId ?? "(none \u2014 account-only mode)"
10941
+ });
10942
+ guestAccountPolling.startPolling(token, sessionId ?? void 0);
10943
+ }, [
10944
+ state.lastResumedAt,
10945
+ state.guestSessionToken,
10946
+ state.guestPreauthSessionId,
10947
+ guestAccountPolling.isPolling,
10948
+ guestAccountPolling.guestAccount,
10949
+ guestAccountPolling.startPolling
10950
+ ]);
10205
10951
  useEffect(() => {
10206
10952
  console.info("[blink-sdk] guestPreauthCompletion effect", {
10207
10953
  hasGuestAccount: !!guestAccountPolling.guestAccount,
@@ -10352,7 +11098,10 @@ function BlinkPaymentInner({
10352
11098
  dispatch({ type: "BACK_TO_LOGIN" });
10353
11099
  },
10354
11100
  onRegisterPasskey: passkey.handleRegisterPasskey,
11101
+ onVerifyPasskey: passkey.handleVerifyPasskey,
11102
+ onCreateNewPasskey: passkey.handleCreateNewPasskey,
10355
11103
  onCreatePasskeyViaPopup: passkey.handleCreatePasskeyViaPopup,
11104
+ onCreateNewPasskeyViaPopup: passkey.handleCreateNewPasskeyViaPopup,
10356
11105
  onVerifyPasskeyViaPopup: passkey.handleVerifyPasskeyViaPopup,
10357
11106
  onPrepareProvider: provider.handlePrepareProvider,
10358
11107
  onSelectProvider: provider.handleSelectProvider,
@@ -10366,6 +11115,11 @@ function BlinkPaymentInner({
10366
11115
  onLogout: handleLogout,
10367
11116
  onNewPayment: handleNewPayment,
10368
11117
  onSetPhase: (phase) => dispatch({ type: "SET_USER_INTENT", intent: phase }),
11118
+ onBackFromSubflow: () => {
11119
+ authExecutor.cancelPendingExecution();
11120
+ dispatch({ type: "RESTORE_SELECTION" });
11121
+ dispatch({ type: "SET_USER_INTENT", intent: { step: "deposit" } });
11122
+ },
10369
11123
  onSetAuthInput: auth.setAuthInput,
10370
11124
  onSetOtpCode: (code) => {
10371
11125
  auth.setOtpCode(code);
@@ -10399,7 +11153,8 @@ function BlinkPaymentInner({
10399
11153
  handleLogout,
10400
11154
  handleNewPayment,
10401
11155
  onDismiss,
10402
- dispatch
11156
+ dispatch,
11157
+ authExecutor
10403
11158
  ]);
10404
11159
  return /* @__PURE__ */ jsx(
10405
11160
  StepRenderer,
@@ -10448,13 +11203,16 @@ function BlinkPaymentInner({
10448
11203
  guestSettingSender: guestTransfer.settingSender,
10449
11204
  guestPendingEntry: guestTransfer.pendingGuestEntry,
10450
11205
  guestQuoteFee: guestTransfer.guestFee?.quote ?? null,
10451
- guestQuoteLoading: guestTransfer.guestQuoteLoading
11206
+ guestQuoteLoading: guestTransfer.guestQuoteLoading,
11207
+ depositQuoteId: depositFee.quoteId,
11208
+ depositQuoteFee: depositFee.quoteFee,
11209
+ depositQuoteLoading: depositFee.quoteLoading
10452
11210
  },
10453
11211
  handlers
10454
11212
  }
10455
11213
  );
10456
11214
  }
10457
11215
 
10458
- export { AdvancedSourceScreen, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, BlinkProvider, ConfirmSignScreen, DepositScreen, FlowPhaseProvider, GuestPreauthLinkingScreen, GuestPreauthSetupCompleteScreen, GuestTokenPickerScreen, IconCircle, InfoBanner, LoginScreen, OpenWalletScreen, OtpVerifyScreen, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, SetupStatusScreen, Spinner, StepList, SuccessScreen, TokenPickerScreen, TransferStatusScreen, VerifyPasskeyScreen, WalletPickerScreen, api_exports as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, guestEntryMatchingRecommended, lightTheme, mapGuestPickerEntries, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
11216
+ export { AdvancedSourceScreen, AuthorizationSessionCancelledError, BLINK_LOGO, BLINK_MASCOT, BlinkLoadingScreen, BlinkPayment, BlinkProvider, ConfirmSignScreen, DepositScreen, FlowPhaseProvider, GuestPreauthLinkingScreen, GuestPreauthSetupCompleteScreen, GuestTokenPickerScreen, IconCircle, InfoBanner, LoginScreen, OpenWalletScreen, OtpVerifyScreen, OutlineButton, PasskeyIframeBlockedError, PasskeyScreen, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, SetupScreen, SetupStatusScreen, Spinner, StepList, SuccessScreen, TokenPickerScreen, TransferStatusScreen, VerifyPasskeyScreen, WalletPickerScreen, api_exports as blinkApi, buildPasskeyPopupOptions, createPasskeyCredential, createPasskeyViaPopup, darkTheme, deviceHasPasskey, findDevicePasskey, findDevicePasskeyViaPopup, getTheme, guestEntryMatchingRecommended, isAuthorizationSessionCancelled, isUserDismissedAuthorizationError, lightTheme, mapGuestPickerEntries, resolvePasskeyRpId, screenForPhase, useAuthorizationExecutor, useBlinkConfig, useBlinkDepositAmount, useTransferPolling, useTransferSigning };
10459
11217
  //# sourceMappingURL=index.js.map
10460
11218
  //# sourceMappingURL=index.js.map