@swype-org/react-sdk 0.1.133 → 0.1.142

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,5 +1,5 @@
1
1
  import { createContext, useRef, useState, useCallback, useMemo, useContext, useEffect, useReducer, Component } from 'react';
2
- import { PrivyProvider, usePrivy, useLoginWithEmail, useLoginWithSms, useLoginWithOAuth } from '@privy-io/react-auth';
2
+ import { PrivyProvider, usePrivy, useLoginWithOAuth, useLoginWithEmail, useLoginWithSms } from '@privy-io/react-auth';
3
3
  import { createConfig, http, WagmiProvider, useConfig, useConnect, useSwitchChain } from 'wagmi';
4
4
  import { mainnet, arbitrum, base, polygon, bsc } from 'wagmi/chains';
5
5
  import { injected } from 'wagmi/connectors';
@@ -153,261 +153,6 @@ function useSwypeDepositAmount() {
153
153
  };
154
154
  }
155
155
 
156
- // src/api.ts
157
- var api_exports = {};
158
- __export(api_exports, {
159
- createAccount: () => createAccount,
160
- createAccountAuthorizationSession: () => createAccountAuthorizationSession,
161
- createTransfer: () => createTransfer,
162
- fetchAccount: () => fetchAccount,
163
- fetchAccounts: () => fetchAccounts,
164
- fetchAuthorizationSession: () => fetchAuthorizationSession,
165
- fetchChains: () => fetchChains,
166
- fetchMerchantPublicKey: () => fetchMerchantPublicKey,
167
- fetchProviders: () => fetchProviders,
168
- fetchTransfer: () => fetchTransfer,
169
- fetchUserConfig: () => fetchUserConfig,
170
- registerPasskey: () => registerPasskey,
171
- reportActionCompletion: () => reportActionCompletion,
172
- reportPasskeyActivity: () => reportPasskeyActivity,
173
- signTransfer: () => signTransfer,
174
- updateUserConfig: () => updateUserConfig,
175
- updateUserConfigBySession: () => updateUserConfigBySession
176
- });
177
- async function throwApiError(res) {
178
- const body = await res.json().catch(() => null);
179
- const detail = body?.error ?? body;
180
- const msg = detail?.message ?? res.statusText;
181
- const code = detail?.code ?? String(res.status);
182
- throw new Error(`${res.status} \u2014 ${code}: ${msg}`);
183
- }
184
- async function fetchProviders(apiBaseUrl, token) {
185
- const res = await fetch(`${apiBaseUrl}/v1/providers`, {
186
- headers: { Authorization: `Bearer ${token}` }
187
- });
188
- if (!res.ok) await throwApiError(res);
189
- const data = await res.json();
190
- return data.items;
191
- }
192
- async function fetchChains(apiBaseUrl, token) {
193
- const res = await fetch(`${apiBaseUrl}/v1/chains`, {
194
- headers: { Authorization: `Bearer ${token}` }
195
- });
196
- if (!res.ok) await throwApiError(res);
197
- const data = await res.json();
198
- return data.items;
199
- }
200
- async function fetchAccounts(apiBaseUrl, token, credentialId) {
201
- const params = new URLSearchParams({ credentialId });
202
- const res = await fetch(`${apiBaseUrl}/v1/accounts?${params.toString()}`, {
203
- headers: { Authorization: `Bearer ${token}` }
204
- });
205
- if (!res.ok) await throwApiError(res);
206
- const data = await res.json();
207
- return data.items;
208
- }
209
- async function fetchAccount(apiBaseUrl, token, accountId, credentialId) {
210
- const params = new URLSearchParams({ credentialId });
211
- const res = await fetch(`${apiBaseUrl}/v1/accounts/${accountId}?${params.toString()}`, {
212
- headers: { Authorization: `Bearer ${token}` }
213
- });
214
- if (!res.ok) await throwApiError(res);
215
- return await res.json();
216
- }
217
- async function createAccount(apiBaseUrl, token, params) {
218
- const body = {
219
- id: params.id ?? crypto.randomUUID(),
220
- name: params.name,
221
- credentialId: params.credentialId,
222
- providerId: params.providerId
223
- };
224
- if (params.nickname) {
225
- body.nickname = params.nickname;
226
- }
227
- const res = await fetch(`${apiBaseUrl}/v1/accounts`, {
228
- method: "POST",
229
- headers: {
230
- "Content-Type": "application/json",
231
- Authorization: `Bearer ${token}`
232
- },
233
- body: JSON.stringify(body)
234
- });
235
- if (!res.ok) await throwApiError(res);
236
- return await res.json();
237
- }
238
- async function createAccountAuthorizationSession(apiBaseUrl, token, accountId, credentialId, options) {
239
- const body = { credentialId };
240
- if (options?.tokenAddress) body.tokenAddress = options.tokenAddress;
241
- if (options?.chainId != null) body.chainId = options.chainId;
242
- const res = await fetch(
243
- `${apiBaseUrl}/v1/accounts/${accountId}/authorization-sessions`,
244
- {
245
- method: "POST",
246
- headers: {
247
- "Content-Type": "application/json",
248
- Authorization: `Bearer ${token}`
249
- },
250
- body: JSON.stringify(body)
251
- }
252
- );
253
- if (!res.ok) await throwApiError(res);
254
- return await res.json();
255
- }
256
- async function createTransfer(apiBaseUrl, token, params) {
257
- if (!params.merchantAuthorization) {
258
- throw new Error("merchantAuthorization is required for transfer creation.");
259
- }
260
- const body = {
261
- id: params.id ?? crypto.randomUUID(),
262
- credentialId: params.credentialId,
263
- merchantAuthorization: params.merchantAuthorization,
264
- sources: [{ [params.sourceType]: params.sourceId }],
265
- destinations: [
266
- {
267
- chainId: params.destination.chainId,
268
- token: { address: params.destination.token.address },
269
- address: params.destination.address
270
- }
271
- ],
272
- amount: {
273
- amount: params.amount,
274
- currency: params.currency ?? "USD"
275
- }
276
- };
277
- const res = await fetch(`${apiBaseUrl}/v1/transfers`, {
278
- method: "POST",
279
- headers: {
280
- "Content-Type": "application/json",
281
- Authorization: `Bearer ${token}`
282
- },
283
- body: JSON.stringify(body)
284
- });
285
- if (!res.ok) await throwApiError(res);
286
- return await res.json();
287
- }
288
- async function fetchMerchantPublicKey(apiBaseUrl, merchantId) {
289
- const res = await fetch(
290
- `${apiBaseUrl}/v1/merchants/${encodeURIComponent(merchantId)}/public-key`
291
- );
292
- if (!res.ok) await throwApiError(res);
293
- return await res.json();
294
- }
295
- async function fetchTransfer(apiBaseUrl, token, transferId, authorizationSessionToken) {
296
- if (!token && !authorizationSessionToken) {
297
- throw new Error("Missing auth credentials for transfer fetch.");
298
- }
299
- const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
300
- headers: {
301
- ...token ? { Authorization: `Bearer ${token}` } : {},
302
- ...authorizationSessionToken ? { "x-authorization-session-token": authorizationSessionToken } : {}
303
- }
304
- });
305
- if (!res.ok) await throwApiError(res);
306
- return await res.json();
307
- }
308
- async function signTransfer(apiBaseUrl, token, transferId, signedUserOp, authorizationSessionToken) {
309
- if (!token && !authorizationSessionToken) {
310
- throw new Error("Missing auth credentials for transfer signing.");
311
- }
312
- const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
313
- method: "PATCH",
314
- headers: {
315
- "Content-Type": "application/json",
316
- ...token ? { Authorization: `Bearer ${token}` } : {},
317
- ...authorizationSessionToken ? { "x-authorization-session-token": authorizationSessionToken } : {}
318
- },
319
- body: JSON.stringify({ signedUserOp })
320
- });
321
- if (!res.ok) await throwApiError(res);
322
- return await res.json();
323
- }
324
- async function fetchAuthorizationSession(apiBaseUrl, sessionId) {
325
- const res = await fetch(
326
- `${apiBaseUrl}/v1/authorization-sessions/${sessionId}`
327
- );
328
- if (!res.ok) await throwApiError(res);
329
- return await res.json();
330
- }
331
- async function registerPasskey(apiBaseUrl, token, credentialId, publicKey) {
332
- const res = await fetch(`${apiBaseUrl}/v1/users/config/passkey`, {
333
- method: "POST",
334
- headers: {
335
- "Content-Type": "application/json",
336
- Authorization: `Bearer ${token}`
337
- },
338
- body: JSON.stringify({ credentialId, publicKey })
339
- });
340
- if (!res.ok) await throwApiError(res);
341
- }
342
- async function reportPasskeyActivity(apiBaseUrl, token, credentialId) {
343
- const res = await fetch(`${apiBaseUrl}/v1/users/config/passkey`, {
344
- method: "PATCH",
345
- headers: {
346
- "Content-Type": "application/json",
347
- Authorization: `Bearer ${token}`
348
- },
349
- body: JSON.stringify({ credentialId })
350
- });
351
- if (!res.ok) await throwApiError(res);
352
- }
353
- async function fetchUserConfig(apiBaseUrl, token) {
354
- const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
355
- headers: { Authorization: `Bearer ${token}` }
356
- });
357
- if (!res.ok) await throwApiError(res);
358
- return await res.json();
359
- }
360
- async function updateUserConfig(apiBaseUrl, token, config) {
361
- const res = await fetch(`${apiBaseUrl}/v1/users`, {
362
- method: "PATCH",
363
- headers: {
364
- "Content-Type": "application/json",
365
- Authorization: `Bearer ${token}`
366
- },
367
- body: JSON.stringify({ config })
368
- });
369
- if (!res.ok) await throwApiError(res);
370
- }
371
- async function updateUserConfigBySession(apiBaseUrl, sessionId, config) {
372
- const res = await fetch(
373
- `${apiBaseUrl}/v1/authorization-sessions/${sessionId}/user-config`,
374
- {
375
- method: "PATCH",
376
- headers: { "Content-Type": "application/json" },
377
- body: JSON.stringify({ config })
378
- }
379
- );
380
- if (!res.ok) await throwApiError(res);
381
- }
382
- async function reportActionCompletion(apiBaseUrl, actionId, result) {
383
- const res = await fetch(
384
- `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
385
- {
386
- method: "PATCH",
387
- headers: { "Content-Type": "application/json" },
388
- body: JSON.stringify({ status: "COMPLETED", result })
389
- }
390
- );
391
- if (!res.ok) await throwApiError(res);
392
- return await res.json();
393
- }
394
-
395
- // src/sentry.ts
396
- var _mod;
397
- function captureException(error) {
398
- if (_mod === null) return;
399
- if (_mod) {
400
- _mod.captureException(error);
401
- return;
402
- }
403
- import('@sentry/react').then((m) => {
404
- _mod = m;
405
- m.captureException(error);
406
- }).catch(() => {
407
- _mod = null;
408
- });
409
- }
410
-
411
156
  // node_modules/@wagmi/core/dist/esm/version.js
412
157
  var version = "2.22.1";
413
158
 
@@ -668,8 +413,250 @@ async function getWalletClient(config, parameters = {}) {
668
413
  return client.extend(walletActions);
669
414
  }
670
415
 
671
- // src/passkeyRpId.ts
672
- function normalizeConfiguredDomain(value) {
416
+ // src/api.ts
417
+ var api_exports = {};
418
+ __export(api_exports, {
419
+ createAccount: () => createAccount,
420
+ createAccountAuthorizationSession: () => createAccountAuthorizationSession,
421
+ createTransfer: () => createTransfer,
422
+ fetchAccount: () => fetchAccount,
423
+ fetchAccounts: () => fetchAccounts,
424
+ fetchAuthorizationSession: () => fetchAuthorizationSession,
425
+ fetchChains: () => fetchChains,
426
+ fetchMerchantPublicKey: () => fetchMerchantPublicKey,
427
+ fetchProviders: () => fetchProviders,
428
+ fetchTransfer: () => fetchTransfer,
429
+ fetchUserConfig: () => fetchUserConfig,
430
+ registerPasskey: () => registerPasskey,
431
+ reportActionCompletion: () => reportActionCompletion,
432
+ reportPasskeyActivity: () => reportPasskeyActivity,
433
+ signTransfer: () => signTransfer,
434
+ updateUserConfig: () => updateUserConfig,
435
+ updateUserConfigBySession: () => updateUserConfigBySession
436
+ });
437
+ async function throwApiError(res) {
438
+ const body = await res.json().catch(() => null);
439
+ const detail = body?.error ?? body;
440
+ const msg = detail?.message ?? res.statusText;
441
+ const code = detail?.code ?? String(res.status);
442
+ throw new Error(`${res.status} \u2014 ${code}: ${msg}`);
443
+ }
444
+ async function fetchProviders(apiBaseUrl, token) {
445
+ const res = await fetch(`${apiBaseUrl}/v1/providers`, {
446
+ headers: { Authorization: `Bearer ${token}` }
447
+ });
448
+ if (!res.ok) await throwApiError(res);
449
+ const data = await res.json();
450
+ return data.items;
451
+ }
452
+ async function fetchChains(apiBaseUrl, token) {
453
+ const res = await fetch(`${apiBaseUrl}/v1/chains`, {
454
+ headers: { Authorization: `Bearer ${token}` }
455
+ });
456
+ if (!res.ok) await throwApiError(res);
457
+ const data = await res.json();
458
+ return data.items;
459
+ }
460
+ async function fetchAccounts(apiBaseUrl, token, credentialId) {
461
+ const params = new URLSearchParams({ credentialId });
462
+ const res = await fetch(`${apiBaseUrl}/v1/accounts?${params.toString()}`, {
463
+ headers: { Authorization: `Bearer ${token}` }
464
+ });
465
+ if (!res.ok) await throwApiError(res);
466
+ const data = await res.json();
467
+ return data.items;
468
+ }
469
+ async function fetchAccount(apiBaseUrl, token, accountId, credentialId) {
470
+ const params = new URLSearchParams({ credentialId });
471
+ const res = await fetch(`${apiBaseUrl}/v1/accounts/${accountId}?${params.toString()}`, {
472
+ headers: { Authorization: `Bearer ${token}` }
473
+ });
474
+ if (!res.ok) await throwApiError(res);
475
+ return await res.json();
476
+ }
477
+ async function createAccount(apiBaseUrl, token, params) {
478
+ const body = {
479
+ id: params.id ?? crypto.randomUUID(),
480
+ name: params.name,
481
+ credentialId: params.credentialId,
482
+ providerId: params.providerId
483
+ };
484
+ if (params.nickname) {
485
+ body.nickname = params.nickname;
486
+ }
487
+ const res = await fetch(`${apiBaseUrl}/v1/accounts`, {
488
+ method: "POST",
489
+ headers: {
490
+ "Content-Type": "application/json",
491
+ Authorization: `Bearer ${token}`
492
+ },
493
+ body: JSON.stringify(body)
494
+ });
495
+ if (!res.ok) await throwApiError(res);
496
+ return await res.json();
497
+ }
498
+ async function createAccountAuthorizationSession(apiBaseUrl, token, accountId, credentialId, options) {
499
+ const body = { credentialId };
500
+ if (options?.tokenAddress) body.tokenAddress = options.tokenAddress;
501
+ if (options?.chainId != null) body.chainId = options.chainId;
502
+ const res = await fetch(
503
+ `${apiBaseUrl}/v1/accounts/${accountId}/authorization-sessions`,
504
+ {
505
+ method: "POST",
506
+ headers: {
507
+ "Content-Type": "application/json",
508
+ Authorization: `Bearer ${token}`
509
+ },
510
+ body: JSON.stringify(body)
511
+ }
512
+ );
513
+ if (!res.ok) await throwApiError(res);
514
+ return await res.json();
515
+ }
516
+ async function createTransfer(apiBaseUrl, token, params) {
517
+ if (!params.merchantAuthorization) {
518
+ throw new Error("merchantAuthorization is required for transfer creation.");
519
+ }
520
+ const body = {
521
+ id: params.id ?? crypto.randomUUID(),
522
+ credentialId: params.credentialId,
523
+ merchantAuthorization: params.merchantAuthorization,
524
+ sources: [{
525
+ [params.sourceType]: params.sourceId,
526
+ ...params.sourceTokenAddress ? { tokenAddress: params.sourceTokenAddress } : {}
527
+ }],
528
+ destinations: [
529
+ {
530
+ chainId: params.destination.chainId,
531
+ token: { address: params.destination.token.address },
532
+ address: params.destination.address
533
+ }
534
+ ],
535
+ amount: {
536
+ amount: params.amount,
537
+ currency: params.currency ?? "USD"
538
+ }
539
+ };
540
+ const res = await fetch(`${apiBaseUrl}/v1/transfers`, {
541
+ method: "POST",
542
+ headers: {
543
+ "Content-Type": "application/json",
544
+ Authorization: `Bearer ${token}`
545
+ },
546
+ body: JSON.stringify(body)
547
+ });
548
+ if (!res.ok) await throwApiError(res);
549
+ return await res.json();
550
+ }
551
+ async function fetchMerchantPublicKey(apiBaseUrl, merchantId) {
552
+ const res = await fetch(
553
+ `${apiBaseUrl}/v1/merchants/${encodeURIComponent(merchantId)}/public-key`
554
+ );
555
+ if (!res.ok) await throwApiError(res);
556
+ return await res.json();
557
+ }
558
+ async function fetchTransfer(apiBaseUrl, token, transferId, authorizationSessionToken) {
559
+ if (!token && !authorizationSessionToken) {
560
+ throw new Error("Missing auth credentials for transfer fetch.");
561
+ }
562
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
563
+ headers: {
564
+ ...token ? { Authorization: `Bearer ${token}` } : {},
565
+ ...authorizationSessionToken ? { "x-authorization-session-token": authorizationSessionToken } : {}
566
+ }
567
+ });
568
+ if (!res.ok) await throwApiError(res);
569
+ return await res.json();
570
+ }
571
+ async function signTransfer(apiBaseUrl, token, transferId, signedUserOp, authorizationSessionToken) {
572
+ if (!token && !authorizationSessionToken) {
573
+ throw new Error("Missing auth credentials for transfer signing.");
574
+ }
575
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
576
+ method: "PATCH",
577
+ headers: {
578
+ "Content-Type": "application/json",
579
+ ...token ? { Authorization: `Bearer ${token}` } : {},
580
+ ...authorizationSessionToken ? { "x-authorization-session-token": authorizationSessionToken } : {}
581
+ },
582
+ body: JSON.stringify({ signedUserOp })
583
+ });
584
+ if (!res.ok) await throwApiError(res);
585
+ return await res.json();
586
+ }
587
+ async function fetchAuthorizationSession(apiBaseUrl, sessionId) {
588
+ const res = await fetch(
589
+ `${apiBaseUrl}/v1/authorization-sessions/${sessionId}`
590
+ );
591
+ if (!res.ok) await throwApiError(res);
592
+ return await res.json();
593
+ }
594
+ async function registerPasskey(apiBaseUrl, token, credentialId, publicKey) {
595
+ const res = await fetch(`${apiBaseUrl}/v1/users/config/passkey`, {
596
+ method: "POST",
597
+ headers: {
598
+ "Content-Type": "application/json",
599
+ Authorization: `Bearer ${token}`
600
+ },
601
+ body: JSON.stringify({ credentialId, publicKey })
602
+ });
603
+ if (!res.ok) await throwApiError(res);
604
+ }
605
+ async function reportPasskeyActivity(apiBaseUrl, token, credentialId) {
606
+ const res = await fetch(`${apiBaseUrl}/v1/users/config/passkey`, {
607
+ method: "PATCH",
608
+ headers: {
609
+ "Content-Type": "application/json",
610
+ Authorization: `Bearer ${token}`
611
+ },
612
+ body: JSON.stringify({ credentialId })
613
+ });
614
+ if (!res.ok) await throwApiError(res);
615
+ }
616
+ async function fetchUserConfig(apiBaseUrl, token) {
617
+ const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
618
+ headers: { Authorization: `Bearer ${token}` }
619
+ });
620
+ if (!res.ok) await throwApiError(res);
621
+ return await res.json();
622
+ }
623
+ async function updateUserConfig(apiBaseUrl, token, config) {
624
+ const res = await fetch(`${apiBaseUrl}/v1/users`, {
625
+ method: "PATCH",
626
+ headers: {
627
+ "Content-Type": "application/json",
628
+ Authorization: `Bearer ${token}`
629
+ },
630
+ body: JSON.stringify({ config })
631
+ });
632
+ if (!res.ok) await throwApiError(res);
633
+ }
634
+ async function updateUserConfigBySession(apiBaseUrl, sessionId, config) {
635
+ const res = await fetch(
636
+ `${apiBaseUrl}/v1/authorization-sessions/${sessionId}/user-config`,
637
+ {
638
+ method: "PATCH",
639
+ headers: { "Content-Type": "application/json" },
640
+ body: JSON.stringify({ config })
641
+ }
642
+ );
643
+ if (!res.ok) await throwApiError(res);
644
+ }
645
+ async function reportActionCompletion(apiBaseUrl, actionId, result) {
646
+ const res = await fetch(
647
+ `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
648
+ {
649
+ method: "PATCH",
650
+ headers: { "Content-Type": "application/json" },
651
+ body: JSON.stringify({ status: "COMPLETED", result })
652
+ }
653
+ );
654
+ if (!res.ok) await throwApiError(res);
655
+ return await res.json();
656
+ }
657
+
658
+ // src/passkeyRpId.ts
659
+ function normalizeConfiguredDomain(value) {
673
660
  return value.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/^\./, "").trim();
674
661
  }
675
662
  function resolveRootDomainFromHostname(hostname) {
@@ -1653,170 +1640,6 @@ function useTransferSigning(pollIntervalMs = 2e3, options) {
1653
1640
  return { signing, signPayload, error, signTransfer: signTransfer2 };
1654
1641
  }
1655
1642
 
1656
- // src/auth.ts
1657
- var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1658
- var PHONE_DIGIT_PATTERN = /^\d{7,15}$/;
1659
- function normalizePhoneNumber(rawValue) {
1660
- const trimmed = rawValue.trim();
1661
- if (!trimmed) return null;
1662
- const hasExplicitCountryCode = trimmed.startsWith("+");
1663
- const digits = trimmed.replace(/\D/g, "");
1664
- if (!PHONE_DIGIT_PATTERN.test(digits)) return null;
1665
- return hasExplicitCountryCode ? `+${digits}` : digits;
1666
- }
1667
- function normalizeAuthIdentifier(rawValue) {
1668
- const trimmed = rawValue.trim();
1669
- if (!trimmed) return null;
1670
- if (EMAIL_PATTERN.test(trimmed)) {
1671
- return {
1672
- kind: "email",
1673
- value: trimmed.toLowerCase()
1674
- };
1675
- }
1676
- const normalizedPhoneNumber = normalizePhoneNumber(trimmed);
1677
- if (normalizedPhoneNumber) {
1678
- return {
1679
- kind: "phone",
1680
- value: normalizedPhoneNumber
1681
- };
1682
- }
1683
- return null;
1684
- }
1685
- function maskAuthIdentifier(identifier) {
1686
- if (identifier.kind === "email") {
1687
- const [localPart, domain = ""] = identifier.value.split("@");
1688
- const localPrefix = localPart.slice(0, 2);
1689
- return `${localPrefix}${"*".repeat(Math.max(localPart.length - 2, 0))}@${domain}`;
1690
- }
1691
- const digits = identifier.value.replace(/\D/g, "");
1692
- const visibleSuffix = digits.slice(-4);
1693
- return `***-***-${visibleSuffix}`;
1694
- }
1695
-
1696
- // src/processingStatus.ts
1697
- var PROCESSING_TIMEOUT_MS = 18e4;
1698
- function resolvePreferredTransfer(polledTransfer, localTransfer) {
1699
- return polledTransfer ?? localTransfer;
1700
- }
1701
- function getTransferStatus(polledTransfer, localTransfer) {
1702
- const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
1703
- return transfer?.status ?? "UNKNOWN";
1704
- }
1705
- function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
1706
- if (!processingStartedAtMs) return false;
1707
- return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
1708
- }
1709
- var STATUS_DISPLAY_LABELS = {
1710
- CREATED: "created",
1711
- AUTHORIZED: "authorized",
1712
- SENDING: "sending",
1713
- SENT: "confirming delivery",
1714
- COMPLETED: "completed",
1715
- FAILED: "failed"
1716
- };
1717
- function getStatusDisplayLabel(status) {
1718
- return STATUS_DISPLAY_LABELS[status] ?? status;
1719
- }
1720
- function buildProcessingTimeoutMessage(status) {
1721
- const label = getStatusDisplayLabel(status);
1722
- return `Payment is taking longer than expected (status: ${label}). Please try again.`;
1723
- }
1724
-
1725
- // src/walletFlow.ts
1726
- var MOBILE_USER_AGENT_PATTERN = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
1727
- function isMobileUserAgent(userAgent) {
1728
- if (!userAgent) {
1729
- return false;
1730
- }
1731
- return MOBILE_USER_AGENT_PATTERN.test(userAgent);
1732
- }
1733
- function shouldUseWalletConnector(options) {
1734
- return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
1735
- }
1736
-
1737
- // src/deeplink.ts
1738
- var IFRAME_CLEANUP_DELAY_MS = 3e3;
1739
- var LOCATION_FALLBACK_DELAY_MS = 100;
1740
- function triggerDeeplink(uri) {
1741
- try {
1742
- const iframe = document.createElement("iframe");
1743
- iframe.style.display = "none";
1744
- iframe.src = uri;
1745
- document.body.appendChild(iframe);
1746
- setTimeout(() => {
1747
- try {
1748
- document.body.removeChild(iframe);
1749
- } catch {
1750
- }
1751
- }, IFRAME_CLEANUP_DELAY_MS);
1752
- } catch {
1753
- }
1754
- setTimeout(() => {
1755
- window.location.href = uri;
1756
- }, LOCATION_FALLBACK_DELAY_MS);
1757
- }
1758
-
1759
- // src/mobileFlow.ts
1760
- function hasActiveWallet(accounts) {
1761
- return accounts.some((account) => account.wallets.some((wallet) => wallet.status === "ACTIVE"));
1762
- }
1763
- function resolvePostAuthStep(state) {
1764
- if (!state.hasPasskey) {
1765
- return { step: "create-passkey", clearPersistedFlow: false };
1766
- }
1767
- if (state.persistedMobileFlow) {
1768
- if (state.persistedMobileFlow.isReauthorization) {
1769
- return { step: "open-wallet", clearPersistedFlow: false };
1770
- }
1771
- if (state.persistedMobileFlow.isSetup && hasActiveWallet(state.accounts)) {
1772
- return { step: "deposit", clearPersistedFlow: true };
1773
- }
1774
- return { step: "open-wallet", clearPersistedFlow: false };
1775
- }
1776
- if (state.mobileSetupInProgress && !hasActiveWallet(state.accounts)) {
1777
- return { step: "open-wallet", clearPersistedFlow: false };
1778
- }
1779
- if ((state.accounts.length === 0 || !hasActiveWallet(state.accounts)) && !state.connectingNewAccount) {
1780
- return { step: "wallet-picker", clearPersistedFlow: false };
1781
- }
1782
- return { step: "deposit", clearPersistedFlow: false };
1783
- }
1784
- function resolveRestoredMobileFlow(transferStatus, isSetup) {
1785
- if (transferStatus === "AUTHORIZED") {
1786
- return isSetup ? { kind: "resume-setup-deposit", step: "deposit", clearPersistedFlow: true } : { kind: "resume-confirm-sign", step: "confirm-sign", clearPersistedFlow: true };
1787
- }
1788
- if (transferStatus === "COMPLETED") {
1789
- return { kind: "resume-success", step: "success", clearPersistedFlow: true };
1790
- }
1791
- if (transferStatus === "FAILED") {
1792
- return { kind: "resume-failed", step: "success", clearPersistedFlow: true };
1793
- }
1794
- if (transferStatus === "SENDING" || transferStatus === "SENT") {
1795
- return { kind: "resume-processing", step: "processing", clearPersistedFlow: true };
1796
- }
1797
- if (isSetup) {
1798
- return { kind: "resume-stale-setup", step: "wallet-picker", clearPersistedFlow: true };
1799
- }
1800
- return { kind: "resume-open-wallet", step: "open-wallet", clearPersistedFlow: false };
1801
- }
1802
-
1803
- // src/dataLoading.ts
1804
- function resolveDataLoadAction({
1805
- authenticated,
1806
- step,
1807
- accountsCount,
1808
- hasActiveCredential,
1809
- loading
1810
- }) {
1811
- if (!authenticated || step === "login" || step === "otp-verify" || accountsCount > 0 || !hasActiveCredential) {
1812
- return "reset";
1813
- }
1814
- if (loading) {
1815
- return "wait";
1816
- }
1817
- return "load";
1818
- }
1819
-
1820
1643
  // src/paymentHelpers.ts
1821
1644
  var ACTIVE_CREDENTIAL_STORAGE_KEY = "swype_active_credential_id";
1822
1645
  var MOBILE_FLOW_STORAGE_KEY = "swype_mobile_flow";
@@ -2232,6 +2055,46 @@ function paymentReducer(state, action) {
2232
2055
  return state;
2233
2056
  }
2234
2057
  }
2058
+
2059
+ // src/auth.ts
2060
+ var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2061
+ var PHONE_DIGIT_PATTERN = /^\d{7,15}$/;
2062
+ function normalizePhoneNumber(rawValue) {
2063
+ const trimmed = rawValue.trim();
2064
+ if (!trimmed) return null;
2065
+ const hasExplicitCountryCode = trimmed.startsWith("+");
2066
+ const digits = trimmed.replace(/\D/g, "");
2067
+ if (!PHONE_DIGIT_PATTERN.test(digits)) return null;
2068
+ return hasExplicitCountryCode ? `+${digits}` : digits;
2069
+ }
2070
+ function normalizeAuthIdentifier(rawValue) {
2071
+ const trimmed = rawValue.trim();
2072
+ if (!trimmed) return null;
2073
+ if (EMAIL_PATTERN.test(trimmed)) {
2074
+ return {
2075
+ kind: "email",
2076
+ value: trimmed.toLowerCase()
2077
+ };
2078
+ }
2079
+ const normalizedPhoneNumber = normalizePhoneNumber(trimmed);
2080
+ if (normalizedPhoneNumber) {
2081
+ return {
2082
+ kind: "phone",
2083
+ value: normalizedPhoneNumber
2084
+ };
2085
+ }
2086
+ return null;
2087
+ }
2088
+ function maskAuthIdentifier(identifier) {
2089
+ if (identifier.kind === "email") {
2090
+ const [localPart, domain = ""] = identifier.value.split("@");
2091
+ const localPrefix = localPart.slice(0, 2);
2092
+ return `${localPrefix}${"*".repeat(Math.max(localPart.length - 2, 0))}@${domain}`;
2093
+ }
2094
+ const digits = identifier.value.replace(/\D/g, "");
2095
+ const visibleSuffix = digits.slice(-4);
2096
+ return `***-***-${visibleSuffix}`;
2097
+ }
2235
2098
  var ACCENT = "#28b67a";
2236
2099
  var BG_RING = "#d2e4ea";
2237
2100
  function SwypeLoadingScreen() {
@@ -3857,7 +3720,7 @@ var dividerTextStyle = (color) => ({
3857
3720
  color,
3858
3721
  whiteSpace: "nowrap"
3859
3722
  });
3860
- var DEFAULT_MAX = 500;
3723
+ var DEFAULT_MAX = 1e7;
3861
3724
  var ABSOLUTE_MIN = 0.01;
3862
3725
  function SetupScreen({
3863
3726
  availableBalance,
@@ -3872,7 +3735,7 @@ function SetupScreen({
3872
3735
  error
3873
3736
  }) {
3874
3737
  const { tokens } = useSwypeConfig();
3875
- const effectiveMax = Math.min(DEFAULT_MAX, availableBalance);
3738
+ const effectiveMax = DEFAULT_MAX;
3876
3739
  const effectiveMin = Math.min(ABSOLUTE_MIN, effectiveMax);
3877
3740
  const [limit, setLimit] = useState(() => Math.min(availableBalance, effectiveMax));
3878
3741
  const [editing, setEditing] = useState(false);
@@ -4249,8 +4112,7 @@ function DepositScreen({
4249
4112
  onAuthorizeAccount,
4250
4113
  onAddProvider,
4251
4114
  onSelectToken,
4252
- pendingSetup,
4253
- onStartSetup
4115
+ selectedSourceLabel
4254
4116
  }) {
4255
4117
  const { tokens } = useSwypeConfig();
4256
4118
  const amount = initialAmount;
@@ -4258,29 +4120,6 @@ function DepositScreen({
4258
4120
  const exceedsLimit = amount > remainingLimit && !isLowBalance;
4259
4121
  const canDeposit = amount >= MIN_DEPOSIT && !exceedsLimit && !isLowBalance && !processing;
4260
4122
  const headerTitle = merchantName ? `Deposit to ${merchantName}` : "Deposit";
4261
- if (pendingSetup) {
4262
- return /* @__PURE__ */ jsxs(
4263
- ScreenLayout,
4264
- {
4265
- footer: /* @__PURE__ */ jsxs(Fragment, { children: [
4266
- /* @__PURE__ */ jsx(PrimaryButton, { onClick: onStartSetup, children: "Set up One-Tap" }),
4267
- /* @__PURE__ */ jsx("p", { style: setupHintStyle(tokens.textSecondary), children: "Choose your source and set your One-Tap limit to deposit instantly." }),
4268
- /* @__PURE__ */ jsx(PoweredByFooter, {})
4269
- ] }),
4270
- children: [
4271
- /* @__PURE__ */ jsx(ScreenHeader, { title: headerTitle, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
4272
- /* @__PURE__ */ jsxs("div", { style: setupContentStyle, children: [
4273
- /* @__PURE__ */ jsx("div", { style: amountDisplayStyle, children: /* @__PURE__ */ jsxs("span", { style: amountStyle(tokens), children: [
4274
- "$",
4275
- amount.toFixed(2)
4276
- ] }) }),
4277
- /* @__PURE__ */ jsx("p", { style: setupDescStyle(tokens.textSecondary), children: "Set up your payment source to deposit with One-Tap \u2014 no approvals needed after setup." })
4278
- ] }),
4279
- error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error })
4280
- ]
4281
- }
4282
- );
4283
- }
4284
4123
  if (isLowBalance) {
4285
4124
  return /* @__PURE__ */ jsxs(
4286
4125
  ScreenLayout,
@@ -4318,7 +4157,7 @@ function DepositScreen({
4318
4157
  /* @__PURE__ */ jsx("text", { x: "12", y: "16", textAnchor: "middle", fontSize: "12", fill: "#fff", fontWeight: "700", children: "$" })
4319
4158
  ] }) }),
4320
4159
  /* @__PURE__ */ jsxs("div", { children: [
4321
- /* @__PURE__ */ jsx("div", { style: balanceLabelStyle2(tokens.textMuted), children: "Available" }),
4160
+ /* @__PURE__ */ jsx("div", { style: balanceLabelStyle2(tokens.textMuted), children: selectedSourceLabel ?? "Available" }),
4322
4161
  /* @__PURE__ */ jsxs("div", { style: { ...balanceAmountStyle, color: tokens.warning }, children: [
4323
4162
  "$",
4324
4163
  availableBalance.toFixed(2)
@@ -4393,10 +4232,7 @@ function DepositScreen({
4393
4232
  /* @__PURE__ */ jsx("text", { x: "12", y: "16", textAnchor: "middle", fontSize: "12", fill: "#fff", fontWeight: "700", children: "$" })
4394
4233
  ] }) }),
4395
4234
  /* @__PURE__ */ jsxs("div", { children: [
4396
- /* @__PURE__ */ jsxs("div", { style: balanceLabelStyle2(tokens.textMuted), children: [
4397
- "Paying from ",
4398
- sourceName
4399
- ] }),
4235
+ /* @__PURE__ */ jsx("div", { style: balanceLabelStyle2(tokens.textMuted), children: selectedSourceLabel ?? `Paying from ${sourceName}` }),
4400
4236
  /* @__PURE__ */ jsxs("div", { style: balanceAmountStyle, children: [
4401
4237
  "$",
4402
4238
  availableBalance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
@@ -4543,29 +4379,6 @@ var switchHintStyle = (color) => ({
4543
4379
  var outlineBtnWrapStyle = {
4544
4380
  marginBottom: 8
4545
4381
  };
4546
- var setupContentStyle = {
4547
- flex: 1,
4548
- display: "flex",
4549
- flexDirection: "column",
4550
- alignItems: "center",
4551
- justifyContent: "center",
4552
- textAlign: "center",
4553
- padding: "0 24px"
4554
- };
4555
- var setupDescStyle = (color) => ({
4556
- fontSize: "0.88rem",
4557
- color,
4558
- margin: "8px 0 0",
4559
- lineHeight: 1.6,
4560
- maxWidth: 300
4561
- });
4562
- var setupHintStyle = (color) => ({
4563
- textAlign: "center",
4564
- fontSize: "0.78rem",
4565
- color,
4566
- margin: "12px 0 2px",
4567
- lineHeight: 1.5
4568
- });
4569
4382
  function SuccessScreen({
4570
4383
  amount,
4571
4384
  currency,
@@ -5215,6 +5028,28 @@ var waitHintStyle2 = (color) => ({
5215
5028
  color,
5216
5029
  margin: 0
5217
5030
  });
5031
+
5032
+ // src/deeplink.ts
5033
+ var IFRAME_CLEANUP_DELAY_MS = 3e3;
5034
+ var LOCATION_FALLBACK_DELAY_MS = 100;
5035
+ function triggerDeeplink(uri) {
5036
+ try {
5037
+ const iframe = document.createElement("iframe");
5038
+ iframe.style.display = "none";
5039
+ iframe.src = uri;
5040
+ document.body.appendChild(iframe);
5041
+ setTimeout(() => {
5042
+ try {
5043
+ document.body.removeChild(iframe);
5044
+ } catch {
5045
+ }
5046
+ }, IFRAME_CLEANUP_DELAY_MS);
5047
+ } catch {
5048
+ }
5049
+ setTimeout(() => {
5050
+ window.location.href = uri;
5051
+ }, LOCATION_FALLBACK_DELAY_MS);
5052
+ }
5218
5053
  function OpenWalletScreen({
5219
5054
  walletName,
5220
5055
  deeplinkUri,
@@ -5660,12 +5495,12 @@ function StepRenderer({
5660
5495
  selectedSource,
5661
5496
  selectSourceChoices,
5662
5497
  selectSourceRecommended,
5498
+ selectSourceAvailableBalance,
5663
5499
  authInput,
5664
5500
  otpCode,
5665
5501
  selectSourceChainName,
5666
5502
  selectSourceTokenSymbol,
5667
5503
  savingOneTapLimit,
5668
- pendingSetup,
5669
5504
  merchantName,
5670
5505
  onBack,
5671
5506
  onDismiss,
@@ -5782,19 +5617,23 @@ function StepRenderer({
5782
5617
  );
5783
5618
  }
5784
5619
  if (step === "setup") {
5785
- const hasPendingSelectSource = selectSourceChoices.length > 0;
5786
- const setupSourceLabel = hasPendingSelectSource && selectSourceChainName && selectSourceTokenSymbol ? `${selectSourceTokenSymbol} on ${selectSourceChainName}` : selectedSourceLabel;
5620
+ const selectSourceTokenCount = selectSourceChoices.reduce(
5621
+ (sum, chain) => sum + chain.tokens.length,
5622
+ 0
5623
+ );
5624
+ const effectiveTokenCount = tokenCount > 0 ? tokenCount : selectSourceTokenCount;
5625
+ const effectiveSourceLabel = selectedSourceLabel ?? (selectSourceChainName && selectSourceTokenSymbol ? `${selectSourceTokenSymbol} on ${selectSourceChainName}` : void 0);
5787
5626
  return /* @__PURE__ */ jsx(
5788
5627
  SetupScreen,
5789
5628
  {
5790
- availableBalance: selectedSource ? selectedSource.balance.available.amount : selectedAccount ? selectedAccount.wallets.reduce((sum, w) => sum + w.balance.available.amount, 0) : maxSourceBalance,
5791
- tokenCount,
5629
+ availableBalance: selectedSource ? selectedSource.balance.available.amount : selectedAccount ? selectedAccount.wallets.reduce((sum, w) => sum + w.balance.available.amount, 0) : selectSourceAvailableBalance > 0 ? selectSourceAvailableBalance : maxSourceBalance,
5630
+ tokenCount: effectiveTokenCount,
5792
5631
  sourceName,
5793
5632
  onSetupOneTap: handlers.onSetupOneTap,
5794
5633
  onBack: () => handlers.onNavigate("deposit"),
5795
5634
  onLogout: handlers.onLogout,
5796
- onAdvanced: hasPendingSelectSource ? () => handlers.onNavigate("select-source") : handlers.onSelectToken,
5797
- selectedSourceLabel: setupSourceLabel,
5635
+ onAdvanced: handlers.onSelectToken,
5636
+ selectedSourceLabel: effectiveSourceLabel,
5798
5637
  loading: savingOneTapLimit,
5799
5638
  error: state.error
5800
5639
  }
@@ -5843,8 +5682,7 @@ function StepRenderer({
5843
5682
  onAuthorizeAccount: handlers.onContinueConnection,
5844
5683
  onAddProvider: () => handlers.onNavigate("wallet-picker"),
5845
5684
  onSelectToken: handlers.onSelectToken,
5846
- pendingSetup,
5847
- onStartSetup: () => handlers.onNavigate("setup")
5685
+ selectedSourceLabel
5848
5686
  }
5849
5687
  );
5850
5688
  }
@@ -5876,7 +5714,7 @@ function StepRenderer({
5876
5714
  );
5877
5715
  }
5878
5716
  if (step === "select-source") {
5879
- const enteredFromSetup = state.previousStep === "setup";
5717
+ const cameFromSetup = state.previousStep === "setup";
5880
5718
  return /* @__PURE__ */ jsx(
5881
5719
  SelectSourceScreen,
5882
5720
  {
@@ -5886,8 +5724,8 @@ function StepRenderer({
5886
5724
  recommended: selectSourceRecommended,
5887
5725
  onChainChange: handlers.onSelectSourceChainChange,
5888
5726
  onTokenChange: handlers.onSetSelectSourceTokenSymbol,
5889
- onConfirm: enteredFromSetup ? () => handlers.onNavigate("setup") : handlers.onConfirmSelectSource,
5890
- onBack: enteredFromSetup ? () => handlers.onNavigate("setup") : void 0,
5727
+ onConfirm: cameFromSetup ? () => handlers.onNavigate("setup") : handlers.onConfirmSelectSource,
5728
+ onBack: cameFromSetup ? () => handlers.onNavigate("setup") : void 0,
5891
5729
  onLogout: handlers.onLogout
5892
5730
  }
5893
5731
  );
@@ -5937,21 +5775,38 @@ function StepRenderer({
5937
5775
  selectedAccountId: state.selectedAccountId,
5938
5776
  onSelectAccount: handlers.onSelectAccount,
5939
5777
  onAuthorizeAccount: handlers.onContinueConnection,
5940
- onAddProvider: () => handlers.onNavigate("wallet-picker")
5778
+ onAddProvider: () => handlers.onNavigate("wallet-picker"),
5779
+ selectedSourceLabel
5941
5780
  }
5942
5781
  );
5943
5782
  }
5944
5783
  return null;
5945
5784
  }
5946
- var PaymentErrorBoundary = class extends Component {
5947
- constructor(props) {
5948
- super(props);
5949
- this.state = { hasError: false };
5950
- }
5951
- static getDerivedStateFromError() {
5952
- return { hasError: true };
5953
- }
5954
- componentDidCatch(error, _info) {
5785
+
5786
+ // src/sentry.ts
5787
+ var _mod;
5788
+ function captureException(error) {
5789
+ if (_mod === null) return;
5790
+ if (_mod) {
5791
+ _mod.captureException(error);
5792
+ return;
5793
+ }
5794
+ import('@sentry/react').then((m) => {
5795
+ _mod = m;
5796
+ m.captureException(error);
5797
+ }).catch(() => {
5798
+ _mod = null;
5799
+ });
5800
+ }
5801
+ var PaymentErrorBoundary = class extends Component {
5802
+ constructor(props) {
5803
+ super(props);
5804
+ this.state = { hasError: false };
5805
+ }
5806
+ static getDerivedStateFromError() {
5807
+ return { hasError: true };
5808
+ }
5809
+ componentDidCatch(error, _info) {
5955
5810
  captureException(error);
5956
5811
  }
5957
5812
  handleReset = () => {
@@ -6011,78 +5866,7 @@ var buttonStyle3 = {
6011
5866
  fontFamily: "inherit",
6012
5867
  cursor: "pointer"
6013
5868
  };
6014
- function SwypePayment(props) {
6015
- const resetKey = useRef(0);
6016
- const handleBoundaryReset = useCallback(() => {
6017
- resetKey.current += 1;
6018
- }, []);
6019
- return /* @__PURE__ */ jsx(PaymentErrorBoundary, { onReset: handleBoundaryReset, children: /* @__PURE__ */ jsx(SwypePaymentInner, { ...props }) }, resetKey.current);
6020
- }
6021
- function SwypePaymentInner({
6022
- destination,
6023
- onComplete,
6024
- onError,
6025
- useWalletConnector: useWalletConnectorProp,
6026
- idempotencyKey,
6027
- merchantAuthorization,
6028
- merchantName,
6029
- onBack,
6030
- onDismiss,
6031
- autoCloseSeconds
6032
- }) {
6033
- const { apiBaseUrl, depositAmount } = useSwypeConfig();
6034
- const { ready, authenticated, user, logout, getAccessToken } = usePrivy();
6035
- const {
6036
- sendCode: sendEmailCode,
6037
- loginWithCode: loginWithEmailCode,
6038
- state: emailLoginState
6039
- } = useLoginWithEmail();
6040
- const {
6041
- sendCode: sendSmsCode,
6042
- loginWithCode: loginWithSmsCode,
6043
- state: smsLoginState
6044
- } = useLoginWithSms();
6045
- useLoginWithOAuth();
6046
- const [state, dispatch] = useReducer(
6047
- paymentReducer,
6048
- {
6049
- depositAmount,
6050
- passkeyPopupNeeded: isSafari() && isInCrossOriginIframe(),
6051
- activeCredentialId: typeof window === "undefined" ? null : window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY)
6052
- },
6053
- createInitialState
6054
- );
6055
- const loadingDataRef = useRef(false);
6056
- const pollingTransferIdRef = useRef(null);
6057
- const setupAccountIdRef = useRef(null);
6058
- const mobileSetupFlowRef = useRef(false);
6059
- const handlingMobileReturnRef = useRef(false);
6060
- const processingStartedAtRef = useRef(null);
6061
- const initializedSelectSourceActionRef = useRef(null);
6062
- const preSelectSourceStepRef = useRef(null);
6063
- const pendingTokenAuthRef = useRef(null);
6064
- const pendingTokenSelectionRef = useRef(null);
6065
- const pendingTokenAuthSessionRef = useRef(null);
6066
- const reauthSessionIdRef = useRef(null);
6067
- const reauthTokenRef = useRef(null);
6068
- const checkingPasskeyRef = useRef(false);
6069
- const onCompleteRef = useRef(onComplete);
6070
- onCompleteRef.current = onComplete;
6071
- const pollingRef = useRef(null);
6072
- const getAccessTokenRef = useRef(getAccessToken);
6073
- getAccessTokenRef.current = getAccessToken;
6074
- const handleAuthorizedMobileReturnRef = useRef(
6075
- null
6076
- );
6077
- const [authInput, setAuthInput] = useState("");
6078
- const [otpCode, setOtpCode] = useState("");
6079
- const [selectSourceChainName, setSelectSourceChainName] = useState("");
6080
- const [selectSourceTokenSymbol, setSelectSourceTokenSymbol] = useState("");
6081
- const [savingOneTapLimit, setSavingOneTapLimit] = useState(false);
6082
- const authExecutor = useAuthorizationExecutor();
6083
- const polling = useTransferPolling();
6084
- pollingRef.current = polling;
6085
- const transferSigning = useTransferSigning();
5869
+ function useDerivedState(state) {
6086
5870
  const { sourceType, sourceId } = deriveSourceTypeAndId(state);
6087
5871
  const selectedAccount = state.accounts.find((a) => a.id === state.selectedAccountId);
6088
5872
  const selectedWallet = selectedAccount?.wallets.find(
@@ -6132,8 +5916,36 @@ function SwypePaymentInner({
6132
5916
  }
6133
5917
  return count;
6134
5918
  }, [state.accounts]);
6135
- const activeOtpStatus = state.verificationTarget?.kind === "email" ? emailLoginState.status : state.verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
6136
- const activeOtpErrorMessage = state.verificationTarget?.kind === "email" && emailLoginState.status === "error" ? emailLoginState.error?.message ?? "Failed to continue with email." : state.verificationTarget?.kind === "phone" && smsLoginState.status === "error" ? smsLoginState.error?.message ?? "Failed to continue with phone number." : null;
5919
+ return {
5920
+ sourceType,
5921
+ sourceId,
5922
+ selectedAccount,
5923
+ selectedWallet,
5924
+ selectedSource,
5925
+ sourceName,
5926
+ sourceAddress,
5927
+ sourceVerified,
5928
+ pendingConnections,
5929
+ depositEligibleAccounts,
5930
+ maxSourceBalance,
5931
+ tokenCount
5932
+ };
5933
+ }
5934
+ function useAuthHandlers(dispatch, verificationTarget) {
5935
+ const {
5936
+ sendCode: sendEmailCode,
5937
+ loginWithCode: loginWithEmailCode,
5938
+ state: emailLoginState
5939
+ } = useLoginWithEmail();
5940
+ const {
5941
+ sendCode: sendSmsCode,
5942
+ loginWithCode: loginWithSmsCode,
5943
+ state: smsLoginState
5944
+ } = useLoginWithSms();
5945
+ const [authInput, setAuthInput] = useState("");
5946
+ const [otpCode, setOtpCode] = useState("");
5947
+ const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
5948
+ const activeOtpErrorMessage = verificationTarget?.kind === "email" && emailLoginState.status === "error" ? emailLoginState.error?.message ?? "Failed to continue with email." : verificationTarget?.kind === "phone" && smsLoginState.status === "error" ? smsLoginState.error?.message ?? "Failed to continue with phone number." : null;
6137
5949
  const handleSendLoginCode = useCallback(async () => {
6138
5950
  const normalizedIdentifier = normalizeAuthIdentifier(authInput);
6139
5951
  if (!normalizedIdentifier) {
@@ -6155,9 +5967,9 @@ function SwypePaymentInner({
6155
5967
  error: err instanceof Error ? err.message : "Failed to send verification code"
6156
5968
  });
6157
5969
  }
6158
- }, [authInput, sendEmailCode, sendSmsCode]);
5970
+ }, [authInput, sendEmailCode, sendSmsCode, dispatch]);
6159
5971
  const handleVerifyLoginCode = useCallback(async () => {
6160
- if (!state.verificationTarget) return;
5972
+ if (!verificationTarget) return;
6161
5973
  const trimmedCode = otpCode.trim();
6162
5974
  if (!/^\d{6}$/.test(trimmedCode)) {
6163
5975
  dispatch({ type: "SET_ERROR", error: "Enter the 6-digit verification code." });
@@ -6165,7 +5977,7 @@ function SwypePaymentInner({
6165
5977
  }
6166
5978
  dispatch({ type: "SET_ERROR", error: null });
6167
5979
  try {
6168
- if (state.verificationTarget.kind === "email") {
5980
+ if (verificationTarget.kind === "email") {
6169
5981
  await loginWithEmailCode({ code: trimmedCode });
6170
5982
  } else {
6171
5983
  await loginWithSmsCode({ code: trimmedCode });
@@ -6177,15 +5989,15 @@ function SwypePaymentInner({
6177
5989
  error: err instanceof Error ? err.message : "Failed to verify code"
6178
5990
  });
6179
5991
  }
6180
- }, [state.verificationTarget, otpCode, loginWithEmailCode, loginWithSmsCode]);
5992
+ }, [verificationTarget, otpCode, loginWithEmailCode, loginWithSmsCode, dispatch]);
6181
5993
  const handleResendLoginCode = useCallback(async () => {
6182
- if (!state.verificationTarget) return;
5994
+ if (!verificationTarget) return;
6183
5995
  dispatch({ type: "SET_ERROR", error: null });
6184
5996
  try {
6185
- if (state.verificationTarget.kind === "email") {
6186
- await sendEmailCode({ email: state.verificationTarget.value });
5997
+ if (verificationTarget.kind === "email") {
5998
+ await sendEmailCode({ email: verificationTarget.value });
6187
5999
  } else {
6188
- await sendSmsCode({ phoneNumber: state.verificationTarget.value });
6000
+ await sendSmsCode({ phoneNumber: verificationTarget.value });
6189
6001
  }
6190
6002
  } catch (err) {
6191
6003
  captureException(err);
@@ -6194,7 +6006,68 @@ function SwypePaymentInner({
6194
6006
  error: err instanceof Error ? err.message : "Failed to resend code"
6195
6007
  });
6196
6008
  }
6197
- }, [state.verificationTarget, sendEmailCode, sendSmsCode]);
6009
+ }, [verificationTarget, sendEmailCode, sendSmsCode, dispatch]);
6010
+ return {
6011
+ authInput,
6012
+ otpCode,
6013
+ activeOtpStatus,
6014
+ activeOtpErrorMessage,
6015
+ setAuthInput,
6016
+ setOtpCode,
6017
+ handleSendLoginCode,
6018
+ handleVerifyLoginCode,
6019
+ handleResendLoginCode
6020
+ };
6021
+ }
6022
+
6023
+ // src/mobileFlow.ts
6024
+ function hasActiveWallet(accounts) {
6025
+ return accounts.some((account) => account.wallets.some((wallet) => wallet.status === "ACTIVE"));
6026
+ }
6027
+ function resolvePostAuthStep(state) {
6028
+ if (!state.hasPasskey) {
6029
+ return { step: "create-passkey", clearPersistedFlow: false };
6030
+ }
6031
+ if (state.persistedMobileFlow) {
6032
+ if (state.persistedMobileFlow.isReauthorization) {
6033
+ return { step: "open-wallet", clearPersistedFlow: false };
6034
+ }
6035
+ if (state.persistedMobileFlow.isSetup && hasActiveWallet(state.accounts)) {
6036
+ return { step: "deposit", clearPersistedFlow: true };
6037
+ }
6038
+ return { step: "open-wallet", clearPersistedFlow: false };
6039
+ }
6040
+ if (state.mobileSetupInProgress && !hasActiveWallet(state.accounts)) {
6041
+ return { step: "open-wallet", clearPersistedFlow: false };
6042
+ }
6043
+ if ((state.accounts.length === 0 || !hasActiveWallet(state.accounts)) && !state.connectingNewAccount) {
6044
+ return { step: "wallet-picker", clearPersistedFlow: false };
6045
+ }
6046
+ return { step: "deposit", clearPersistedFlow: false };
6047
+ }
6048
+ function resolveRestoredMobileFlow(transferStatus, isSetup) {
6049
+ if (transferStatus === "AUTHORIZED") {
6050
+ return isSetup ? { kind: "resume-setup-deposit", step: "deposit", clearPersistedFlow: true } : { kind: "resume-confirm-sign", step: "confirm-sign", clearPersistedFlow: true };
6051
+ }
6052
+ if (transferStatus === "COMPLETED") {
6053
+ return { kind: "resume-success", step: "success", clearPersistedFlow: true };
6054
+ }
6055
+ if (transferStatus === "FAILED") {
6056
+ return { kind: "resume-failed", step: "success", clearPersistedFlow: true };
6057
+ }
6058
+ if (transferStatus === "SENDING" || transferStatus === "SENT") {
6059
+ return { kind: "resume-processing", step: "processing", clearPersistedFlow: true };
6060
+ }
6061
+ if (isSetup) {
6062
+ return { kind: "resume-stale-setup", step: "wallet-picker", clearPersistedFlow: true };
6063
+ }
6064
+ return { kind: "resume-open-wallet", step: "open-wallet", clearPersistedFlow: false };
6065
+ }
6066
+
6067
+ // src/hooks/usePasskeyHandlers.ts
6068
+ function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds, mobileSetupFlowRef) {
6069
+ const { user, getAccessToken } = usePrivy();
6070
+ const checkingPasskeyRef = useRef(false);
6198
6071
  const completePasskeyRegistration = useCallback(async (credentialId, publicKey) => {
6199
6072
  const token = await getAccessToken();
6200
6073
  if (!token) throw new Error("Not authenticated");
@@ -6203,14 +6076,14 @@ function SwypePaymentInner({
6203
6076
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
6204
6077
  const resolved = resolvePostAuthStep({
6205
6078
  hasPasskey: true,
6206
- accounts: state.accounts,
6079
+ accounts,
6207
6080
  persistedMobileFlow: loadMobileFlowState(),
6208
6081
  mobileSetupInProgress: mobileSetupFlowRef.current,
6209
6082
  connectingNewAccount: false
6210
6083
  });
6211
6084
  if (resolved.clearPersistedFlow) clearMobileFlowState();
6212
6085
  dispatch({ type: "NAVIGATE", step: resolved.step });
6213
- }, [getAccessToken, apiBaseUrl, state.accounts]);
6086
+ }, [getAccessToken, apiBaseUrl, accounts, mobileSetupFlowRef, dispatch]);
6214
6087
  const handleRegisterPasskey = useCallback(async () => {
6215
6088
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
6216
6089
  dispatch({ type: "SET_ERROR", error: null });
@@ -6234,7 +6107,7 @@ function SwypePaymentInner({
6234
6107
  } finally {
6235
6108
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
6236
6109
  }
6237
- }, [user, completePasskeyRegistration]);
6110
+ }, [user, completePasskeyRegistration, dispatch]);
6238
6111
  const handleCreatePasskeyViaPopup = useCallback(async () => {
6239
6112
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
6240
6113
  dispatch({ type: "SET_ERROR", error: null });
@@ -6252,7 +6125,7 @@ function SwypePaymentInner({
6252
6125
  localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
6253
6126
  const resolved = resolvePostAuthStep({
6254
6127
  hasPasskey: true,
6255
- accounts: state.accounts,
6128
+ accounts,
6256
6129
  persistedMobileFlow: loadMobileFlowState(),
6257
6130
  mobileSetupInProgress: mobileSetupFlowRef.current,
6258
6131
  connectingNewAccount: false
@@ -6268,14 +6141,14 @@ function SwypePaymentInner({
6268
6141
  } finally {
6269
6142
  dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
6270
6143
  }
6271
- }, [user, getAccessToken, apiBaseUrl, state.accounts]);
6144
+ }, [user, getAccessToken, apiBaseUrl, accounts, mobileSetupFlowRef, dispatch]);
6272
6145
  const handleVerifyPasskeyViaPopup = useCallback(async () => {
6273
6146
  dispatch({ type: "SET_VERIFYING_PASSKEY", value: true });
6274
6147
  dispatch({ type: "SET_ERROR", error: null });
6275
6148
  try {
6276
6149
  const token = await getAccessToken();
6277
6150
  const matched = await findDevicePasskeyViaPopup({
6278
- credentialIds: state.knownCredentialIds,
6151
+ credentialIds: knownCredentialIds,
6279
6152
  rpId: resolvePasskeyRpId(),
6280
6153
  authToken: token ?? void 0,
6281
6154
  apiBaseUrl
@@ -6289,7 +6162,7 @@ function SwypePaymentInner({
6289
6162
  }
6290
6163
  const resolved = resolvePostAuthStep({
6291
6164
  hasPasskey: true,
6292
- accounts: state.accounts,
6165
+ accounts,
6293
6166
  persistedMobileFlow: loadMobileFlowState(),
6294
6167
  mobileSetupInProgress: mobileSetupFlowRef.current,
6295
6168
  connectingNewAccount: false
@@ -6311,44 +6184,48 @@ function SwypePaymentInner({
6311
6184
  } finally {
6312
6185
  dispatch({ type: "SET_VERIFYING_PASSKEY", value: false });
6313
6186
  }
6314
- }, [state.knownCredentialIds, getAccessToken, apiBaseUrl, state.accounts]);
6187
+ }, [knownCredentialIds, getAccessToken, apiBaseUrl, accounts, mobileSetupFlowRef, dispatch]);
6188
+ return {
6189
+ handleRegisterPasskey,
6190
+ handleCreatePasskeyViaPopup,
6191
+ handleVerifyPasskeyViaPopup,
6192
+ checkingPasskeyRef
6193
+ };
6194
+ }
6195
+ function useTransferHandlers(deps) {
6196
+ const {
6197
+ dispatch,
6198
+ getAccessToken,
6199
+ apiBaseUrl,
6200
+ depositAmount,
6201
+ destination,
6202
+ idempotencyKey,
6203
+ merchantAuthorization,
6204
+ onComplete,
6205
+ onError,
6206
+ polling,
6207
+ transferSigning,
6208
+ sourceType,
6209
+ sourceId,
6210
+ sourceTokenAddress,
6211
+ activeCredentialId,
6212
+ selectedAccountId,
6213
+ transfer,
6214
+ accounts
6215
+ } = deps;
6216
+ const processingStartedAtRef = useRef(null);
6217
+ const pollingTransferIdRef = useRef(null);
6315
6218
  const reloadAccounts = useCallback(async () => {
6316
6219
  const token = await getAccessToken();
6317
- if (!token || !state.activeCredentialId) return;
6220
+ if (!token || !activeCredentialId) return;
6318
6221
  const [accts, prov] = await Promise.all([
6319
- fetchAccounts(apiBaseUrl, token, state.activeCredentialId),
6222
+ fetchAccounts(apiBaseUrl, token, activeCredentialId),
6320
6223
  fetchProviders(apiBaseUrl, token)
6321
6224
  ]);
6322
6225
  const parsedAmt = depositAmount != null ? depositAmount : 0;
6323
- const defaults = resolveDepositSelection(accts, parsedAmt, state.selectedAccountId);
6226
+ const defaults = resolveDepositSelection(accts, parsedAmt, selectedAccountId);
6324
6227
  dispatch({ type: "ACCOUNTS_RELOADED", accounts: accts, providers: prov, defaults });
6325
- }, [getAccessToken, state.activeCredentialId, state.selectedAccountId, apiBaseUrl, depositAmount]);
6326
- const handleAuthorizedMobileReturn = useCallback(async (authorizedTransfer, isSetup) => {
6327
- if (handlingMobileReturnRef.current) return;
6328
- handlingMobileReturnRef.current = true;
6329
- polling.stopPolling();
6330
- if (isSetup) {
6331
- mobileSetupFlowRef.current = false;
6332
- clearMobileFlowState();
6333
- try {
6334
- await reloadAccounts();
6335
- loadingDataRef.current = false;
6336
- dispatch({ type: "MOBILE_SETUP_COMPLETE", transfer: authorizedTransfer });
6337
- } catch (err) {
6338
- handlingMobileReturnRef.current = false;
6339
- dispatch({
6340
- type: "SET_ERROR",
6341
- error: err instanceof Error ? err.message : "Wallet authorized, but we could not refresh your account yet."
6342
- });
6343
- dispatch({ type: "NAVIGATE", step: "open-wallet" });
6344
- }
6345
- return;
6346
- }
6347
- mobileSetupFlowRef.current = false;
6348
- clearMobileFlowState();
6349
- dispatch({ type: "MOBILE_SIGN_READY", transfer: authorizedTransfer });
6350
- }, [polling.stopPolling, reloadAccounts]);
6351
- handleAuthorizedMobileReturnRef.current = handleAuthorizedMobileReturn;
6228
+ }, [getAccessToken, activeCredentialId, selectedAccountId, apiBaseUrl, depositAmount, dispatch]);
6352
6229
  const handlePay = useCallback(async (payAmount, sourceOverrides) => {
6353
6230
  if (isNaN(payAmount) || payAmount < MIN_SEND_AMOUNT_USD) {
6354
6231
  dispatch({ type: "SET_ERROR", error: `Minimum amount is $${MIN_SEND_AMOUNT_USD.toFixed(2)}.` });
@@ -6358,7 +6235,7 @@ function SwypePaymentInner({
6358
6235
  dispatch({ type: "SET_ERROR", error: "No account or provider selected." });
6359
6236
  return;
6360
6237
  }
6361
- if (!state.activeCredentialId) {
6238
+ if (!activeCredentialId) {
6362
6239
  dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
6363
6240
  dispatch({ type: "NAVIGATE", step: "create-passkey" });
6364
6241
  return;
@@ -6366,10 +6243,10 @@ function SwypePaymentInner({
6366
6243
  dispatch({ type: "PAY_STARTED", isSetupRedirect: false });
6367
6244
  processingStartedAtRef.current = Date.now();
6368
6245
  try {
6369
- if (state.transfer?.status === "AUTHORIZED") {
6370
- const signedTransfer2 = await transferSigning.signTransfer(state.transfer.id);
6246
+ if (transfer?.status === "AUTHORIZED") {
6247
+ const signedTransfer2 = await transferSigning.signTransfer(transfer.id);
6371
6248
  dispatch({ type: "TRANSFER_SIGNED", transfer: signedTransfer2 });
6372
- polling.startPolling(state.transfer.id);
6249
+ polling.startPolling(transfer.id);
6373
6250
  return;
6374
6251
  }
6375
6252
  const token = await getAccessToken();
@@ -6377,7 +6254,7 @@ function SwypePaymentInner({
6377
6254
  let effectiveSourceType = sourceOverrides?.sourceType ?? sourceType;
6378
6255
  let effectiveSourceId = sourceOverrides?.sourceId ?? sourceId;
6379
6256
  if (effectiveSourceType === "accountId") {
6380
- const acct = state.accounts.find((a) => a.id === effectiveSourceId);
6257
+ const acct = accounts.find((a) => a.id === effectiveSourceId);
6381
6258
  const preferredWallet = acct ? getPreferredDepositWallet(acct, payAmount) : null;
6382
6259
  if (preferredWallet?.status === "ACTIVE") {
6383
6260
  effectiveSourceType = "walletId";
@@ -6386,10 +6263,11 @@ function SwypePaymentInner({
6386
6263
  }
6387
6264
  const t = await createTransfer(apiBaseUrl, token, {
6388
6265
  id: idempotencyKey,
6389
- credentialId: state.activeCredentialId,
6266
+ credentialId: activeCredentialId,
6390
6267
  merchantAuthorization,
6391
6268
  sourceType: effectiveSourceType,
6392
6269
  sourceId: effectiveSourceId,
6270
+ sourceTokenAddress,
6393
6271
  destination,
6394
6272
  amount: payAmount
6395
6273
  });
@@ -6409,11 +6287,7 @@ function SwypePaymentInner({
6409
6287
  } catch (err) {
6410
6288
  captureException(err);
6411
6289
  const msg = err instanceof Error ? err.message : "Transfer failed";
6412
- dispatch({
6413
- type: "PAY_ERROR",
6414
- error: msg,
6415
- fallbackStep: "deposit"
6416
- });
6290
+ dispatch({ type: "PAY_ERROR", error: msg, fallbackStep: "deposit" });
6417
6291
  onError?.(msg);
6418
6292
  } finally {
6419
6293
  dispatch({ type: "PAY_ENDED" });
@@ -6421,9 +6295,10 @@ function SwypePaymentInner({
6421
6295
  }, [
6422
6296
  sourceId,
6423
6297
  sourceType,
6424
- state.activeCredentialId,
6425
- state.transfer,
6426
- state.accounts,
6298
+ sourceTokenAddress,
6299
+ activeCredentialId,
6300
+ transfer,
6301
+ accounts,
6427
6302
  destination,
6428
6303
  apiBaseUrl,
6429
6304
  getAccessToken,
@@ -6432,185 +6307,133 @@ function SwypePaymentInner({
6432
6307
  onError,
6433
6308
  onComplete,
6434
6309
  idempotencyKey,
6435
- merchantAuthorization
6310
+ merchantAuthorization,
6311
+ dispatch
6436
6312
  ]);
6437
- const handleIncreaseLimit = useCallback(async () => {
6438
- if (!state.selectedAccountId) {
6439
- dispatch({ type: "SET_ERROR", error: "No account selected." });
6440
- return;
6441
- }
6442
- if (!state.activeCredentialId) {
6443
- dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
6444
- dispatch({ type: "NAVIGATE", step: "create-passkey" });
6445
- return;
6446
- }
6447
- const acct = state.accounts.find((a) => a.id === state.selectedAccountId);
6448
- const matchedProvider = acct ? state.providers.find((p) => p.name === acct.name) : void 0;
6449
- if (matchedProvider) {
6450
- dispatch({ type: "SELECT_PROVIDER", providerId: matchedProvider.id });
6451
- }
6452
- dispatch({ type: "SET_ERROR", error: null });
6453
- dispatch({ type: "SET_INCREASING_LIMIT", value: true });
6313
+ const handleConfirmSign = useCallback(async () => {
6314
+ const t = transfer ?? polling.transfer;
6315
+ if (!t) return;
6454
6316
  try {
6455
- const token = await getAccessToken();
6456
- if (!token) throw new Error("Not authenticated");
6457
- const session = await createAccountAuthorizationSession(
6458
- apiBaseUrl,
6459
- token,
6460
- state.selectedAccountId,
6461
- state.activeCredentialId
6462
- );
6463
- const isMobile = !shouldUseWalletConnector({
6464
- useWalletConnector: useWalletConnectorProp,
6465
- userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
6466
- });
6467
- if (isMobile) {
6468
- handlingMobileReturnRef.current = false;
6469
- mobileSetupFlowRef.current = true;
6470
- setupAccountIdRef.current = state.selectedAccountId;
6471
- reauthSessionIdRef.current = session.id;
6472
- reauthTokenRef.current = null;
6473
- persistMobileFlowState({
6474
- accountId: state.selectedAccountId,
6475
- sessionId: session.id,
6476
- deeplinkUri: session.uri,
6477
- providerId: matchedProvider?.id ?? null,
6478
- isSetup: true,
6479
- isReauthorization: true
6480
- });
6481
- dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: session.uri });
6482
- triggerDeeplink(session.uri);
6483
- } else {
6484
- await authExecutor.executeSessionById(session.id);
6485
- await reloadAccounts();
6486
- dispatch({ type: "NAVIGATE", step: "deposit" });
6487
- }
6317
+ const signedTransfer = await transferSigning.signTransfer(t.id);
6318
+ clearMobileFlowState();
6319
+ dispatch({ type: "CONFIRM_SIGN_SUCCESS", transfer: signedTransfer });
6320
+ polling.startPolling(t.id);
6488
6321
  } catch (err) {
6489
6322
  captureException(err);
6490
- const msg = err instanceof Error ? err.message : "Failed to increase limit";
6323
+ const msg = err instanceof Error ? err.message : "Failed to sign transfer";
6491
6324
  dispatch({ type: "SET_ERROR", error: msg });
6492
6325
  onError?.(msg);
6493
- } finally {
6494
- dispatch({ type: "SET_INCREASING_LIMIT", value: false });
6495
6326
  }
6496
- }, [
6497
- state.selectedAccountId,
6498
- state.activeCredentialId,
6499
- state.accounts,
6500
- state.providers,
6501
- apiBaseUrl,
6502
- getAccessToken,
6503
- authExecutor,
6504
- useWalletConnectorProp,
6327
+ }, [transfer, polling.transfer, polling.startPolling, transferSigning, onError, dispatch]);
6328
+ return {
6505
6329
  reloadAccounts,
6506
- onError
6507
- ]);
6508
- const handleNavigateToTokenPicker = useCallback(() => {
6509
- dispatch({ type: "NAVIGATE", step: "token-picker" });
6510
- }, []);
6511
- const handleSelectAuthorizedToken = useCallback((walletId, tokenSymbol) => {
6512
- dispatch({ type: "SELECT_TOKEN", walletId, tokenSymbol });
6513
- }, []);
6514
- const handleAuthorizeToken = useCallback(async (_walletId, tokenAddress, chainId, tokenSymbol) => {
6515
- if (!state.selectedAccountId) {
6516
- dispatch({ type: "SET_ERROR", error: "No account selected." });
6517
- return;
6518
- }
6519
- if (!state.activeCredentialId) {
6520
- dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
6521
- dispatch({ type: "NAVIGATE", step: "create-passkey" });
6522
- return;
6330
+ handlePay,
6331
+ handleConfirmSign,
6332
+ processingStartedAtRef,
6333
+ pollingTransferIdRef
6334
+ };
6335
+ }
6336
+ function useSourceSelectionHandlers(dispatch, authExecutor) {
6337
+ const [selectSourceChainName, setSelectSourceChainName] = useState("");
6338
+ const [selectSourceTokenSymbol, setSelectSourceTokenSymbol] = useState("");
6339
+ const initializedSelectSourceActionRef = useRef(null);
6340
+ const preSelectSourceStepRef = useRef(null);
6341
+ const pendingSelectSourceAction = authExecutor.pendingSelectSource;
6342
+ const selectSourceChoices = useMemo(() => {
6343
+ if (!pendingSelectSourceAction) return [];
6344
+ const options = pendingSelectSourceAction.metadata?.options ?? [];
6345
+ return buildSelectSourceChoices(options);
6346
+ }, [pendingSelectSourceAction]);
6347
+ const selectSourceRecommended = useMemo(() => {
6348
+ if (!pendingSelectSourceAction) return null;
6349
+ return pendingSelectSourceAction.metadata?.recommended ?? null;
6350
+ }, [pendingSelectSourceAction]);
6351
+ const selectSourceAvailableBalance = useMemo(() => {
6352
+ if (!pendingSelectSourceAction) return 0;
6353
+ const options = pendingSelectSourceAction.metadata?.options ?? [];
6354
+ const recommended = selectSourceRecommended;
6355
+ if (recommended) {
6356
+ const match = options.find(
6357
+ (opt) => opt.chainName === recommended.chainName && opt.tokenSymbol === recommended.tokenSymbol
6358
+ );
6359
+ if (match) return Number(match.rawBalance) / Math.pow(10, match.decimals);
6523
6360
  }
6524
- const acct = state.accounts.find((a) => a.id === state.selectedAccountId);
6525
- const matchedProvider = acct ? state.providers.find((p) => p.name === acct.name) : void 0;
6526
- if (matchedProvider) {
6527
- dispatch({ type: "SELECT_PROVIDER", providerId: matchedProvider.id });
6361
+ let max = 0;
6362
+ for (const opt of options) {
6363
+ const bal = Number(opt.rawBalance) / Math.pow(10, opt.decimals);
6364
+ if (bal > max) max = bal;
6528
6365
  }
6529
- dispatch({ type: "SET_ERROR", error: null });
6530
- dispatch({ type: "SET_INCREASING_LIMIT", value: true });
6531
- pendingTokenAuthRef.current = { tokenAddress, chainId, tokenSymbol, walletId: _walletId };
6532
- try {
6533
- const token = await getAccessToken();
6534
- if (!token) throw new Error("Not authenticated");
6535
- const session = await createAccountAuthorizationSession(
6536
- apiBaseUrl,
6537
- token,
6538
- state.selectedAccountId,
6539
- state.activeCredentialId,
6540
- { tokenAddress, chainId }
6366
+ return max;
6367
+ }, [pendingSelectSourceAction, selectSourceRecommended]);
6368
+ const handleSelectSourceChainChange = useCallback(
6369
+ (chainName) => {
6370
+ setSelectSourceChainName(chainName);
6371
+ const chain = selectSourceChoices.find((c) => c.chainName === chainName);
6372
+ if (!chain || chain.tokens.length === 0) return;
6373
+ const recommendedToken = selectSourceRecommended?.chainName === chainName ? selectSourceRecommended.tokenSymbol : null;
6374
+ const hasRecommended = !!recommendedToken && chain.tokens.some((t) => t.tokenSymbol === recommendedToken);
6375
+ setSelectSourceTokenSymbol(
6376
+ hasRecommended ? recommendedToken : chain.tokens[0].tokenSymbol
6541
6377
  );
6542
- const isMobile = !shouldUseWalletConnector({
6543
- useWalletConnector: useWalletConnectorProp,
6544
- userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
6545
- });
6546
- if (isMobile) {
6378
+ },
6379
+ [selectSourceChoices, selectSourceRecommended]
6380
+ );
6381
+ const handleConfirmSelectSource = useCallback(() => {
6382
+ authExecutor.resolveSelectSource({
6383
+ chainName: selectSourceChainName,
6384
+ tokenSymbol: selectSourceTokenSymbol
6385
+ });
6386
+ }, [authExecutor, selectSourceChainName, selectSourceTokenSymbol]);
6387
+ return {
6388
+ selectSourceChainName,
6389
+ selectSourceTokenSymbol,
6390
+ setSelectSourceChainName,
6391
+ setSelectSourceTokenSymbol,
6392
+ selectSourceChoices,
6393
+ selectSourceRecommended,
6394
+ selectSourceAvailableBalance,
6395
+ handleSelectSourceChainChange,
6396
+ handleConfirmSelectSource,
6397
+ pendingSelectSourceAction,
6398
+ initializedSelectSourceActionRef,
6399
+ preSelectSourceStepRef
6400
+ };
6401
+ }
6402
+ function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs) {
6403
+ const {
6404
+ mobileSetupFlowRef,
6405
+ handlingMobileReturnRef,
6406
+ loadingDataRef
6407
+ } = refs;
6408
+ const handleAuthorizedMobileReturn = useCallback(async (authorizedTransfer, isSetup) => {
6409
+ if (handlingMobileReturnRef.current) return;
6410
+ handlingMobileReturnRef.current = true;
6411
+ polling.stopPolling();
6412
+ if (isSetup) {
6413
+ mobileSetupFlowRef.current = false;
6414
+ clearMobileFlowState();
6415
+ try {
6416
+ await reloadAccounts();
6417
+ loadingDataRef.current = false;
6418
+ dispatch({ type: "MOBILE_SETUP_COMPLETE", transfer: authorizedTransfer });
6419
+ } catch (err) {
6547
6420
  handlingMobileReturnRef.current = false;
6548
- mobileSetupFlowRef.current = true;
6549
- setupAccountIdRef.current = state.selectedAccountId;
6550
- reauthSessionIdRef.current = session.id;
6551
- reauthTokenRef.current = { walletId: _walletId, tokenSymbol };
6552
- persistMobileFlowState({
6553
- accountId: state.selectedAccountId,
6554
- sessionId: session.id,
6555
- deeplinkUri: session.uri,
6556
- providerId: matchedProvider?.id ?? null,
6557
- isSetup: true,
6558
- isReauthorization: true,
6559
- reauthorizationToken: { walletId: _walletId, tokenSymbol }
6421
+ dispatch({
6422
+ type: "SET_ERROR",
6423
+ error: err instanceof Error ? err.message : "Wallet authorized, but we could not refresh your account yet."
6560
6424
  });
6561
- dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: session.uri });
6562
- triggerDeeplink(session.uri);
6563
- } else {
6564
- pendingTokenAuthSessionRef.current = {
6565
- sessionId: session.id,
6566
- walletId: _walletId,
6567
- tokenSymbol,
6568
- tokenAddress,
6569
- chainId
6570
- };
6571
- dispatch({ type: "SELECT_TOKEN", walletId: _walletId, tokenSymbol });
6572
- dispatch({ type: "NAVIGATE", step: "setup" });
6425
+ dispatch({ type: "NAVIGATE", step: "open-wallet" });
6573
6426
  }
6574
- } catch (err) {
6575
- captureException(err);
6576
- const msg = err instanceof Error ? err.message : "Failed to authorize token";
6577
- dispatch({ type: "SET_ERROR", error: msg });
6578
- onError?.(msg);
6579
- } finally {
6580
- pendingTokenAuthRef.current = null;
6581
- dispatch({ type: "SET_INCREASING_LIMIT", value: false });
6582
- }
6583
- }, [
6584
- state.selectedAccountId,
6585
- state.activeCredentialId,
6586
- state.accounts,
6587
- state.providers,
6588
- apiBaseUrl,
6589
- getAccessToken,
6590
- authExecutor,
6591
- useWalletConnectorProp,
6592
- reloadAccounts,
6593
- onError
6594
- ]);
6595
- const handleConfirmSign = useCallback(async () => {
6596
- const t = state.transfer ?? polling.transfer;
6597
- if (!t) return;
6598
- try {
6599
- const signedTransfer = await transferSigning.signTransfer(t.id);
6600
- clearMobileFlowState();
6601
- dispatch({ type: "CONFIRM_SIGN_SUCCESS", transfer: signedTransfer });
6602
- polling.startPolling(t.id);
6603
- } catch (err) {
6604
- captureException(err);
6605
- const msg = err instanceof Error ? err.message : "Failed to sign transfer";
6606
- dispatch({ type: "SET_ERROR", error: msg });
6607
- onError?.(msg);
6427
+ return;
6608
6428
  }
6609
- }, [state.transfer, polling.transfer, polling.startPolling, transferSigning, onError]);
6429
+ mobileSetupFlowRef.current = false;
6430
+ clearMobileFlowState();
6431
+ dispatch({ type: "MOBILE_SIGN_READY", transfer: authorizedTransfer });
6432
+ }, [polling.stopPolling, reloadAccounts, dispatch]);
6610
6433
  const handleRetryMobileStatus = useCallback(() => {
6611
6434
  dispatch({ type: "SET_ERROR", error: null });
6612
6435
  handlingMobileReturnRef.current = false;
6613
- const currentTransfer = polling.transfer ?? state.transfer;
6436
+ const currentTransfer = polling.transfer ?? stateTransfer;
6614
6437
  if (currentTransfer?.status === "AUTHORIZED") {
6615
6438
  void handleAuthorizedMobileReturn(currentTransfer, mobileSetupFlowRef.current);
6616
6439
  return;
@@ -6619,15 +6442,54 @@ function SwypePaymentInner({
6619
6442
  if (transferIdToResume) {
6620
6443
  polling.startPolling(transferIdToResume);
6621
6444
  }
6622
- }, [handleAuthorizedMobileReturn, polling, state.transfer]);
6445
+ }, [handleAuthorizedMobileReturn, polling, stateTransfer, pollingTransferIdRef, dispatch]);
6446
+ return {
6447
+ handleAuthorizedMobileReturn,
6448
+ handleRetryMobileStatus
6449
+ };
6450
+ }
6451
+
6452
+ // src/walletFlow.ts
6453
+ var MOBILE_USER_AGENT_PATTERN = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
6454
+ function isMobileUserAgent(userAgent) {
6455
+ if (!userAgent) {
6456
+ return false;
6457
+ }
6458
+ return MOBILE_USER_AGENT_PATTERN.test(userAgent);
6459
+ }
6460
+ function shouldUseWalletConnector(options) {
6461
+ return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
6462
+ }
6463
+
6464
+ // src/hooks/useProviderHandlers.ts
6465
+ function useProviderHandlers(deps) {
6466
+ const {
6467
+ dispatch,
6468
+ getAccessToken,
6469
+ apiBaseUrl,
6470
+ depositAmount,
6471
+ useWalletConnectorProp,
6472
+ activeCredentialId,
6473
+ selectedAccountId,
6474
+ accounts,
6475
+ providers,
6476
+ authExecutor,
6477
+ reloadAccounts,
6478
+ onError,
6479
+ mobileSetupFlowRef,
6480
+ handlingMobileReturnRef,
6481
+ setupAccountIdRef,
6482
+ reauthSessionIdRef,
6483
+ reauthTokenRef
6484
+ } = deps;
6623
6485
  const handleSelectProvider = useCallback(async (providerId) => {
6624
6486
  dispatch({ type: "SELECT_PROVIDER", providerId });
6625
- if (!state.activeCredentialId) {
6487
+ if (!activeCredentialId) {
6626
6488
  dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
6627
6489
  dispatch({ type: "NAVIGATE", step: "create-passkey" });
6628
6490
  return;
6629
6491
  }
6630
- const provider = state.providers.find((p) => p.id === providerId);
6492
+ const provider = providers.find((p) => p.id === providerId);
6631
6493
  const providerName = provider?.name ?? "Wallet";
6632
6494
  const isMobile = !shouldUseWalletConnector({
6633
6495
  useWalletConnector: useWalletConnectorProp,
@@ -6646,7 +6508,7 @@ function SwypePaymentInner({
6646
6508
  const account = await createAccount(apiBaseUrl, token, {
6647
6509
  id: accountId,
6648
6510
  name: providerName,
6649
- credentialId: state.activeCredentialId,
6511
+ credentialId: activeCredentialId,
6650
6512
  providerId
6651
6513
  });
6652
6514
  const session = account.authorizationSessions?.[0];
@@ -6678,29 +6540,33 @@ function SwypePaymentInner({
6678
6540
  dispatch({ type: "PAY_ENDED" });
6679
6541
  }
6680
6542
  }, [
6681
- state.activeCredentialId,
6682
- state.providers,
6543
+ activeCredentialId,
6544
+ providers,
6683
6545
  apiBaseUrl,
6684
6546
  getAccessToken,
6685
6547
  authExecutor,
6686
6548
  useWalletConnectorProp,
6687
6549
  reloadAccounts,
6688
- onError
6550
+ onError,
6551
+ dispatch,
6552
+ mobileSetupFlowRef,
6553
+ handlingMobileReturnRef,
6554
+ setupAccountIdRef
6689
6555
  ]);
6690
6556
  const handleContinueConnection = useCallback(
6691
6557
  (accountId) => {
6692
- const acct = state.accounts.find((a) => a.id === accountId);
6558
+ const acct = accounts.find((a) => a.id === accountId);
6693
6559
  if (!acct) return;
6694
- const matchedProvider = state.providers.find((p) => p.name === acct.name);
6560
+ const matchedProvider = providers.find((p) => p.name === acct.name);
6695
6561
  if (matchedProvider) {
6696
6562
  handleSelectProvider(matchedProvider.id);
6697
6563
  }
6698
6564
  },
6699
- [state.accounts, state.providers, handleSelectProvider]
6565
+ [accounts, providers, handleSelectProvider]
6700
6566
  );
6701
6567
  const handleSelectAccount = useCallback(
6702
6568
  (accountId) => {
6703
- const acct = state.accounts.find((a) => a.id === accountId);
6569
+ const acct = accounts.find((a) => a.id === accountId);
6704
6570
  if (!acct) return;
6705
6571
  const activeWallet = getPreferredDepositWallet(acct, depositAmount ?? 0);
6706
6572
  dispatch({
@@ -6709,8 +6575,197 @@ function SwypePaymentInner({
6709
6575
  walletId: activeWallet?.id ?? null
6710
6576
  });
6711
6577
  },
6712
- [state.accounts, depositAmount]
6578
+ [accounts, depositAmount, dispatch]
6713
6579
  );
6580
+ const handleIncreaseLimit = useCallback(async () => {
6581
+ if (!selectedAccountId) {
6582
+ dispatch({ type: "SET_ERROR", error: "No account selected." });
6583
+ return;
6584
+ }
6585
+ if (!activeCredentialId) {
6586
+ dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
6587
+ dispatch({ type: "NAVIGATE", step: "create-passkey" });
6588
+ return;
6589
+ }
6590
+ const acct = accounts.find((a) => a.id === selectedAccountId);
6591
+ const matchedProvider = acct ? providers.find((p) => p.name === acct.name) : void 0;
6592
+ if (matchedProvider) {
6593
+ dispatch({ type: "SELECT_PROVIDER", providerId: matchedProvider.id });
6594
+ }
6595
+ dispatch({ type: "SET_ERROR", error: null });
6596
+ dispatch({ type: "SET_INCREASING_LIMIT", value: true });
6597
+ try {
6598
+ const token = await getAccessToken();
6599
+ if (!token) throw new Error("Not authenticated");
6600
+ const session = await createAccountAuthorizationSession(
6601
+ apiBaseUrl,
6602
+ token,
6603
+ selectedAccountId,
6604
+ activeCredentialId
6605
+ );
6606
+ const isMobile = !shouldUseWalletConnector({
6607
+ useWalletConnector: useWalletConnectorProp,
6608
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
6609
+ });
6610
+ if (isMobile) {
6611
+ handlingMobileReturnRef.current = false;
6612
+ mobileSetupFlowRef.current = true;
6613
+ setupAccountIdRef.current = selectedAccountId;
6614
+ reauthSessionIdRef.current = session.id;
6615
+ reauthTokenRef.current = null;
6616
+ persistMobileFlowState({
6617
+ accountId: selectedAccountId,
6618
+ sessionId: session.id,
6619
+ deeplinkUri: session.uri,
6620
+ providerId: matchedProvider?.id ?? null,
6621
+ isSetup: true,
6622
+ isReauthorization: true
6623
+ });
6624
+ dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: session.uri });
6625
+ triggerDeeplink(session.uri);
6626
+ } else {
6627
+ dispatch({ type: "NAVIGATE", step: "setup-status" });
6628
+ await authExecutor.executeSessionById(session.id);
6629
+ await reloadAccounts();
6630
+ dispatch({ type: "NAVIGATE", step: "deposit" });
6631
+ }
6632
+ } catch (err) {
6633
+ captureException(err);
6634
+ const msg = err instanceof Error ? err.message : "Failed to increase limit";
6635
+ dispatch({ type: "SET_ERROR", error: msg });
6636
+ onError?.(msg);
6637
+ } finally {
6638
+ dispatch({ type: "SET_INCREASING_LIMIT", value: false });
6639
+ }
6640
+ }, [
6641
+ selectedAccountId,
6642
+ activeCredentialId,
6643
+ accounts,
6644
+ providers,
6645
+ apiBaseUrl,
6646
+ getAccessToken,
6647
+ authExecutor,
6648
+ useWalletConnectorProp,
6649
+ reloadAccounts,
6650
+ onError,
6651
+ dispatch,
6652
+ mobileSetupFlowRef,
6653
+ handlingMobileReturnRef,
6654
+ setupAccountIdRef,
6655
+ reauthSessionIdRef,
6656
+ reauthTokenRef
6657
+ ]);
6658
+ const handleNavigateToTokenPicker = useCallback(() => {
6659
+ if (authExecutor.pendingSelectSource) {
6660
+ dispatch({ type: "NAVIGATE", step: "select-source" });
6661
+ } else {
6662
+ dispatch({ type: "NAVIGATE", step: "token-picker" });
6663
+ }
6664
+ }, [dispatch, authExecutor.pendingSelectSource]);
6665
+ const handleSelectAuthorizedToken = useCallback((walletId, tokenSymbol) => {
6666
+ dispatch({ type: "SELECT_TOKEN", walletId, tokenSymbol });
6667
+ }, [dispatch]);
6668
+ const handleAuthorizeToken = useCallback(async (_walletId, tokenAddress, chainId, tokenSymbol) => {
6669
+ if (!selectedAccountId) {
6670
+ dispatch({ type: "SET_ERROR", error: "No account selected." });
6671
+ return;
6672
+ }
6673
+ if (!activeCredentialId) {
6674
+ dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
6675
+ dispatch({ type: "NAVIGATE", step: "create-passkey" });
6676
+ return;
6677
+ }
6678
+ const acct = accounts.find((a) => a.id === selectedAccountId);
6679
+ const matchedProvider = acct ? providers.find((p) => p.name === acct.name) : void 0;
6680
+ if (matchedProvider) {
6681
+ dispatch({ type: "SELECT_PROVIDER", providerId: matchedProvider.id });
6682
+ }
6683
+ dispatch({ type: "SET_ERROR", error: null });
6684
+ dispatch({ type: "SET_INCREASING_LIMIT", value: true });
6685
+ try {
6686
+ const token = await getAccessToken();
6687
+ if (!token) throw new Error("Not authenticated");
6688
+ const session = await createAccountAuthorizationSession(
6689
+ apiBaseUrl,
6690
+ token,
6691
+ selectedAccountId,
6692
+ activeCredentialId,
6693
+ { tokenAddress, chainId }
6694
+ );
6695
+ const isMobile = !shouldUseWalletConnector({
6696
+ useWalletConnector: useWalletConnectorProp,
6697
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
6698
+ });
6699
+ if (isMobile) {
6700
+ handlingMobileReturnRef.current = false;
6701
+ mobileSetupFlowRef.current = true;
6702
+ setupAccountIdRef.current = selectedAccountId;
6703
+ reauthSessionIdRef.current = session.id;
6704
+ reauthTokenRef.current = { walletId: _walletId, tokenSymbol };
6705
+ persistMobileFlowState({
6706
+ accountId: selectedAccountId,
6707
+ sessionId: session.id,
6708
+ deeplinkUri: session.uri,
6709
+ providerId: matchedProvider?.id ?? null,
6710
+ isSetup: true,
6711
+ isReauthorization: true,
6712
+ reauthorizationToken: { walletId: _walletId, tokenSymbol }
6713
+ });
6714
+ dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: session.uri });
6715
+ triggerDeeplink(session.uri);
6716
+ } else {
6717
+ dispatch({ type: "NAVIGATE", step: "setup-status" });
6718
+ await authExecutor.executeSessionById(session.id);
6719
+ await reloadAccounts();
6720
+ dispatch({ type: "SELECT_TOKEN", walletId: _walletId, tokenSymbol });
6721
+ }
6722
+ } catch (err) {
6723
+ captureException(err);
6724
+ const msg = err instanceof Error ? err.message : "Failed to authorize token";
6725
+ dispatch({ type: "SET_ERROR", error: msg });
6726
+ onError?.(msg);
6727
+ } finally {
6728
+ dispatch({ type: "SET_INCREASING_LIMIT", value: false });
6729
+ }
6730
+ }, [
6731
+ selectedAccountId,
6732
+ activeCredentialId,
6733
+ accounts,
6734
+ providers,
6735
+ apiBaseUrl,
6736
+ getAccessToken,
6737
+ authExecutor,
6738
+ useWalletConnectorProp,
6739
+ reloadAccounts,
6740
+ onError,
6741
+ dispatch,
6742
+ mobileSetupFlowRef,
6743
+ handlingMobileReturnRef,
6744
+ setupAccountIdRef,
6745
+ reauthSessionIdRef,
6746
+ reauthTokenRef
6747
+ ]);
6748
+ return {
6749
+ handleSelectProvider,
6750
+ handleContinueConnection,
6751
+ handleSelectAccount,
6752
+ handleIncreaseLimit,
6753
+ handleNavigateToTokenPicker,
6754
+ handleSelectAuthorizedToken,
6755
+ handleAuthorizeToken
6756
+ };
6757
+ }
6758
+ function useOneTapSetupHandlers(deps) {
6759
+ const {
6760
+ dispatch,
6761
+ getAccessToken,
6762
+ apiBaseUrl,
6763
+ authExecutor,
6764
+ selectSourceChainName,
6765
+ selectSourceTokenSymbol
6766
+ } = deps;
6767
+ const [savingOneTapLimit, setSavingOneTapLimit] = useState(false);
6768
+ const oneTapLimitSavedDuringSetupRef = useRef(false);
6714
6769
  const handleSetupOneTap = useCallback(async (limit) => {
6715
6770
  setSavingOneTapLimit(true);
6716
6771
  try {
@@ -6718,39 +6773,24 @@ function SwypePaymentInner({
6718
6773
  if (!token) throw new Error("Not authenticated");
6719
6774
  await updateUserConfig(apiBaseUrl, token, { defaultAllowance: limit });
6720
6775
  if (authExecutor.pendingSelectSource) {
6721
- authExecutor.resolveSelectSource({
6722
- chainName: selectSourceChainName,
6723
- tokenSymbol: selectSourceTokenSymbol
6724
- });
6776
+ const action = authExecutor.pendingSelectSource;
6777
+ const recommended = action.metadata?.recommended;
6778
+ let chainName;
6779
+ let tokenSymbol;
6780
+ if (selectSourceChainName && selectSourceTokenSymbol) {
6781
+ chainName = selectSourceChainName;
6782
+ tokenSymbol = selectSourceTokenSymbol;
6783
+ } else {
6784
+ const options = action.metadata?.options ?? [];
6785
+ const choices = buildSelectSourceChoices(options);
6786
+ chainName = recommended?.chainName ?? choices[0]?.chainName ?? "Base";
6787
+ tokenSymbol = recommended?.tokenSymbol ?? choices[0]?.tokens[0]?.tokenSymbol ?? "USDC";
6788
+ }
6789
+ oneTapLimitSavedDuringSetupRef.current = true;
6790
+ authExecutor.resolveSelectSource({ chainName, tokenSymbol });
6725
6791
  dispatch({ type: "NAVIGATE", step: "setup-status" });
6726
6792
  } else if (authExecutor.pendingOneTapSetup) {
6727
6793
  authExecutor.resolveOneTapSetup();
6728
- } else if (pendingTokenAuthSessionRef.current) {
6729
- const pending = pendingTokenAuthSessionRef.current;
6730
- pendingTokenAuthSessionRef.current = null;
6731
- pendingTokenAuthRef.current = {
6732
- tokenAddress: pending.tokenAddress,
6733
- chainId: pending.chainId,
6734
- tokenSymbol: pending.tokenSymbol,
6735
- walletId: pending.walletId
6736
- };
6737
- dispatch({ type: "SET_INCREASING_LIMIT", value: true });
6738
- dispatch({ type: "NAVIGATE", step: "setup-status" });
6739
- try {
6740
- await authExecutor.executeSessionById(pending.sessionId);
6741
- await reloadAccounts();
6742
- dispatch({ type: "SELECT_TOKEN", walletId: pending.walletId, tokenSymbol: pending.tokenSymbol });
6743
- } catch (authErr) {
6744
- captureException(authErr);
6745
- dispatch({
6746
- type: "SET_ERROR",
6747
- error: authErr instanceof Error ? authErr.message : "Failed to authorize token"
6748
- });
6749
- dispatch({ type: "NAVIGATE", step: "deposit" });
6750
- } finally {
6751
- pendingTokenAuthRef.current = null;
6752
- dispatch({ type: "SET_INCREASING_LIMIT", value: false });
6753
- }
6754
6794
  } else {
6755
6795
  dispatch({ type: "NAVIGATE", step: "deposit" });
6756
6796
  }
@@ -6763,76 +6803,118 @@ function SwypePaymentInner({
6763
6803
  } finally {
6764
6804
  setSavingOneTapLimit(false);
6765
6805
  }
6766
- }, [getAccessToken, apiBaseUrl, authExecutor, reloadAccounts, onError, selectSourceChainName, selectSourceTokenSymbol]);
6767
- const handleNewPayment = useCallback(() => {
6768
- clearMobileFlowState();
6769
- processingStartedAtRef.current = null;
6770
- pollingTransferIdRef.current = null;
6771
- preSelectSourceStepRef.current = null;
6772
- pendingTokenSelectionRef.current = null;
6773
- pendingTokenAuthSessionRef.current = null;
6774
- dispatch({
6775
- type: "NEW_PAYMENT",
6776
- depositAmount,
6777
- firstAccountId: state.accounts.length > 0 ? state.accounts[0].id : null
6778
- });
6779
- }, [depositAmount, state.accounts]);
6780
- const handleLogout = useCallback(async () => {
6781
- try {
6782
- await logout();
6783
- } catch {
6784
- }
6785
- clearMobileFlowState();
6786
- if (typeof window !== "undefined") {
6787
- window.localStorage.removeItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
6788
- }
6789
- polling.stopPolling();
6790
- preSelectSourceStepRef.current = null;
6791
- pendingTokenSelectionRef.current = null;
6792
- pendingTokenAuthSessionRef.current = null;
6793
- checkingPasskeyRef.current = false;
6794
- setAuthInput("");
6795
- setOtpCode("");
6796
- dispatch({ type: "LOGOUT", depositAmount });
6797
- }, [logout, polling, depositAmount]);
6798
- const pendingSelectSourceAction = authExecutor.pendingSelectSource;
6799
- const selectSourceChoices = useMemo(() => {
6800
- if (!pendingSelectSourceAction) return [];
6801
- const options = pendingSelectSourceAction.metadata?.options ?? [];
6802
- return buildSelectSourceChoices(options);
6803
- }, [pendingSelectSourceAction]);
6804
- const selectSourceRecommended = useMemo(() => {
6805
- if (!pendingSelectSourceAction) return null;
6806
- return pendingSelectSourceAction.metadata?.recommended ?? null;
6807
- }, [pendingSelectSourceAction]);
6808
- const handleSelectSourceChainChange = useCallback(
6809
- (chainName) => {
6810
- setSelectSourceChainName(chainName);
6811
- const chain = selectSourceChoices.find((c) => c.chainName === chainName);
6812
- if (!chain || chain.tokens.length === 0) return;
6813
- const recommendedToken = selectSourceRecommended?.chainName === chainName ? selectSourceRecommended.tokenSymbol : null;
6814
- const hasRecommended = !!recommendedToken && chain.tokens.some((t) => t.tokenSymbol === recommendedToken);
6815
- setSelectSourceTokenSymbol(
6816
- hasRecommended ? recommendedToken : chain.tokens[0].tokenSymbol
6817
- );
6818
- },
6819
- [selectSourceChoices, selectSourceRecommended]
6820
- );
6821
- const handleConfirmSelectSource = useCallback(() => {
6822
- authExecutor.resolveSelectSource({
6823
- chainName: selectSourceChainName,
6824
- tokenSymbol: selectSourceTokenSymbol
6825
- });
6826
- }, [authExecutor, selectSourceChainName, selectSourceTokenSymbol]);
6806
+ }, [getAccessToken, apiBaseUrl, authExecutor, dispatch, selectSourceChainName, selectSourceTokenSymbol]);
6807
+ return {
6808
+ handleSetupOneTap,
6809
+ savingOneTapLimit,
6810
+ oneTapLimitSavedDuringSetupRef
6811
+ };
6812
+ }
6813
+
6814
+ // src/dataLoading.ts
6815
+ function resolveDataLoadAction({
6816
+ authenticated,
6817
+ step,
6818
+ accountsCount,
6819
+ hasActiveCredential,
6820
+ loading
6821
+ }) {
6822
+ if (!authenticated || step === "login" || step === "otp-verify" || accountsCount > 0 || !hasActiveCredential) {
6823
+ return "reset";
6824
+ }
6825
+ if (loading) {
6826
+ return "wait";
6827
+ }
6828
+ return "load";
6829
+ }
6830
+
6831
+ // src/processingStatus.ts
6832
+ var PROCESSING_TIMEOUT_MS = 18e4;
6833
+ function resolvePreferredTransfer(polledTransfer, localTransfer) {
6834
+ return polledTransfer ?? localTransfer;
6835
+ }
6836
+ function getTransferStatus(polledTransfer, localTransfer) {
6837
+ const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
6838
+ return transfer?.status ?? "UNKNOWN";
6839
+ }
6840
+ function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
6841
+ if (!processingStartedAtMs) return false;
6842
+ return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
6843
+ }
6844
+ var STATUS_DISPLAY_LABELS = {
6845
+ CREATED: "created",
6846
+ AUTHORIZED: "authorized",
6847
+ SENDING: "sending",
6848
+ SENT: "confirming delivery",
6849
+ COMPLETED: "completed",
6850
+ FAILED: "failed"
6851
+ };
6852
+ function getStatusDisplayLabel(status) {
6853
+ return STATUS_DISPLAY_LABELS[status] ?? status;
6854
+ }
6855
+ function buildProcessingTimeoutMessage(status) {
6856
+ const label = getStatusDisplayLabel(status);
6857
+ return `Payment is taking longer than expected (status: ${label}). Please try again.`;
6858
+ }
6859
+
6860
+ // src/hooks/usePaymentEffects.ts
6861
+ function usePaymentEffects(deps) {
6862
+ const {
6863
+ state,
6864
+ dispatch,
6865
+ ready,
6866
+ authenticated,
6867
+ apiBaseUrl,
6868
+ depositAmount,
6869
+ useWalletConnectorProp,
6870
+ onComplete,
6871
+ onError,
6872
+ polling,
6873
+ authExecutor,
6874
+ reloadAccounts,
6875
+ activeOtpStatus,
6876
+ activeOtpErrorMessage,
6877
+ otpCode,
6878
+ handleVerifyLoginCode,
6879
+ setAuthInput,
6880
+ setOtpCode,
6881
+ mobileSetupFlowRef,
6882
+ handlingMobileReturnRef,
6883
+ setupAccountIdRef,
6884
+ reauthSessionIdRef,
6885
+ reauthTokenRef,
6886
+ loadingDataRef,
6887
+ pollingTransferIdRef,
6888
+ processingStartedAtRef,
6889
+ checkingPasskeyRef,
6890
+ pendingSelectSourceAction,
6891
+ selectSourceChoices,
6892
+ selectSourceRecommended,
6893
+ setSelectSourceChainName,
6894
+ setSelectSourceTokenSymbol,
6895
+ initializedSelectSourceActionRef,
6896
+ preSelectSourceStepRef,
6897
+ oneTapLimitSavedDuringSetupRef,
6898
+ handleAuthorizedMobileReturn
6899
+ } = deps;
6900
+ const { getAccessToken } = usePrivy();
6901
+ const onCompleteRef = useRef(onComplete);
6902
+ onCompleteRef.current = onComplete;
6903
+ const getAccessTokenRef = useRef(getAccessToken);
6904
+ getAccessTokenRef.current = getAccessToken;
6905
+ const pollingRef = useRef(polling);
6906
+ pollingRef.current = polling;
6907
+ const handleAuthorizedMobileReturnRef = useRef(handleAuthorizedMobileReturn);
6908
+ handleAuthorizedMobileReturnRef.current = handleAuthorizedMobileReturn;
6827
6909
  useEffect(() => {
6828
6910
  if (depositAmount != null) {
6829
6911
  dispatch({ type: "SYNC_AMOUNT", amount: depositAmount.toString() });
6830
6912
  }
6831
- }, [depositAmount]);
6913
+ }, [depositAmount, dispatch]);
6832
6914
  useEffect(() => {
6833
6915
  if (authenticated || state.step !== "otp-verify") return;
6834
6916
  if (activeOtpErrorMessage) dispatch({ type: "SET_ERROR", error: activeOtpErrorMessage });
6835
- }, [activeOtpErrorMessage, authenticated, state.step]);
6917
+ }, [activeOtpErrorMessage, authenticated, state.step, dispatch]);
6836
6918
  useEffect(() => {
6837
6919
  if (state.step === "otp-verify" && /^\d{6}$/.test(otpCode.trim()) && activeOtpStatus === "awaiting-code-input") {
6838
6920
  handleVerifyLoginCode();
@@ -7059,7 +7141,7 @@ function SwypePaymentInner({
7059
7141
  const load = async () => {
7060
7142
  dispatch({ type: "DATA_LOAD_START" });
7061
7143
  try {
7062
- const token = await getAccessToken();
7144
+ const token = await getAccessTokenRef.current();
7063
7145
  if (!token) throw new Error("Not authenticated");
7064
7146
  const [prov, accts, chn] = await Promise.all([
7065
7147
  fetchProviders(apiBaseUrl, token),
@@ -7113,7 +7195,6 @@ function SwypePaymentInner({
7113
7195
  state.step,
7114
7196
  state.accounts.length,
7115
7197
  apiBaseUrl,
7116
- getAccessToken,
7117
7198
  state.activeCredentialId,
7118
7199
  state.selectedAccountId,
7119
7200
  depositAmount
@@ -7128,7 +7209,7 @@ function SwypePaymentInner({
7128
7209
  clearMobileFlowState();
7129
7210
  dispatch({ type: "TRANSFER_FAILED", transfer: polling.transfer, error: "Transfer failed." });
7130
7211
  }
7131
- }, [polling.transfer, onComplete]);
7212
+ }, [polling.transfer, onComplete, dispatch]);
7132
7213
  useEffect(() => {
7133
7214
  if (state.step !== "processing") {
7134
7215
  processingStartedAtRef.current = null;
@@ -7154,7 +7235,7 @@ function SwypePaymentInner({
7154
7235
  }
7155
7236
  const timeoutId = window.setTimeout(handleTimeout, remainingMs);
7156
7237
  return () => window.clearTimeout(timeoutId);
7157
- }, [state.step, polling.transfer, state.transfer, polling.stopPolling, onError]);
7238
+ }, [state.step, polling.transfer, state.transfer, polling.stopPolling, onError, dispatch, processingStartedAtRef]);
7158
7239
  useEffect(() => {
7159
7240
  if (!state.mobileFlow) {
7160
7241
  handlingMobileReturnRef.current = false;
@@ -7164,7 +7245,7 @@ function SwypePaymentInner({
7164
7245
  const polledTransfer = polling.transfer;
7165
7246
  if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
7166
7247
  void handleAuthorizedMobileReturn(polledTransfer, mobileSetupFlowRef.current);
7167
- }, [state.mobileFlow, polling.transfer, handleAuthorizedMobileReturn]);
7248
+ }, [state.mobileFlow, polling.transfer, handleAuthorizedMobileReturn, handlingMobileReturnRef, mobileSetupFlowRef]);
7168
7249
  useEffect(() => {
7169
7250
  if (!state.mobileFlow || !mobileSetupFlowRef.current) return;
7170
7251
  if (state.step !== "open-wallet") return;
@@ -7235,7 +7316,18 @@ function SwypePaymentInner({
7235
7316
  window.clearInterval(intervalId);
7236
7317
  document.removeEventListener("visibilitychange", handleVisibility);
7237
7318
  };
7238
- }, [state.mobileFlow, state.step, state.activeCredentialId, apiBaseUrl, reloadAccounts]);
7319
+ }, [
7320
+ state.mobileFlow,
7321
+ state.step,
7322
+ state.activeCredentialId,
7323
+ apiBaseUrl,
7324
+ reloadAccounts,
7325
+ dispatch,
7326
+ mobileSetupFlowRef,
7327
+ setupAccountIdRef,
7328
+ reauthSessionIdRef,
7329
+ reauthTokenRef
7330
+ ]);
7239
7331
  useEffect(() => {
7240
7332
  if (!state.mobileFlow) return;
7241
7333
  if (handlingMobileReturnRef.current) return;
@@ -7249,7 +7341,14 @@ function SwypePaymentInner({
7249
7341
  };
7250
7342
  document.addEventListener("visibilitychange", handleVisibility);
7251
7343
  return () => document.removeEventListener("visibilitychange", handleVisibility);
7252
- }, [state.mobileFlow, state.transfer?.id, polling.isPolling, polling.startPolling]);
7344
+ }, [
7345
+ state.mobileFlow,
7346
+ state.transfer?.id,
7347
+ polling.isPolling,
7348
+ polling.startPolling,
7349
+ handlingMobileReturnRef,
7350
+ pollingTransferIdRef
7351
+ ]);
7253
7352
  useEffect(() => {
7254
7353
  if (!pendingSelectSourceAction) {
7255
7354
  initializedSelectSourceActionRef.current = null;
@@ -7258,20 +7357,6 @@ function SwypePaymentInner({
7258
7357
  return;
7259
7358
  }
7260
7359
  if (initializedSelectSourceActionRef.current === pendingSelectSourceAction.id) return;
7261
- const options = pendingSelectSourceAction.metadata?.options ?? [];
7262
- if (pendingTokenAuthRef.current) {
7263
- const { tokenAddress, chainId } = pendingTokenAuthRef.current;
7264
- const chainIdHex = `0x${chainId.toString(16)}`;
7265
- const match = options.find(
7266
- (opt) => opt.tokenAddress.toLowerCase() === tokenAddress.toLowerCase() && opt.chainId.toLowerCase() === chainIdHex.toLowerCase()
7267
- );
7268
- if (match) {
7269
- setSelectSourceChainName(match.chainName);
7270
- setSelectSourceTokenSymbol(match.tokenSymbol);
7271
- initializedSelectSourceActionRef.current = pendingSelectSourceAction.id;
7272
- return;
7273
- }
7274
- }
7275
7360
  const hasRecommended = !!selectSourceRecommended && selectSourceChoices.some(
7276
7361
  (chain) => chain.chainName === selectSourceRecommended.chainName && chain.tokens.some((t) => t.tokenSymbol === selectSourceRecommended.tokenSymbol)
7277
7362
  );
@@ -7286,7 +7371,14 @@ function SwypePaymentInner({
7286
7371
  setSelectSourceTokenSymbol("USDC");
7287
7372
  }
7288
7373
  initializedSelectSourceActionRef.current = pendingSelectSourceAction.id;
7289
- }, [pendingSelectSourceAction, selectSourceChoices, selectSourceRecommended]);
7374
+ }, [
7375
+ pendingSelectSourceAction,
7376
+ selectSourceChoices,
7377
+ selectSourceRecommended,
7378
+ setSelectSourceChainName,
7379
+ setSelectSourceTokenSymbol,
7380
+ initializedSelectSourceActionRef
7381
+ ]);
7290
7382
  useEffect(() => {
7291
7383
  if (pendingSelectSourceAction && (state.step === "processing" || state.step === "open-wallet" || state.step === "setup-status")) {
7292
7384
  const isDesktop = shouldUseWalletConnector({
@@ -7294,9 +7386,8 @@ function SwypePaymentInner({
7294
7386
  userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
7295
7387
  });
7296
7388
  if (isDesktop && state.step === "setup-status") {
7297
- reloadAccounts().then(() => {
7298
- dispatch({ type: "NAVIGATE", step: "deposit" });
7299
- });
7389
+ preSelectSourceStepRef.current = state.step;
7390
+ dispatch({ type: "NAVIGATE", step: "setup" });
7300
7391
  return;
7301
7392
  }
7302
7393
  preSelectSourceStepRef.current = state.step;
@@ -7305,75 +7396,243 @@ function SwypePaymentInner({
7305
7396
  dispatch({ type: "NAVIGATE", step: preSelectSourceStepRef.current ?? "processing" });
7306
7397
  preSelectSourceStepRef.current = null;
7307
7398
  }
7308
- }, [pendingSelectSourceAction, state.step, authExecutor, useWalletConnectorProp, reloadAccounts]);
7399
+ }, [pendingSelectSourceAction, state.step, useWalletConnectorProp, dispatch, preSelectSourceStepRef, authExecutor]);
7309
7400
  const pendingOneTapSetupAction = authExecutor.pendingOneTapSetup;
7310
7401
  const preOneTapSetupStepRef = useRef(null);
7311
7402
  useEffect(() => {
7312
7403
  if (pendingOneTapSetupAction && state.step === "setup-status") {
7313
- preOneTapSetupStepRef.current = state.step;
7314
- reloadAccounts().then(() => {
7315
- dispatch({ type: "NAVIGATE", step: "setup" });
7316
- });
7404
+ if (oneTapLimitSavedDuringSetupRef.current) {
7405
+ oneTapLimitSavedDuringSetupRef.current = false;
7406
+ authExecutor.resolveOneTapSetup();
7407
+ } else {
7408
+ preOneTapSetupStepRef.current = state.step;
7409
+ reloadAccounts().then(() => {
7410
+ dispatch({ type: "NAVIGATE", step: "setup" });
7411
+ });
7412
+ }
7317
7413
  } else if (!pendingOneTapSetupAction && state.step === "setup" && preOneTapSetupStepRef.current) {
7318
7414
  dispatch({ type: "NAVIGATE", step: preOneTapSetupStepRef.current });
7319
7415
  preOneTapSetupStepRef.current = null;
7320
7416
  }
7321
- }, [pendingOneTapSetupAction, state.step, reloadAccounts]);
7417
+ }, [pendingOneTapSetupAction, state.step, reloadAccounts, authExecutor, dispatch, oneTapLimitSavedDuringSetupRef]);
7418
+ }
7419
+ function SwypePayment(props) {
7420
+ const resetKey = useRef(0);
7421
+ const handleBoundaryReset = useCallback(() => {
7422
+ resetKey.current += 1;
7423
+ }, []);
7424
+ return /* @__PURE__ */ jsx(PaymentErrorBoundary, { onReset: handleBoundaryReset, children: /* @__PURE__ */ jsx(SwypePaymentInner, { ...props }) }, resetKey.current);
7425
+ }
7426
+ function SwypePaymentInner({
7427
+ destination,
7428
+ onComplete,
7429
+ onError,
7430
+ useWalletConnector: useWalletConnectorProp,
7431
+ idempotencyKey,
7432
+ merchantAuthorization,
7433
+ merchantName,
7434
+ onBack,
7435
+ onDismiss,
7436
+ autoCloseSeconds
7437
+ }) {
7438
+ const { apiBaseUrl, depositAmount } = useSwypeConfig();
7439
+ const { ready, authenticated, logout, getAccessToken } = usePrivy();
7440
+ useLoginWithOAuth();
7441
+ const [state, dispatch] = useReducer(
7442
+ paymentReducer,
7443
+ {
7444
+ depositAmount,
7445
+ passkeyPopupNeeded: isSafari() && isInCrossOriginIframe(),
7446
+ activeCredentialId: typeof window === "undefined" ? null : window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY)
7447
+ },
7448
+ createInitialState
7449
+ );
7450
+ const authExecutor = useAuthorizationExecutor();
7451
+ const polling = useTransferPolling();
7452
+ const transferSigning = useTransferSigning();
7453
+ const mobileFlowRefs = {
7454
+ mobileSetupFlowRef: useRef(false),
7455
+ handlingMobileReturnRef: useRef(false),
7456
+ setupAccountIdRef: useRef(null),
7457
+ reauthSessionIdRef: useRef(null),
7458
+ reauthTokenRef: useRef(null),
7459
+ loadingDataRef: useRef(false)
7460
+ };
7461
+ const derived = useDerivedState(state);
7462
+ const auth = useAuthHandlers(dispatch, state.verificationTarget);
7463
+ const passkey = usePasskeyHandlers(
7464
+ dispatch,
7465
+ apiBaseUrl,
7466
+ state.accounts,
7467
+ state.knownCredentialIds,
7468
+ mobileFlowRefs.mobileSetupFlowRef
7469
+ );
7470
+ const transfer = useTransferHandlers({
7471
+ dispatch,
7472
+ getAccessToken,
7473
+ apiBaseUrl,
7474
+ depositAmount,
7475
+ destination,
7476
+ idempotencyKey,
7477
+ merchantAuthorization,
7478
+ onComplete,
7479
+ onError,
7480
+ polling,
7481
+ transferSigning,
7482
+ sourceType: derived.sourceType,
7483
+ sourceId: derived.sourceId,
7484
+ sourceTokenAddress: derived.selectedSource?.address,
7485
+ activeCredentialId: state.activeCredentialId,
7486
+ selectedAccountId: state.selectedAccountId,
7487
+ transfer: state.transfer,
7488
+ accounts: state.accounts
7489
+ });
7490
+ const mobileFlow = useMobileFlowHandlers(
7491
+ dispatch,
7492
+ polling,
7493
+ transfer.reloadAccounts,
7494
+ transfer.pollingTransferIdRef,
7495
+ state.transfer,
7496
+ mobileFlowRefs
7497
+ );
7498
+ const sourceSelection = useSourceSelectionHandlers(dispatch, authExecutor);
7499
+ const provider = useProviderHandlers({
7500
+ dispatch,
7501
+ getAccessToken,
7502
+ apiBaseUrl,
7503
+ depositAmount,
7504
+ useWalletConnectorProp,
7505
+ activeCredentialId: state.activeCredentialId,
7506
+ selectedAccountId: state.selectedAccountId,
7507
+ accounts: state.accounts,
7508
+ providers: state.providers,
7509
+ authExecutor,
7510
+ reloadAccounts: transfer.reloadAccounts,
7511
+ onError,
7512
+ mobileSetupFlowRef: mobileFlowRefs.mobileSetupFlowRef,
7513
+ handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
7514
+ setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
7515
+ reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
7516
+ reauthTokenRef: mobileFlowRefs.reauthTokenRef
7517
+ });
7518
+ const oneTapSetup = useOneTapSetupHandlers({
7519
+ dispatch,
7520
+ getAccessToken,
7521
+ apiBaseUrl,
7522
+ authExecutor,
7523
+ selectSourceChainName: sourceSelection.selectSourceChainName,
7524
+ selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol
7525
+ });
7526
+ const handleNewPayment = useCallback(() => {
7527
+ clearMobileFlowState();
7528
+ transfer.processingStartedAtRef.current = null;
7529
+ transfer.pollingTransferIdRef.current = null;
7530
+ sourceSelection.preSelectSourceStepRef.current = null;
7531
+ oneTapSetup.oneTapLimitSavedDuringSetupRef.current = false;
7532
+ dispatch({
7533
+ type: "NEW_PAYMENT",
7534
+ depositAmount,
7535
+ firstAccountId: state.accounts.length > 0 ? state.accounts[0].id : null
7536
+ });
7537
+ }, [depositAmount, state.accounts, transfer, sourceSelection, provider, oneTapSetup]);
7538
+ const handleLogout = useCallback(async () => {
7539
+ try {
7540
+ await logout();
7541
+ } catch {
7542
+ }
7543
+ clearMobileFlowState();
7544
+ if (typeof window !== "undefined") {
7545
+ window.localStorage.removeItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
7546
+ }
7547
+ polling.stopPolling();
7548
+ sourceSelection.preSelectSourceStepRef.current = null;
7549
+ passkey.checkingPasskeyRef.current = false;
7550
+ oneTapSetup.oneTapLimitSavedDuringSetupRef.current = false;
7551
+ auth.setAuthInput("");
7552
+ auth.setOtpCode("");
7553
+ dispatch({ type: "LOGOUT", depositAmount });
7554
+ }, [logout, polling, depositAmount, auth, sourceSelection, provider, passkey, oneTapSetup]);
7555
+ usePaymentEffects({
7556
+ state,
7557
+ dispatch,
7558
+ ready,
7559
+ authenticated,
7560
+ apiBaseUrl,
7561
+ depositAmount,
7562
+ useWalletConnectorProp,
7563
+ onComplete,
7564
+ onError,
7565
+ polling,
7566
+ authExecutor,
7567
+ reloadAccounts: transfer.reloadAccounts,
7568
+ activeOtpStatus: auth.activeOtpStatus,
7569
+ activeOtpErrorMessage: auth.activeOtpErrorMessage,
7570
+ otpCode: auth.otpCode,
7571
+ handleVerifyLoginCode: auth.handleVerifyLoginCode,
7572
+ setAuthInput: auth.setAuthInput,
7573
+ setOtpCode: auth.setOtpCode,
7574
+ mobileSetupFlowRef: mobileFlowRefs.mobileSetupFlowRef,
7575
+ handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
7576
+ setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
7577
+ reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
7578
+ reauthTokenRef: mobileFlowRefs.reauthTokenRef,
7579
+ loadingDataRef: mobileFlowRefs.loadingDataRef,
7580
+ pollingTransferIdRef: transfer.pollingTransferIdRef,
7581
+ processingStartedAtRef: transfer.processingStartedAtRef,
7582
+ checkingPasskeyRef: passkey.checkingPasskeyRef,
7583
+ pendingSelectSourceAction: sourceSelection.pendingSelectSourceAction,
7584
+ selectSourceChoices: sourceSelection.selectSourceChoices,
7585
+ selectSourceRecommended: sourceSelection.selectSourceRecommended,
7586
+ setSelectSourceChainName: sourceSelection.setSelectSourceChainName,
7587
+ setSelectSourceTokenSymbol: sourceSelection.setSelectSourceTokenSymbol,
7588
+ initializedSelectSourceActionRef: sourceSelection.initializedSelectSourceActionRef,
7589
+ preSelectSourceStepRef: sourceSelection.preSelectSourceStepRef,
7590
+ oneTapLimitSavedDuringSetupRef: oneTapSetup.oneTapLimitSavedDuringSetupRef,
7591
+ handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn
7592
+ });
7322
7593
  const handlers = useMemo(() => ({
7323
- onSendLoginCode: handleSendLoginCode,
7324
- onVerifyLoginCode: handleVerifyLoginCode,
7325
- onResendLoginCode: handleResendLoginCode,
7594
+ onSendLoginCode: auth.handleSendLoginCode,
7595
+ onVerifyLoginCode: auth.handleVerifyLoginCode,
7596
+ onResendLoginCode: auth.handleResendLoginCode,
7326
7597
  onBackFromOtp: () => {
7327
- setOtpCode("");
7598
+ auth.setOtpCode("");
7328
7599
  dispatch({ type: "BACK_TO_LOGIN" });
7329
7600
  },
7330
- onRegisterPasskey: handleRegisterPasskey,
7331
- onCreatePasskeyViaPopup: handleCreatePasskeyViaPopup,
7332
- onVerifyPasskeyViaPopup: handleVerifyPasskeyViaPopup,
7333
- onSelectProvider: handleSelectProvider,
7334
- onContinueConnection: handleContinueConnection,
7335
- onSelectAccount: handleSelectAccount,
7336
- onPay: handlePay,
7337
- onIncreaseLimit: handleIncreaseLimit,
7338
- onConfirmSign: handleConfirmSign,
7339
- onRetryMobileStatus: handleRetryMobileStatus,
7601
+ onRegisterPasskey: passkey.handleRegisterPasskey,
7602
+ onCreatePasskeyViaPopup: passkey.handleCreatePasskeyViaPopup,
7603
+ onVerifyPasskeyViaPopup: passkey.handleVerifyPasskeyViaPopup,
7604
+ onSelectProvider: provider.handleSelectProvider,
7605
+ onContinueConnection: provider.handleContinueConnection,
7606
+ onSelectAccount: provider.handleSelectAccount,
7607
+ onPay: transfer.handlePay,
7608
+ onIncreaseLimit: provider.handleIncreaseLimit,
7609
+ onConfirmSign: transfer.handleConfirmSign,
7610
+ onRetryMobileStatus: mobileFlow.handleRetryMobileStatus,
7340
7611
  onLogout: handleLogout,
7341
7612
  onNewPayment: handleNewPayment,
7342
7613
  onNavigate: (step) => dispatch({ type: "NAVIGATE", step }),
7343
- onSetAuthInput: setAuthInput,
7614
+ onSetAuthInput: auth.setAuthInput,
7344
7615
  onSetOtpCode: (code) => {
7345
- setOtpCode(code);
7616
+ auth.setOtpCode(code);
7346
7617
  dispatch({ type: "SET_ERROR", error: null });
7347
7618
  },
7348
- onSelectSourceChainChange: handleSelectSourceChainChange,
7349
- onSetSelectSourceTokenSymbol: setSelectSourceTokenSymbol,
7350
- onConfirmSelectSource: handleConfirmSelectSource,
7351
- onSetupOneTap: handleSetupOneTap,
7352
- onSelectToken: handleNavigateToTokenPicker,
7353
- onSelectAuthorizedToken: handleSelectAuthorizedToken,
7354
- onAuthorizeToken: handleAuthorizeToken
7619
+ onSelectSourceChainChange: sourceSelection.handleSelectSourceChainChange,
7620
+ onSetSelectSourceTokenSymbol: sourceSelection.setSelectSourceTokenSymbol,
7621
+ onConfirmSelectSource: sourceSelection.handleConfirmSelectSource,
7622
+ onSetupOneTap: oneTapSetup.handleSetupOneTap,
7623
+ onSelectToken: provider.handleNavigateToTokenPicker,
7624
+ onSelectAuthorizedToken: provider.handleSelectAuthorizedToken,
7625
+ onAuthorizeToken: provider.handleAuthorizeToken
7355
7626
  }), [
7356
- handleSendLoginCode,
7357
- handleVerifyLoginCode,
7358
- handleResendLoginCode,
7359
- handleRegisterPasskey,
7360
- handleCreatePasskeyViaPopup,
7361
- handleVerifyPasskeyViaPopup,
7362
- handleSelectProvider,
7363
- handleContinueConnection,
7364
- handleSelectAccount,
7365
- handlePay,
7366
- handleIncreaseLimit,
7367
- handleConfirmSign,
7368
- handleRetryMobileStatus,
7627
+ auth,
7628
+ passkey,
7629
+ provider,
7630
+ transfer,
7631
+ mobileFlow,
7632
+ sourceSelection,
7633
+ oneTapSetup,
7369
7634
  handleLogout,
7370
- handleNewPayment,
7371
- handleSelectSourceChainChange,
7372
- handleConfirmSelectSource,
7373
- handleSetupOneTap,
7374
- handleNavigateToTokenPicker,
7375
- handleSelectAuthorizedToken,
7376
- handleAuthorizeToken
7635
+ handleNewPayment
7377
7636
  ]);
7378
7637
  return /* @__PURE__ */ jsx(
7379
7638
  StepRenderer,
@@ -7381,29 +7640,29 @@ function SwypePaymentInner({
7381
7640
  state,
7382
7641
  ready,
7383
7642
  authenticated,
7384
- activeOtpStatus,
7643
+ activeOtpStatus: auth.activeOtpStatus,
7385
7644
  pollingTransfer: polling.transfer,
7386
7645
  pollingError: polling.error,
7387
7646
  authExecutorError: authExecutor.error,
7388
7647
  transferSigningSigning: transferSigning.signing,
7389
7648
  transferSigningError: transferSigning.error,
7390
- pendingConnections,
7391
- depositEligibleAccounts,
7392
- sourceName,
7393
- sourceAddress,
7394
- sourceVerified,
7395
- maxSourceBalance,
7396
- tokenCount,
7397
- selectedAccount,
7398
- selectedSource,
7399
- selectSourceChoices,
7400
- selectSourceRecommended,
7401
- authInput,
7402
- otpCode,
7403
- selectSourceChainName,
7404
- selectSourceTokenSymbol,
7405
- savingOneTapLimit,
7406
- pendingSetup: !!pendingSelectSourceAction || !!pendingOneTapSetupAction,
7649
+ pendingConnections: derived.pendingConnections,
7650
+ depositEligibleAccounts: derived.depositEligibleAccounts,
7651
+ sourceName: derived.sourceName,
7652
+ sourceAddress: derived.sourceAddress,
7653
+ sourceVerified: derived.sourceVerified,
7654
+ maxSourceBalance: derived.maxSourceBalance,
7655
+ tokenCount: derived.tokenCount,
7656
+ selectedAccount: derived.selectedAccount,
7657
+ selectedSource: derived.selectedSource,
7658
+ selectSourceChoices: sourceSelection.selectSourceChoices,
7659
+ selectSourceRecommended: sourceSelection.selectSourceRecommended,
7660
+ selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance,
7661
+ authInput: auth.authInput,
7662
+ otpCode: auth.otpCode,
7663
+ selectSourceChainName: sourceSelection.selectSourceChainName,
7664
+ selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol,
7665
+ savingOneTapLimit: oneTapSetup.savingOneTapLimit,
7407
7666
  merchantName,
7408
7667
  onBack,
7409
7668
  onDismiss,