@swype-org/react-sdk 0.1.133 → 0.1.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1283 -997
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1284 -998
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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/
|
|
672
|
-
|
|
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";
|
|
@@ -1855,24 +1678,34 @@ function hasActiveDepositWallet(account) {
|
|
|
1855
1678
|
function getPreferredDepositWallet(account, transferAmount) {
|
|
1856
1679
|
const wallets = getAddressableWallets(account);
|
|
1857
1680
|
if (wallets.length === 0) return null;
|
|
1681
|
+
let bestWithAllowance = null;
|
|
1682
|
+
let bestWithAllowanceBal = -1;
|
|
1683
|
+
let bestActive = null;
|
|
1684
|
+
let bestActiveBal = -1;
|
|
1685
|
+
let bestAny = null;
|
|
1686
|
+
let bestAnyBal = -1;
|
|
1858
1687
|
for (const wallet of wallets) {
|
|
1859
|
-
if (wallet.status === "ACTIVE" && wallet.sources.some((source) => source.balance.available.amount >= transferAmount)) {
|
|
1860
|
-
return wallet;
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
let bestWallet = null;
|
|
1864
|
-
let bestBalance = -1;
|
|
1865
|
-
let bestIsActive = false;
|
|
1866
|
-
for (const wallet of wallets) {
|
|
1867
|
-
const walletBal = wallet.balance.available.amount;
|
|
1868
1688
|
const isActive = wallet.status === "ACTIVE";
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1689
|
+
const walletBal = wallet.balance.available.amount;
|
|
1690
|
+
if (isActive) {
|
|
1691
|
+
const hasFullyEligibleSource = wallet.sources.some(
|
|
1692
|
+
(s) => s.balance.available.amount >= transferAmount && s.remainingAllowance != null && s.remainingAllowance >= transferAmount
|
|
1693
|
+
);
|
|
1694
|
+
if (hasFullyEligibleSource && walletBal > bestWithAllowanceBal) {
|
|
1695
|
+
bestWithAllowance = wallet;
|
|
1696
|
+
bestWithAllowanceBal = walletBal;
|
|
1697
|
+
}
|
|
1698
|
+
if (walletBal > bestActiveBal) {
|
|
1699
|
+
bestActive = wallet;
|
|
1700
|
+
bestActiveBal = walletBal;
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
if (walletBal > bestAnyBal) {
|
|
1704
|
+
bestAny = wallet;
|
|
1705
|
+
bestAnyBal = walletBal;
|
|
1873
1706
|
}
|
|
1874
1707
|
}
|
|
1875
|
-
return
|
|
1708
|
+
return bestWithAllowance ?? bestActive ?? bestAny ?? wallets[0];
|
|
1876
1709
|
}
|
|
1877
1710
|
function getDepositEligibleAccounts(accounts) {
|
|
1878
1711
|
return accounts.filter((account) => getAddressableWallets(account).length > 0);
|
|
@@ -1892,7 +1725,9 @@ function resolveDepositSelection(accounts, transferAmount, selectedAccountId) {
|
|
|
1892
1725
|
}
|
|
1893
1726
|
for (const account of eligibleAccounts) {
|
|
1894
1727
|
const fullyEligibleWallet = getAddressableWallets(account).find(
|
|
1895
|
-
(wallet) => wallet.status === "ACTIVE" && wallet.sources.some(
|
|
1728
|
+
(wallet) => wallet.status === "ACTIVE" && wallet.sources.some(
|
|
1729
|
+
(source) => source.balance.available.amount >= transferAmount && source.remainingAllowance != null && source.remainingAllowance >= transferAmount
|
|
1730
|
+
)
|
|
1896
1731
|
);
|
|
1897
1732
|
if (fullyEligibleWallet) {
|
|
1898
1733
|
return {
|
|
@@ -2232,6 +2067,46 @@ function paymentReducer(state, action) {
|
|
|
2232
2067
|
return state;
|
|
2233
2068
|
}
|
|
2234
2069
|
}
|
|
2070
|
+
|
|
2071
|
+
// src/auth.ts
|
|
2072
|
+
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2073
|
+
var PHONE_DIGIT_PATTERN = /^\d{7,15}$/;
|
|
2074
|
+
function normalizePhoneNumber(rawValue) {
|
|
2075
|
+
const trimmed = rawValue.trim();
|
|
2076
|
+
if (!trimmed) return null;
|
|
2077
|
+
const hasExplicitCountryCode = trimmed.startsWith("+");
|
|
2078
|
+
const digits = trimmed.replace(/\D/g, "");
|
|
2079
|
+
if (!PHONE_DIGIT_PATTERN.test(digits)) return null;
|
|
2080
|
+
return hasExplicitCountryCode ? `+${digits}` : digits;
|
|
2081
|
+
}
|
|
2082
|
+
function normalizeAuthIdentifier(rawValue) {
|
|
2083
|
+
const trimmed = rawValue.trim();
|
|
2084
|
+
if (!trimmed) return null;
|
|
2085
|
+
if (EMAIL_PATTERN.test(trimmed)) {
|
|
2086
|
+
return {
|
|
2087
|
+
kind: "email",
|
|
2088
|
+
value: trimmed.toLowerCase()
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
const normalizedPhoneNumber = normalizePhoneNumber(trimmed);
|
|
2092
|
+
if (normalizedPhoneNumber) {
|
|
2093
|
+
return {
|
|
2094
|
+
kind: "phone",
|
|
2095
|
+
value: normalizedPhoneNumber
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
return null;
|
|
2099
|
+
}
|
|
2100
|
+
function maskAuthIdentifier(identifier) {
|
|
2101
|
+
if (identifier.kind === "email") {
|
|
2102
|
+
const [localPart, domain = ""] = identifier.value.split("@");
|
|
2103
|
+
const localPrefix = localPart.slice(0, 2);
|
|
2104
|
+
return `${localPrefix}${"*".repeat(Math.max(localPart.length - 2, 0))}@${domain}`;
|
|
2105
|
+
}
|
|
2106
|
+
const digits = identifier.value.replace(/\D/g, "");
|
|
2107
|
+
const visibleSuffix = digits.slice(-4);
|
|
2108
|
+
return `***-***-${visibleSuffix}`;
|
|
2109
|
+
}
|
|
2235
2110
|
var ACCENT = "#28b67a";
|
|
2236
2111
|
var BG_RING = "#d2e4ea";
|
|
2237
2112
|
function SwypeLoadingScreen() {
|
|
@@ -3857,7 +3732,7 @@ var dividerTextStyle = (color) => ({
|
|
|
3857
3732
|
color,
|
|
3858
3733
|
whiteSpace: "nowrap"
|
|
3859
3734
|
});
|
|
3860
|
-
var DEFAULT_MAX =
|
|
3735
|
+
var DEFAULT_MAX = 1e7;
|
|
3861
3736
|
var ABSOLUTE_MIN = 0.01;
|
|
3862
3737
|
function SetupScreen({
|
|
3863
3738
|
availableBalance,
|
|
@@ -3872,7 +3747,7 @@ function SetupScreen({
|
|
|
3872
3747
|
error
|
|
3873
3748
|
}) {
|
|
3874
3749
|
const { tokens } = useSwypeConfig();
|
|
3875
|
-
const effectiveMax =
|
|
3750
|
+
const effectiveMax = DEFAULT_MAX;
|
|
3876
3751
|
const effectiveMin = Math.min(ABSOLUTE_MIN, effectiveMax);
|
|
3877
3752
|
const [limit, setLimit] = useState(() => Math.min(availableBalance, effectiveMax));
|
|
3878
3753
|
const [editing, setEditing] = useState(false);
|
|
@@ -4249,8 +4124,7 @@ function DepositScreen({
|
|
|
4249
4124
|
onAuthorizeAccount,
|
|
4250
4125
|
onAddProvider,
|
|
4251
4126
|
onSelectToken,
|
|
4252
|
-
|
|
4253
|
-
onStartSetup
|
|
4127
|
+
selectedSourceLabel
|
|
4254
4128
|
}) {
|
|
4255
4129
|
const { tokens } = useSwypeConfig();
|
|
4256
4130
|
const amount = initialAmount;
|
|
@@ -4258,29 +4132,6 @@ function DepositScreen({
|
|
|
4258
4132
|
const exceedsLimit = amount > remainingLimit && !isLowBalance;
|
|
4259
4133
|
const canDeposit = amount >= MIN_DEPOSIT && !exceedsLimit && !isLowBalance && !processing;
|
|
4260
4134
|
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
4135
|
if (isLowBalance) {
|
|
4285
4136
|
return /* @__PURE__ */ jsxs(
|
|
4286
4137
|
ScreenLayout,
|
|
@@ -4318,7 +4169,7 @@ function DepositScreen({
|
|
|
4318
4169
|
/* @__PURE__ */ jsx("text", { x: "12", y: "16", textAnchor: "middle", fontSize: "12", fill: "#fff", fontWeight: "700", children: "$" })
|
|
4319
4170
|
] }) }),
|
|
4320
4171
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
4321
|
-
/* @__PURE__ */ jsx("div", { style: balanceLabelStyle2(tokens.textMuted), children: "Available" }),
|
|
4172
|
+
/* @__PURE__ */ jsx("div", { style: balanceLabelStyle2(tokens.textMuted), children: selectedSourceLabel ?? "Available" }),
|
|
4322
4173
|
/* @__PURE__ */ jsxs("div", { style: { ...balanceAmountStyle, color: tokens.warning }, children: [
|
|
4323
4174
|
"$",
|
|
4324
4175
|
availableBalance.toFixed(2)
|
|
@@ -4393,10 +4244,7 @@ function DepositScreen({
|
|
|
4393
4244
|
/* @__PURE__ */ jsx("text", { x: "12", y: "16", textAnchor: "middle", fontSize: "12", fill: "#fff", fontWeight: "700", children: "$" })
|
|
4394
4245
|
] }) }),
|
|
4395
4246
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
4396
|
-
/* @__PURE__ */
|
|
4397
|
-
"Paying from ",
|
|
4398
|
-
sourceName
|
|
4399
|
-
] }),
|
|
4247
|
+
/* @__PURE__ */ jsx("div", { style: balanceLabelStyle2(tokens.textMuted), children: selectedSourceLabel ?? `Paying from ${sourceName}` }),
|
|
4400
4248
|
/* @__PURE__ */ jsxs("div", { style: balanceAmountStyle, children: [
|
|
4401
4249
|
"$",
|
|
4402
4250
|
availableBalance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
@@ -4543,29 +4391,6 @@ var switchHintStyle = (color) => ({
|
|
|
4543
4391
|
var outlineBtnWrapStyle = {
|
|
4544
4392
|
marginBottom: 8
|
|
4545
4393
|
};
|
|
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
4394
|
function SuccessScreen({
|
|
4570
4395
|
amount,
|
|
4571
4396
|
currency,
|
|
@@ -5215,6 +5040,28 @@ var waitHintStyle2 = (color) => ({
|
|
|
5215
5040
|
color,
|
|
5216
5041
|
margin: 0
|
|
5217
5042
|
});
|
|
5043
|
+
|
|
5044
|
+
// src/deeplink.ts
|
|
5045
|
+
var IFRAME_CLEANUP_DELAY_MS = 3e3;
|
|
5046
|
+
var LOCATION_FALLBACK_DELAY_MS = 100;
|
|
5047
|
+
function triggerDeeplink(uri) {
|
|
5048
|
+
try {
|
|
5049
|
+
const iframe = document.createElement("iframe");
|
|
5050
|
+
iframe.style.display = "none";
|
|
5051
|
+
iframe.src = uri;
|
|
5052
|
+
document.body.appendChild(iframe);
|
|
5053
|
+
setTimeout(() => {
|
|
5054
|
+
try {
|
|
5055
|
+
document.body.removeChild(iframe);
|
|
5056
|
+
} catch {
|
|
5057
|
+
}
|
|
5058
|
+
}, IFRAME_CLEANUP_DELAY_MS);
|
|
5059
|
+
} catch {
|
|
5060
|
+
}
|
|
5061
|
+
setTimeout(() => {
|
|
5062
|
+
window.location.href = uri;
|
|
5063
|
+
}, LOCATION_FALLBACK_DELAY_MS);
|
|
5064
|
+
}
|
|
5218
5065
|
function OpenWalletScreen({
|
|
5219
5066
|
walletName,
|
|
5220
5067
|
deeplinkUri,
|
|
@@ -5660,12 +5507,12 @@ function StepRenderer({
|
|
|
5660
5507
|
selectedSource,
|
|
5661
5508
|
selectSourceChoices,
|
|
5662
5509
|
selectSourceRecommended,
|
|
5510
|
+
selectSourceAvailableBalance,
|
|
5663
5511
|
authInput,
|
|
5664
5512
|
otpCode,
|
|
5665
5513
|
selectSourceChainName,
|
|
5666
5514
|
selectSourceTokenSymbol,
|
|
5667
5515
|
savingOneTapLimit,
|
|
5668
|
-
pendingSetup,
|
|
5669
5516
|
merchantName,
|
|
5670
5517
|
onBack,
|
|
5671
5518
|
onDismiss,
|
|
@@ -5782,19 +5629,23 @@ function StepRenderer({
|
|
|
5782
5629
|
);
|
|
5783
5630
|
}
|
|
5784
5631
|
if (step === "setup") {
|
|
5785
|
-
const
|
|
5786
|
-
|
|
5632
|
+
const selectSourceTokenCount = selectSourceChoices.reduce(
|
|
5633
|
+
(sum, chain) => sum + chain.tokens.length,
|
|
5634
|
+
0
|
|
5635
|
+
);
|
|
5636
|
+
const effectiveTokenCount = tokenCount > 0 ? tokenCount : selectSourceTokenCount;
|
|
5637
|
+
const effectiveSourceLabel = selectedSourceLabel ?? (selectSourceChainName && selectSourceTokenSymbol ? `${selectSourceTokenSymbol} on ${selectSourceChainName}` : void 0);
|
|
5787
5638
|
return /* @__PURE__ */ jsx(
|
|
5788
5639
|
SetupScreen,
|
|
5789
5640
|
{
|
|
5790
|
-
availableBalance: selectedSource ? selectedSource.balance.available.amount : selectedAccount ? selectedAccount.wallets.reduce((sum, w) => sum + w.balance.available.amount, 0) : maxSourceBalance,
|
|
5791
|
-
tokenCount,
|
|
5641
|
+
availableBalance: selectedSource ? selectedSource.balance.available.amount : selectedAccount ? selectedAccount.wallets.reduce((sum, w) => sum + w.balance.available.amount, 0) : selectSourceAvailableBalance > 0 ? selectSourceAvailableBalance : maxSourceBalance,
|
|
5642
|
+
tokenCount: effectiveTokenCount,
|
|
5792
5643
|
sourceName,
|
|
5793
5644
|
onSetupOneTap: handlers.onSetupOneTap,
|
|
5794
5645
|
onBack: () => handlers.onNavigate("deposit"),
|
|
5795
5646
|
onLogout: handlers.onLogout,
|
|
5796
|
-
onAdvanced:
|
|
5797
|
-
selectedSourceLabel:
|
|
5647
|
+
onAdvanced: handlers.onSelectToken,
|
|
5648
|
+
selectedSourceLabel: effectiveSourceLabel,
|
|
5798
5649
|
loading: savingOneTapLimit,
|
|
5799
5650
|
error: state.error
|
|
5800
5651
|
}
|
|
@@ -5843,8 +5694,7 @@ function StepRenderer({
|
|
|
5843
5694
|
onAuthorizeAccount: handlers.onContinueConnection,
|
|
5844
5695
|
onAddProvider: () => handlers.onNavigate("wallet-picker"),
|
|
5845
5696
|
onSelectToken: handlers.onSelectToken,
|
|
5846
|
-
|
|
5847
|
-
onStartSetup: () => handlers.onNavigate("setup")
|
|
5697
|
+
selectedSourceLabel
|
|
5848
5698
|
}
|
|
5849
5699
|
);
|
|
5850
5700
|
}
|
|
@@ -5876,7 +5726,7 @@ function StepRenderer({
|
|
|
5876
5726
|
);
|
|
5877
5727
|
}
|
|
5878
5728
|
if (step === "select-source") {
|
|
5879
|
-
const
|
|
5729
|
+
const cameFromSetup = state.previousStep === "setup";
|
|
5880
5730
|
return /* @__PURE__ */ jsx(
|
|
5881
5731
|
SelectSourceScreen,
|
|
5882
5732
|
{
|
|
@@ -5886,8 +5736,8 @@ function StepRenderer({
|
|
|
5886
5736
|
recommended: selectSourceRecommended,
|
|
5887
5737
|
onChainChange: handlers.onSelectSourceChainChange,
|
|
5888
5738
|
onTokenChange: handlers.onSetSelectSourceTokenSymbol,
|
|
5889
|
-
onConfirm:
|
|
5890
|
-
onBack:
|
|
5739
|
+
onConfirm: cameFromSetup ? () => handlers.onNavigate("setup") : handlers.onConfirmSelectSource,
|
|
5740
|
+
onBack: cameFromSetup ? () => handlers.onNavigate("setup") : void 0,
|
|
5891
5741
|
onLogout: handlers.onLogout
|
|
5892
5742
|
}
|
|
5893
5743
|
);
|
|
@@ -5937,12 +5787,29 @@ function StepRenderer({
|
|
|
5937
5787
|
selectedAccountId: state.selectedAccountId,
|
|
5938
5788
|
onSelectAccount: handlers.onSelectAccount,
|
|
5939
5789
|
onAuthorizeAccount: handlers.onContinueConnection,
|
|
5940
|
-
onAddProvider: () => handlers.onNavigate("wallet-picker")
|
|
5790
|
+
onAddProvider: () => handlers.onNavigate("wallet-picker"),
|
|
5791
|
+
selectedSourceLabel
|
|
5941
5792
|
}
|
|
5942
5793
|
);
|
|
5943
5794
|
}
|
|
5944
5795
|
return null;
|
|
5945
5796
|
}
|
|
5797
|
+
|
|
5798
|
+
// src/sentry.ts
|
|
5799
|
+
var _mod;
|
|
5800
|
+
function captureException(error) {
|
|
5801
|
+
if (_mod === null) return;
|
|
5802
|
+
if (_mod) {
|
|
5803
|
+
_mod.captureException(error);
|
|
5804
|
+
return;
|
|
5805
|
+
}
|
|
5806
|
+
import('@sentry/react').then((m) => {
|
|
5807
|
+
_mod = m;
|
|
5808
|
+
m.captureException(error);
|
|
5809
|
+
}).catch(() => {
|
|
5810
|
+
_mod = null;
|
|
5811
|
+
});
|
|
5812
|
+
}
|
|
5946
5813
|
var PaymentErrorBoundary = class extends Component {
|
|
5947
5814
|
constructor(props) {
|
|
5948
5815
|
super(props);
|
|
@@ -6011,78 +5878,7 @@ var buttonStyle3 = {
|
|
|
6011
5878
|
fontFamily: "inherit",
|
|
6012
5879
|
cursor: "pointer"
|
|
6013
5880
|
};
|
|
6014
|
-
function
|
|
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();
|
|
5881
|
+
function useDerivedState(state) {
|
|
6086
5882
|
const { sourceType, sourceId } = deriveSourceTypeAndId(state);
|
|
6087
5883
|
const selectedAccount = state.accounts.find((a) => a.id === state.selectedAccountId);
|
|
6088
5884
|
const selectedWallet = selectedAccount?.wallets.find(
|
|
@@ -6132,8 +5928,36 @@ function SwypePaymentInner({
|
|
|
6132
5928
|
}
|
|
6133
5929
|
return count;
|
|
6134
5930
|
}, [state.accounts]);
|
|
6135
|
-
|
|
6136
|
-
|
|
5931
|
+
return {
|
|
5932
|
+
sourceType,
|
|
5933
|
+
sourceId,
|
|
5934
|
+
selectedAccount,
|
|
5935
|
+
selectedWallet,
|
|
5936
|
+
selectedSource,
|
|
5937
|
+
sourceName,
|
|
5938
|
+
sourceAddress,
|
|
5939
|
+
sourceVerified,
|
|
5940
|
+
pendingConnections,
|
|
5941
|
+
depositEligibleAccounts,
|
|
5942
|
+
maxSourceBalance,
|
|
5943
|
+
tokenCount
|
|
5944
|
+
};
|
|
5945
|
+
}
|
|
5946
|
+
function useAuthHandlers(dispatch, verificationTarget) {
|
|
5947
|
+
const {
|
|
5948
|
+
sendCode: sendEmailCode,
|
|
5949
|
+
loginWithCode: loginWithEmailCode,
|
|
5950
|
+
state: emailLoginState
|
|
5951
|
+
} = useLoginWithEmail();
|
|
5952
|
+
const {
|
|
5953
|
+
sendCode: sendSmsCode,
|
|
5954
|
+
loginWithCode: loginWithSmsCode,
|
|
5955
|
+
state: smsLoginState
|
|
5956
|
+
} = useLoginWithSms();
|
|
5957
|
+
const [authInput, setAuthInput] = useState("");
|
|
5958
|
+
const [otpCode, setOtpCode] = useState("");
|
|
5959
|
+
const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
|
|
5960
|
+
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
5961
|
const handleSendLoginCode = useCallback(async () => {
|
|
6138
5962
|
const normalizedIdentifier = normalizeAuthIdentifier(authInput);
|
|
6139
5963
|
if (!normalizedIdentifier) {
|
|
@@ -6155,9 +5979,9 @@ function SwypePaymentInner({
|
|
|
6155
5979
|
error: err instanceof Error ? err.message : "Failed to send verification code"
|
|
6156
5980
|
});
|
|
6157
5981
|
}
|
|
6158
|
-
}, [authInput, sendEmailCode, sendSmsCode]);
|
|
5982
|
+
}, [authInput, sendEmailCode, sendSmsCode, dispatch]);
|
|
6159
5983
|
const handleVerifyLoginCode = useCallback(async () => {
|
|
6160
|
-
if (!
|
|
5984
|
+
if (!verificationTarget) return;
|
|
6161
5985
|
const trimmedCode = otpCode.trim();
|
|
6162
5986
|
if (!/^\d{6}$/.test(trimmedCode)) {
|
|
6163
5987
|
dispatch({ type: "SET_ERROR", error: "Enter the 6-digit verification code." });
|
|
@@ -6165,7 +5989,7 @@ function SwypePaymentInner({
|
|
|
6165
5989
|
}
|
|
6166
5990
|
dispatch({ type: "SET_ERROR", error: null });
|
|
6167
5991
|
try {
|
|
6168
|
-
if (
|
|
5992
|
+
if (verificationTarget.kind === "email") {
|
|
6169
5993
|
await loginWithEmailCode({ code: trimmedCode });
|
|
6170
5994
|
} else {
|
|
6171
5995
|
await loginWithSmsCode({ code: trimmedCode });
|
|
@@ -6177,15 +6001,15 @@ function SwypePaymentInner({
|
|
|
6177
6001
|
error: err instanceof Error ? err.message : "Failed to verify code"
|
|
6178
6002
|
});
|
|
6179
6003
|
}
|
|
6180
|
-
}, [
|
|
6004
|
+
}, [verificationTarget, otpCode, loginWithEmailCode, loginWithSmsCode, dispatch]);
|
|
6181
6005
|
const handleResendLoginCode = useCallback(async () => {
|
|
6182
|
-
if (!
|
|
6006
|
+
if (!verificationTarget) return;
|
|
6183
6007
|
dispatch({ type: "SET_ERROR", error: null });
|
|
6184
6008
|
try {
|
|
6185
|
-
if (
|
|
6186
|
-
await sendEmailCode({ email:
|
|
6009
|
+
if (verificationTarget.kind === "email") {
|
|
6010
|
+
await sendEmailCode({ email: verificationTarget.value });
|
|
6187
6011
|
} else {
|
|
6188
|
-
await sendSmsCode({ phoneNumber:
|
|
6012
|
+
await sendSmsCode({ phoneNumber: verificationTarget.value });
|
|
6189
6013
|
}
|
|
6190
6014
|
} catch (err) {
|
|
6191
6015
|
captureException(err);
|
|
@@ -6194,7 +6018,68 @@ function SwypePaymentInner({
|
|
|
6194
6018
|
error: err instanceof Error ? err.message : "Failed to resend code"
|
|
6195
6019
|
});
|
|
6196
6020
|
}
|
|
6197
|
-
}, [
|
|
6021
|
+
}, [verificationTarget, sendEmailCode, sendSmsCode, dispatch]);
|
|
6022
|
+
return {
|
|
6023
|
+
authInput,
|
|
6024
|
+
otpCode,
|
|
6025
|
+
activeOtpStatus,
|
|
6026
|
+
activeOtpErrorMessage,
|
|
6027
|
+
setAuthInput,
|
|
6028
|
+
setOtpCode,
|
|
6029
|
+
handleSendLoginCode,
|
|
6030
|
+
handleVerifyLoginCode,
|
|
6031
|
+
handleResendLoginCode
|
|
6032
|
+
};
|
|
6033
|
+
}
|
|
6034
|
+
|
|
6035
|
+
// src/mobileFlow.ts
|
|
6036
|
+
function hasActiveWallet(accounts) {
|
|
6037
|
+
return accounts.some((account) => account.wallets.some((wallet) => wallet.status === "ACTIVE"));
|
|
6038
|
+
}
|
|
6039
|
+
function resolvePostAuthStep(state) {
|
|
6040
|
+
if (!state.hasPasskey) {
|
|
6041
|
+
return { step: "create-passkey", clearPersistedFlow: false };
|
|
6042
|
+
}
|
|
6043
|
+
if (state.persistedMobileFlow) {
|
|
6044
|
+
if (state.persistedMobileFlow.isReauthorization) {
|
|
6045
|
+
return { step: "open-wallet", clearPersistedFlow: false };
|
|
6046
|
+
}
|
|
6047
|
+
if (state.persistedMobileFlow.isSetup && hasActiveWallet(state.accounts)) {
|
|
6048
|
+
return { step: "deposit", clearPersistedFlow: true };
|
|
6049
|
+
}
|
|
6050
|
+
return { step: "open-wallet", clearPersistedFlow: false };
|
|
6051
|
+
}
|
|
6052
|
+
if (state.mobileSetupInProgress && !hasActiveWallet(state.accounts)) {
|
|
6053
|
+
return { step: "open-wallet", clearPersistedFlow: false };
|
|
6054
|
+
}
|
|
6055
|
+
if ((state.accounts.length === 0 || !hasActiveWallet(state.accounts)) && !state.connectingNewAccount) {
|
|
6056
|
+
return { step: "wallet-picker", clearPersistedFlow: false };
|
|
6057
|
+
}
|
|
6058
|
+
return { step: "deposit", clearPersistedFlow: false };
|
|
6059
|
+
}
|
|
6060
|
+
function resolveRestoredMobileFlow(transferStatus, isSetup) {
|
|
6061
|
+
if (transferStatus === "AUTHORIZED") {
|
|
6062
|
+
return isSetup ? { kind: "resume-setup-deposit", step: "deposit", clearPersistedFlow: true } : { kind: "resume-confirm-sign", step: "confirm-sign", clearPersistedFlow: true };
|
|
6063
|
+
}
|
|
6064
|
+
if (transferStatus === "COMPLETED") {
|
|
6065
|
+
return { kind: "resume-success", step: "success", clearPersistedFlow: true };
|
|
6066
|
+
}
|
|
6067
|
+
if (transferStatus === "FAILED") {
|
|
6068
|
+
return { kind: "resume-failed", step: "success", clearPersistedFlow: true };
|
|
6069
|
+
}
|
|
6070
|
+
if (transferStatus === "SENDING" || transferStatus === "SENT") {
|
|
6071
|
+
return { kind: "resume-processing", step: "processing", clearPersistedFlow: true };
|
|
6072
|
+
}
|
|
6073
|
+
if (isSetup) {
|
|
6074
|
+
return { kind: "resume-stale-setup", step: "wallet-picker", clearPersistedFlow: true };
|
|
6075
|
+
}
|
|
6076
|
+
return { kind: "resume-open-wallet", step: "open-wallet", clearPersistedFlow: false };
|
|
6077
|
+
}
|
|
6078
|
+
|
|
6079
|
+
// src/hooks/usePasskeyHandlers.ts
|
|
6080
|
+
function usePasskeyHandlers(dispatch, apiBaseUrl, accounts, knownCredentialIds, mobileSetupFlowRef) {
|
|
6081
|
+
const { user, getAccessToken } = usePrivy();
|
|
6082
|
+
const checkingPasskeyRef = useRef(false);
|
|
6198
6083
|
const completePasskeyRegistration = useCallback(async (credentialId, publicKey) => {
|
|
6199
6084
|
const token = await getAccessToken();
|
|
6200
6085
|
if (!token) throw new Error("Not authenticated");
|
|
@@ -6203,14 +6088,14 @@ function SwypePaymentInner({
|
|
|
6203
6088
|
window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
|
|
6204
6089
|
const resolved = resolvePostAuthStep({
|
|
6205
6090
|
hasPasskey: true,
|
|
6206
|
-
accounts
|
|
6091
|
+
accounts,
|
|
6207
6092
|
persistedMobileFlow: loadMobileFlowState(),
|
|
6208
6093
|
mobileSetupInProgress: mobileSetupFlowRef.current,
|
|
6209
6094
|
connectingNewAccount: false
|
|
6210
6095
|
});
|
|
6211
6096
|
if (resolved.clearPersistedFlow) clearMobileFlowState();
|
|
6212
6097
|
dispatch({ type: "NAVIGATE", step: resolved.step });
|
|
6213
|
-
}, [getAccessToken, apiBaseUrl,
|
|
6098
|
+
}, [getAccessToken, apiBaseUrl, accounts, mobileSetupFlowRef, dispatch]);
|
|
6214
6099
|
const handleRegisterPasskey = useCallback(async () => {
|
|
6215
6100
|
dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
|
|
6216
6101
|
dispatch({ type: "SET_ERROR", error: null });
|
|
@@ -6234,7 +6119,7 @@ function SwypePaymentInner({
|
|
|
6234
6119
|
} finally {
|
|
6235
6120
|
dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
|
|
6236
6121
|
}
|
|
6237
|
-
}, [user, completePasskeyRegistration]);
|
|
6122
|
+
}, [user, completePasskeyRegistration, dispatch]);
|
|
6238
6123
|
const handleCreatePasskeyViaPopup = useCallback(async () => {
|
|
6239
6124
|
dispatch({ type: "SET_REGISTERING_PASSKEY", value: true });
|
|
6240
6125
|
dispatch({ type: "SET_ERROR", error: null });
|
|
@@ -6252,7 +6137,7 @@ function SwypePaymentInner({
|
|
|
6252
6137
|
localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
|
|
6253
6138
|
const resolved = resolvePostAuthStep({
|
|
6254
6139
|
hasPasskey: true,
|
|
6255
|
-
accounts
|
|
6140
|
+
accounts,
|
|
6256
6141
|
persistedMobileFlow: loadMobileFlowState(),
|
|
6257
6142
|
mobileSetupInProgress: mobileSetupFlowRef.current,
|
|
6258
6143
|
connectingNewAccount: false
|
|
@@ -6268,14 +6153,14 @@ function SwypePaymentInner({
|
|
|
6268
6153
|
} finally {
|
|
6269
6154
|
dispatch({ type: "SET_REGISTERING_PASSKEY", value: false });
|
|
6270
6155
|
}
|
|
6271
|
-
}, [user, getAccessToken, apiBaseUrl,
|
|
6156
|
+
}, [user, getAccessToken, apiBaseUrl, accounts, mobileSetupFlowRef, dispatch]);
|
|
6272
6157
|
const handleVerifyPasskeyViaPopup = useCallback(async () => {
|
|
6273
6158
|
dispatch({ type: "SET_VERIFYING_PASSKEY", value: true });
|
|
6274
6159
|
dispatch({ type: "SET_ERROR", error: null });
|
|
6275
6160
|
try {
|
|
6276
6161
|
const token = await getAccessToken();
|
|
6277
6162
|
const matched = await findDevicePasskeyViaPopup({
|
|
6278
|
-
credentialIds:
|
|
6163
|
+
credentialIds: knownCredentialIds,
|
|
6279
6164
|
rpId: resolvePasskeyRpId(),
|
|
6280
6165
|
authToken: token ?? void 0,
|
|
6281
6166
|
apiBaseUrl
|
|
@@ -6289,7 +6174,7 @@ function SwypePaymentInner({
|
|
|
6289
6174
|
}
|
|
6290
6175
|
const resolved = resolvePostAuthStep({
|
|
6291
6176
|
hasPasskey: true,
|
|
6292
|
-
accounts
|
|
6177
|
+
accounts,
|
|
6293
6178
|
persistedMobileFlow: loadMobileFlowState(),
|
|
6294
6179
|
mobileSetupInProgress: mobileSetupFlowRef.current,
|
|
6295
6180
|
connectingNewAccount: false
|
|
@@ -6311,44 +6196,48 @@ function SwypePaymentInner({
|
|
|
6311
6196
|
} finally {
|
|
6312
6197
|
dispatch({ type: "SET_VERIFYING_PASSKEY", value: false });
|
|
6313
6198
|
}
|
|
6314
|
-
}, [
|
|
6199
|
+
}, [knownCredentialIds, getAccessToken, apiBaseUrl, accounts, mobileSetupFlowRef, dispatch]);
|
|
6200
|
+
return {
|
|
6201
|
+
handleRegisterPasskey,
|
|
6202
|
+
handleCreatePasskeyViaPopup,
|
|
6203
|
+
handleVerifyPasskeyViaPopup,
|
|
6204
|
+
checkingPasskeyRef
|
|
6205
|
+
};
|
|
6206
|
+
}
|
|
6207
|
+
function useTransferHandlers(deps) {
|
|
6208
|
+
const {
|
|
6209
|
+
dispatch,
|
|
6210
|
+
getAccessToken,
|
|
6211
|
+
apiBaseUrl,
|
|
6212
|
+
depositAmount,
|
|
6213
|
+
destination,
|
|
6214
|
+
idempotencyKey,
|
|
6215
|
+
merchantAuthorization,
|
|
6216
|
+
onComplete,
|
|
6217
|
+
onError,
|
|
6218
|
+
polling,
|
|
6219
|
+
transferSigning,
|
|
6220
|
+
sourceType,
|
|
6221
|
+
sourceId,
|
|
6222
|
+
sourceTokenAddress,
|
|
6223
|
+
activeCredentialId,
|
|
6224
|
+
selectedAccountId,
|
|
6225
|
+
transfer,
|
|
6226
|
+
accounts
|
|
6227
|
+
} = deps;
|
|
6228
|
+
const processingStartedAtRef = useRef(null);
|
|
6229
|
+
const pollingTransferIdRef = useRef(null);
|
|
6315
6230
|
const reloadAccounts = useCallback(async () => {
|
|
6316
6231
|
const token = await getAccessToken();
|
|
6317
|
-
if (!token || !
|
|
6232
|
+
if (!token || !activeCredentialId) return;
|
|
6318
6233
|
const [accts, prov] = await Promise.all([
|
|
6319
|
-
fetchAccounts(apiBaseUrl, token,
|
|
6234
|
+
fetchAccounts(apiBaseUrl, token, activeCredentialId),
|
|
6320
6235
|
fetchProviders(apiBaseUrl, token)
|
|
6321
6236
|
]);
|
|
6322
6237
|
const parsedAmt = depositAmount != null ? depositAmount : 0;
|
|
6323
|
-
const defaults = resolveDepositSelection(accts, parsedAmt,
|
|
6238
|
+
const defaults = resolveDepositSelection(accts, parsedAmt, selectedAccountId);
|
|
6324
6239
|
dispatch({ type: "ACCOUNTS_RELOADED", accounts: accts, providers: prov, defaults });
|
|
6325
|
-
}, [getAccessToken,
|
|
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;
|
|
6240
|
+
}, [getAccessToken, activeCredentialId, selectedAccountId, apiBaseUrl, depositAmount, dispatch]);
|
|
6352
6241
|
const handlePay = useCallback(async (payAmount, sourceOverrides) => {
|
|
6353
6242
|
if (isNaN(payAmount) || payAmount < MIN_SEND_AMOUNT_USD) {
|
|
6354
6243
|
dispatch({ type: "SET_ERROR", error: `Minimum amount is $${MIN_SEND_AMOUNT_USD.toFixed(2)}.` });
|
|
@@ -6358,7 +6247,7 @@ function SwypePaymentInner({
|
|
|
6358
6247
|
dispatch({ type: "SET_ERROR", error: "No account or provider selected." });
|
|
6359
6248
|
return;
|
|
6360
6249
|
}
|
|
6361
|
-
if (!
|
|
6250
|
+
if (!activeCredentialId) {
|
|
6362
6251
|
dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
|
|
6363
6252
|
dispatch({ type: "NAVIGATE", step: "create-passkey" });
|
|
6364
6253
|
return;
|
|
@@ -6366,10 +6255,10 @@ function SwypePaymentInner({
|
|
|
6366
6255
|
dispatch({ type: "PAY_STARTED", isSetupRedirect: false });
|
|
6367
6256
|
processingStartedAtRef.current = Date.now();
|
|
6368
6257
|
try {
|
|
6369
|
-
if (
|
|
6370
|
-
const signedTransfer2 = await transferSigning.signTransfer(
|
|
6258
|
+
if (transfer?.status === "AUTHORIZED") {
|
|
6259
|
+
const signedTransfer2 = await transferSigning.signTransfer(transfer.id);
|
|
6371
6260
|
dispatch({ type: "TRANSFER_SIGNED", transfer: signedTransfer2 });
|
|
6372
|
-
polling.startPolling(
|
|
6261
|
+
polling.startPolling(transfer.id);
|
|
6373
6262
|
return;
|
|
6374
6263
|
}
|
|
6375
6264
|
const token = await getAccessToken();
|
|
@@ -6377,7 +6266,7 @@ function SwypePaymentInner({
|
|
|
6377
6266
|
let effectiveSourceType = sourceOverrides?.sourceType ?? sourceType;
|
|
6378
6267
|
let effectiveSourceId = sourceOverrides?.sourceId ?? sourceId;
|
|
6379
6268
|
if (effectiveSourceType === "accountId") {
|
|
6380
|
-
const acct =
|
|
6269
|
+
const acct = accounts.find((a) => a.id === effectiveSourceId);
|
|
6381
6270
|
const preferredWallet = acct ? getPreferredDepositWallet(acct, payAmount) : null;
|
|
6382
6271
|
if (preferredWallet?.status === "ACTIVE") {
|
|
6383
6272
|
effectiveSourceType = "walletId";
|
|
@@ -6386,10 +6275,11 @@ function SwypePaymentInner({
|
|
|
6386
6275
|
}
|
|
6387
6276
|
const t = await createTransfer(apiBaseUrl, token, {
|
|
6388
6277
|
id: idempotencyKey,
|
|
6389
|
-
credentialId:
|
|
6278
|
+
credentialId: activeCredentialId,
|
|
6390
6279
|
merchantAuthorization,
|
|
6391
6280
|
sourceType: effectiveSourceType,
|
|
6392
6281
|
sourceId: effectiveSourceId,
|
|
6282
|
+
sourceTokenAddress,
|
|
6393
6283
|
destination,
|
|
6394
6284
|
amount: payAmount
|
|
6395
6285
|
});
|
|
@@ -6409,11 +6299,7 @@ function SwypePaymentInner({
|
|
|
6409
6299
|
} catch (err) {
|
|
6410
6300
|
captureException(err);
|
|
6411
6301
|
const msg = err instanceof Error ? err.message : "Transfer failed";
|
|
6412
|
-
dispatch({
|
|
6413
|
-
type: "PAY_ERROR",
|
|
6414
|
-
error: msg,
|
|
6415
|
-
fallbackStep: "deposit"
|
|
6416
|
-
});
|
|
6302
|
+
dispatch({ type: "PAY_ERROR", error: msg, fallbackStep: "deposit" });
|
|
6417
6303
|
onError?.(msg);
|
|
6418
6304
|
} finally {
|
|
6419
6305
|
dispatch({ type: "PAY_ENDED" });
|
|
@@ -6421,9 +6307,10 @@ function SwypePaymentInner({
|
|
|
6421
6307
|
}, [
|
|
6422
6308
|
sourceId,
|
|
6423
6309
|
sourceType,
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6310
|
+
sourceTokenAddress,
|
|
6311
|
+
activeCredentialId,
|
|
6312
|
+
transfer,
|
|
6313
|
+
accounts,
|
|
6427
6314
|
destination,
|
|
6428
6315
|
apiBaseUrl,
|
|
6429
6316
|
getAccessToken,
|
|
@@ -6432,185 +6319,133 @@ function SwypePaymentInner({
|
|
|
6432
6319
|
onError,
|
|
6433
6320
|
onComplete,
|
|
6434
6321
|
idempotencyKey,
|
|
6435
|
-
merchantAuthorization
|
|
6322
|
+
merchantAuthorization,
|
|
6323
|
+
dispatch
|
|
6436
6324
|
]);
|
|
6437
|
-
const
|
|
6438
|
-
|
|
6439
|
-
|
|
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 });
|
|
6325
|
+
const handleConfirmSign = useCallback(async () => {
|
|
6326
|
+
const t = transfer ?? polling.transfer;
|
|
6327
|
+
if (!t) return;
|
|
6454
6328
|
try {
|
|
6455
|
-
const
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
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
|
-
}
|
|
6329
|
+
const signedTransfer = await transferSigning.signTransfer(t.id);
|
|
6330
|
+
clearMobileFlowState();
|
|
6331
|
+
dispatch({ type: "CONFIRM_SIGN_SUCCESS", transfer: signedTransfer });
|
|
6332
|
+
polling.startPolling(t.id);
|
|
6488
6333
|
} catch (err) {
|
|
6489
6334
|
captureException(err);
|
|
6490
|
-
const msg = err instanceof Error ? err.message : "Failed to
|
|
6335
|
+
const msg = err instanceof Error ? err.message : "Failed to sign transfer";
|
|
6491
6336
|
dispatch({ type: "SET_ERROR", error: msg });
|
|
6492
6337
|
onError?.(msg);
|
|
6493
|
-
} finally {
|
|
6494
|
-
dispatch({ type: "SET_INCREASING_LIMIT", value: false });
|
|
6495
6338
|
}
|
|
6496
|
-
}, [
|
|
6497
|
-
|
|
6498
|
-
state.activeCredentialId,
|
|
6499
|
-
state.accounts,
|
|
6500
|
-
state.providers,
|
|
6501
|
-
apiBaseUrl,
|
|
6502
|
-
getAccessToken,
|
|
6503
|
-
authExecutor,
|
|
6504
|
-
useWalletConnectorProp,
|
|
6339
|
+
}, [transfer, polling.transfer, polling.startPolling, transferSigning, onError, dispatch]);
|
|
6340
|
+
return {
|
|
6505
6341
|
reloadAccounts,
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
}
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
const
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
if (!
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6342
|
+
handlePay,
|
|
6343
|
+
handleConfirmSign,
|
|
6344
|
+
processingStartedAtRef,
|
|
6345
|
+
pollingTransferIdRef
|
|
6346
|
+
};
|
|
6347
|
+
}
|
|
6348
|
+
function useSourceSelectionHandlers(dispatch, authExecutor) {
|
|
6349
|
+
const [selectSourceChainName, setSelectSourceChainName] = useState("");
|
|
6350
|
+
const [selectSourceTokenSymbol, setSelectSourceTokenSymbol] = useState("");
|
|
6351
|
+
const initializedSelectSourceActionRef = useRef(null);
|
|
6352
|
+
const preSelectSourceStepRef = useRef(null);
|
|
6353
|
+
const pendingSelectSourceAction = authExecutor.pendingSelectSource;
|
|
6354
|
+
const selectSourceChoices = useMemo(() => {
|
|
6355
|
+
if (!pendingSelectSourceAction) return [];
|
|
6356
|
+
const options = pendingSelectSourceAction.metadata?.options ?? [];
|
|
6357
|
+
return buildSelectSourceChoices(options);
|
|
6358
|
+
}, [pendingSelectSourceAction]);
|
|
6359
|
+
const selectSourceRecommended = useMemo(() => {
|
|
6360
|
+
if (!pendingSelectSourceAction) return null;
|
|
6361
|
+
return pendingSelectSourceAction.metadata?.recommended ?? null;
|
|
6362
|
+
}, [pendingSelectSourceAction]);
|
|
6363
|
+
const selectSourceAvailableBalance = useMemo(() => {
|
|
6364
|
+
if (!pendingSelectSourceAction) return 0;
|
|
6365
|
+
const options = pendingSelectSourceAction.metadata?.options ?? [];
|
|
6366
|
+
const recommended = selectSourceRecommended;
|
|
6367
|
+
if (recommended) {
|
|
6368
|
+
const match = options.find(
|
|
6369
|
+
(opt) => opt.chainName === recommended.chainName && opt.tokenSymbol === recommended.tokenSymbol
|
|
6370
|
+
);
|
|
6371
|
+
if (match) return Number(match.rawBalance) / Math.pow(10, match.decimals);
|
|
6523
6372
|
}
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6373
|
+
let max = 0;
|
|
6374
|
+
for (const opt of options) {
|
|
6375
|
+
const bal = Number(opt.rawBalance) / Math.pow(10, opt.decimals);
|
|
6376
|
+
if (bal > max) max = bal;
|
|
6528
6377
|
}
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
{ tokenAddress, chainId }
|
|
6378
|
+
return max;
|
|
6379
|
+
}, [pendingSelectSourceAction, selectSourceRecommended]);
|
|
6380
|
+
const handleSelectSourceChainChange = useCallback(
|
|
6381
|
+
(chainName) => {
|
|
6382
|
+
setSelectSourceChainName(chainName);
|
|
6383
|
+
const chain = selectSourceChoices.find((c) => c.chainName === chainName);
|
|
6384
|
+
if (!chain || chain.tokens.length === 0) return;
|
|
6385
|
+
const recommendedToken = selectSourceRecommended?.chainName === chainName ? selectSourceRecommended.tokenSymbol : null;
|
|
6386
|
+
const hasRecommended = !!recommendedToken && chain.tokens.some((t) => t.tokenSymbol === recommendedToken);
|
|
6387
|
+
setSelectSourceTokenSymbol(
|
|
6388
|
+
hasRecommended ? recommendedToken : chain.tokens[0].tokenSymbol
|
|
6541
6389
|
);
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6390
|
+
},
|
|
6391
|
+
[selectSourceChoices, selectSourceRecommended]
|
|
6392
|
+
);
|
|
6393
|
+
const handleConfirmSelectSource = useCallback(() => {
|
|
6394
|
+
authExecutor.resolveSelectSource({
|
|
6395
|
+
chainName: selectSourceChainName,
|
|
6396
|
+
tokenSymbol: selectSourceTokenSymbol
|
|
6397
|
+
});
|
|
6398
|
+
}, [authExecutor, selectSourceChainName, selectSourceTokenSymbol]);
|
|
6399
|
+
return {
|
|
6400
|
+
selectSourceChainName,
|
|
6401
|
+
selectSourceTokenSymbol,
|
|
6402
|
+
setSelectSourceChainName,
|
|
6403
|
+
setSelectSourceTokenSymbol,
|
|
6404
|
+
selectSourceChoices,
|
|
6405
|
+
selectSourceRecommended,
|
|
6406
|
+
selectSourceAvailableBalance,
|
|
6407
|
+
handleSelectSourceChainChange,
|
|
6408
|
+
handleConfirmSelectSource,
|
|
6409
|
+
pendingSelectSourceAction,
|
|
6410
|
+
initializedSelectSourceActionRef,
|
|
6411
|
+
preSelectSourceStepRef
|
|
6412
|
+
};
|
|
6413
|
+
}
|
|
6414
|
+
function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransferIdRef, stateTransfer, refs) {
|
|
6415
|
+
const {
|
|
6416
|
+
mobileSetupFlowRef,
|
|
6417
|
+
handlingMobileReturnRef,
|
|
6418
|
+
loadingDataRef
|
|
6419
|
+
} = refs;
|
|
6420
|
+
const handleAuthorizedMobileReturn = useCallback(async (authorizedTransfer, isSetup) => {
|
|
6421
|
+
if (handlingMobileReturnRef.current) return;
|
|
6422
|
+
handlingMobileReturnRef.current = true;
|
|
6423
|
+
polling.stopPolling();
|
|
6424
|
+
if (isSetup) {
|
|
6425
|
+
mobileSetupFlowRef.current = false;
|
|
6426
|
+
clearMobileFlowState();
|
|
6427
|
+
try {
|
|
6428
|
+
await reloadAccounts();
|
|
6429
|
+
loadingDataRef.current = false;
|
|
6430
|
+
dispatch({ type: "MOBILE_SETUP_COMPLETE", transfer: authorizedTransfer });
|
|
6431
|
+
} catch (err) {
|
|
6547
6432
|
handlingMobileReturnRef.current = false;
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
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 }
|
|
6433
|
+
dispatch({
|
|
6434
|
+
type: "SET_ERROR",
|
|
6435
|
+
error: err instanceof Error ? err.message : "Wallet authorized, but we could not refresh your account yet."
|
|
6560
6436
|
});
|
|
6561
|
-
dispatch({ type: "
|
|
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" });
|
|
6437
|
+
dispatch({ type: "NAVIGATE", step: "open-wallet" });
|
|
6573
6438
|
}
|
|
6574
|
-
|
|
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);
|
|
6439
|
+
return;
|
|
6608
6440
|
}
|
|
6609
|
-
|
|
6441
|
+
mobileSetupFlowRef.current = false;
|
|
6442
|
+
clearMobileFlowState();
|
|
6443
|
+
dispatch({ type: "MOBILE_SIGN_READY", transfer: authorizedTransfer });
|
|
6444
|
+
}, [polling.stopPolling, reloadAccounts, dispatch]);
|
|
6610
6445
|
const handleRetryMobileStatus = useCallback(() => {
|
|
6611
6446
|
dispatch({ type: "SET_ERROR", error: null });
|
|
6612
6447
|
handlingMobileReturnRef.current = false;
|
|
6613
|
-
const currentTransfer = polling.transfer ??
|
|
6448
|
+
const currentTransfer = polling.transfer ?? stateTransfer;
|
|
6614
6449
|
if (currentTransfer?.status === "AUTHORIZED") {
|
|
6615
6450
|
void handleAuthorizedMobileReturn(currentTransfer, mobileSetupFlowRef.current);
|
|
6616
6451
|
return;
|
|
@@ -6619,15 +6454,57 @@ function SwypePaymentInner({
|
|
|
6619
6454
|
if (transferIdToResume) {
|
|
6620
6455
|
polling.startPolling(transferIdToResume);
|
|
6621
6456
|
}
|
|
6622
|
-
}, [handleAuthorizedMobileReturn, polling,
|
|
6457
|
+
}, [handleAuthorizedMobileReturn, polling, stateTransfer, pollingTransferIdRef, dispatch]);
|
|
6458
|
+
return {
|
|
6459
|
+
handleAuthorizedMobileReturn,
|
|
6460
|
+
handleRetryMobileStatus
|
|
6461
|
+
};
|
|
6462
|
+
}
|
|
6463
|
+
|
|
6464
|
+
// src/walletFlow.ts
|
|
6465
|
+
var MOBILE_USER_AGENT_PATTERN = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
|
|
6466
|
+
function isMobileUserAgent(userAgent) {
|
|
6467
|
+
if (!userAgent) {
|
|
6468
|
+
return false;
|
|
6469
|
+
}
|
|
6470
|
+
return MOBILE_USER_AGENT_PATTERN.test(userAgent);
|
|
6471
|
+
}
|
|
6472
|
+
function shouldUseWalletConnector(options) {
|
|
6473
|
+
return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
|
|
6474
|
+
}
|
|
6475
|
+
|
|
6476
|
+
// src/hooks/useProviderHandlers.ts
|
|
6477
|
+
function useProviderHandlers(deps) {
|
|
6478
|
+
const {
|
|
6479
|
+
dispatch,
|
|
6480
|
+
getAccessToken,
|
|
6481
|
+
apiBaseUrl,
|
|
6482
|
+
depositAmount,
|
|
6483
|
+
useWalletConnectorProp,
|
|
6484
|
+
activeCredentialId,
|
|
6485
|
+
selectedAccountId,
|
|
6486
|
+
selectedWalletId,
|
|
6487
|
+
selectedTokenSymbol,
|
|
6488
|
+
chains,
|
|
6489
|
+
accounts,
|
|
6490
|
+
providers,
|
|
6491
|
+
authExecutor,
|
|
6492
|
+
reloadAccounts,
|
|
6493
|
+
onError,
|
|
6494
|
+
mobileSetupFlowRef,
|
|
6495
|
+
handlingMobileReturnRef,
|
|
6496
|
+
setupAccountIdRef,
|
|
6497
|
+
reauthSessionIdRef,
|
|
6498
|
+
reauthTokenRef
|
|
6499
|
+
} = deps;
|
|
6623
6500
|
const handleSelectProvider = useCallback(async (providerId) => {
|
|
6624
6501
|
dispatch({ type: "SELECT_PROVIDER", providerId });
|
|
6625
|
-
if (!
|
|
6502
|
+
if (!activeCredentialId) {
|
|
6626
6503
|
dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
|
|
6627
6504
|
dispatch({ type: "NAVIGATE", step: "create-passkey" });
|
|
6628
6505
|
return;
|
|
6629
6506
|
}
|
|
6630
|
-
const provider =
|
|
6507
|
+
const provider = providers.find((p) => p.id === providerId);
|
|
6631
6508
|
const providerName = provider?.name ?? "Wallet";
|
|
6632
6509
|
const isMobile = !shouldUseWalletConnector({
|
|
6633
6510
|
useWalletConnector: useWalletConnectorProp,
|
|
@@ -6646,7 +6523,7 @@ function SwypePaymentInner({
|
|
|
6646
6523
|
const account = await createAccount(apiBaseUrl, token, {
|
|
6647
6524
|
id: accountId,
|
|
6648
6525
|
name: providerName,
|
|
6649
|
-
credentialId:
|
|
6526
|
+
credentialId: activeCredentialId,
|
|
6650
6527
|
providerId
|
|
6651
6528
|
});
|
|
6652
6529
|
const session = account.authorizationSessions?.[0];
|
|
@@ -6678,29 +6555,33 @@ function SwypePaymentInner({
|
|
|
6678
6555
|
dispatch({ type: "PAY_ENDED" });
|
|
6679
6556
|
}
|
|
6680
6557
|
}, [
|
|
6681
|
-
|
|
6682
|
-
|
|
6558
|
+
activeCredentialId,
|
|
6559
|
+
providers,
|
|
6683
6560
|
apiBaseUrl,
|
|
6684
6561
|
getAccessToken,
|
|
6685
6562
|
authExecutor,
|
|
6686
6563
|
useWalletConnectorProp,
|
|
6687
6564
|
reloadAccounts,
|
|
6688
|
-
onError
|
|
6565
|
+
onError,
|
|
6566
|
+
dispatch,
|
|
6567
|
+
mobileSetupFlowRef,
|
|
6568
|
+
handlingMobileReturnRef,
|
|
6569
|
+
setupAccountIdRef
|
|
6689
6570
|
]);
|
|
6690
6571
|
const handleContinueConnection = useCallback(
|
|
6691
6572
|
(accountId) => {
|
|
6692
|
-
const acct =
|
|
6573
|
+
const acct = accounts.find((a) => a.id === accountId);
|
|
6693
6574
|
if (!acct) return;
|
|
6694
|
-
const matchedProvider =
|
|
6575
|
+
const matchedProvider = providers.find((p) => p.name === acct.name);
|
|
6695
6576
|
if (matchedProvider) {
|
|
6696
6577
|
handleSelectProvider(matchedProvider.id);
|
|
6697
6578
|
}
|
|
6698
6579
|
},
|
|
6699
|
-
[
|
|
6580
|
+
[accounts, providers, handleSelectProvider]
|
|
6700
6581
|
);
|
|
6701
6582
|
const handleSelectAccount = useCallback(
|
|
6702
6583
|
(accountId) => {
|
|
6703
|
-
const acct =
|
|
6584
|
+
const acct = accounts.find((a) => a.id === accountId);
|
|
6704
6585
|
if (!acct) return;
|
|
6705
6586
|
const activeWallet = getPreferredDepositWallet(acct, depositAmount ?? 0);
|
|
6706
6587
|
dispatch({
|
|
@@ -6709,8 +6590,206 @@ function SwypePaymentInner({
|
|
|
6709
6590
|
walletId: activeWallet?.id ?? null
|
|
6710
6591
|
});
|
|
6711
6592
|
},
|
|
6712
|
-
[
|
|
6593
|
+
[accounts, depositAmount, dispatch]
|
|
6713
6594
|
);
|
|
6595
|
+
const handleIncreaseLimit = useCallback(async () => {
|
|
6596
|
+
if (!selectedAccountId) {
|
|
6597
|
+
dispatch({ type: "SET_ERROR", error: "No account selected." });
|
|
6598
|
+
return;
|
|
6599
|
+
}
|
|
6600
|
+
if (!activeCredentialId) {
|
|
6601
|
+
dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
|
|
6602
|
+
dispatch({ type: "NAVIGATE", step: "create-passkey" });
|
|
6603
|
+
return;
|
|
6604
|
+
}
|
|
6605
|
+
const acct = accounts.find((a) => a.id === selectedAccountId);
|
|
6606
|
+
const matchedProvider = acct ? providers.find((p) => p.name === acct.name) : void 0;
|
|
6607
|
+
if (matchedProvider) {
|
|
6608
|
+
dispatch({ type: "SELECT_PROVIDER", providerId: matchedProvider.id });
|
|
6609
|
+
}
|
|
6610
|
+
dispatch({ type: "SET_ERROR", error: null });
|
|
6611
|
+
dispatch({ type: "SET_INCREASING_LIMIT", value: true });
|
|
6612
|
+
try {
|
|
6613
|
+
const token = await getAccessToken();
|
|
6614
|
+
if (!token) throw new Error("Not authenticated");
|
|
6615
|
+
const wallet = acct?.wallets.find((w) => w.id === selectedWalletId);
|
|
6616
|
+
const source = wallet?.sources.find(
|
|
6617
|
+
(s) => selectedTokenSymbol ? s.token.symbol === selectedTokenSymbol : s.token.status === "AUTHORIZED"
|
|
6618
|
+
);
|
|
6619
|
+
const evmChainId = chains.find((c) => c.name === wallet?.chain.name)?.commonId ?? void 0;
|
|
6620
|
+
const session = await createAccountAuthorizationSession(
|
|
6621
|
+
apiBaseUrl,
|
|
6622
|
+
token,
|
|
6623
|
+
selectedAccountId,
|
|
6624
|
+
activeCredentialId,
|
|
6625
|
+
{ tokenAddress: source?.address, chainId: evmChainId }
|
|
6626
|
+
);
|
|
6627
|
+
const isMobile = !shouldUseWalletConnector({
|
|
6628
|
+
useWalletConnector: useWalletConnectorProp,
|
|
6629
|
+
userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
|
|
6630
|
+
});
|
|
6631
|
+
if (isMobile) {
|
|
6632
|
+
handlingMobileReturnRef.current = false;
|
|
6633
|
+
mobileSetupFlowRef.current = true;
|
|
6634
|
+
setupAccountIdRef.current = selectedAccountId;
|
|
6635
|
+
reauthSessionIdRef.current = session.id;
|
|
6636
|
+
reauthTokenRef.current = null;
|
|
6637
|
+
persistMobileFlowState({
|
|
6638
|
+
accountId: selectedAccountId,
|
|
6639
|
+
sessionId: session.id,
|
|
6640
|
+
deeplinkUri: session.uri,
|
|
6641
|
+
providerId: matchedProvider?.id ?? null,
|
|
6642
|
+
isSetup: true,
|
|
6643
|
+
isReauthorization: true
|
|
6644
|
+
});
|
|
6645
|
+
dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: session.uri });
|
|
6646
|
+
triggerDeeplink(session.uri);
|
|
6647
|
+
} else {
|
|
6648
|
+
dispatch({ type: "NAVIGATE", step: "setup-status" });
|
|
6649
|
+
await authExecutor.executeSessionById(session.id);
|
|
6650
|
+
await reloadAccounts();
|
|
6651
|
+
dispatch({ type: "NAVIGATE", step: "deposit" });
|
|
6652
|
+
}
|
|
6653
|
+
} catch (err) {
|
|
6654
|
+
captureException(err);
|
|
6655
|
+
const msg = err instanceof Error ? err.message : "Failed to increase limit";
|
|
6656
|
+
dispatch({ type: "SET_ERROR", error: msg });
|
|
6657
|
+
onError?.(msg);
|
|
6658
|
+
} finally {
|
|
6659
|
+
dispatch({ type: "SET_INCREASING_LIMIT", value: false });
|
|
6660
|
+
}
|
|
6661
|
+
}, [
|
|
6662
|
+
selectedAccountId,
|
|
6663
|
+
selectedWalletId,
|
|
6664
|
+
selectedTokenSymbol,
|
|
6665
|
+
chains,
|
|
6666
|
+
activeCredentialId,
|
|
6667
|
+
accounts,
|
|
6668
|
+
providers,
|
|
6669
|
+
apiBaseUrl,
|
|
6670
|
+
getAccessToken,
|
|
6671
|
+
authExecutor,
|
|
6672
|
+
useWalletConnectorProp,
|
|
6673
|
+
reloadAccounts,
|
|
6674
|
+
onError,
|
|
6675
|
+
dispatch,
|
|
6676
|
+
mobileSetupFlowRef,
|
|
6677
|
+
handlingMobileReturnRef,
|
|
6678
|
+
setupAccountIdRef,
|
|
6679
|
+
reauthSessionIdRef,
|
|
6680
|
+
reauthTokenRef
|
|
6681
|
+
]);
|
|
6682
|
+
const handleNavigateToTokenPicker = useCallback(() => {
|
|
6683
|
+
if (authExecutor.pendingSelectSource) {
|
|
6684
|
+
dispatch({ type: "NAVIGATE", step: "select-source" });
|
|
6685
|
+
} else {
|
|
6686
|
+
dispatch({ type: "NAVIGATE", step: "token-picker" });
|
|
6687
|
+
}
|
|
6688
|
+
}, [dispatch, authExecutor.pendingSelectSource]);
|
|
6689
|
+
const handleSelectAuthorizedToken = useCallback((walletId, tokenSymbol) => {
|
|
6690
|
+
dispatch({ type: "SELECT_TOKEN", walletId, tokenSymbol });
|
|
6691
|
+
}, [dispatch]);
|
|
6692
|
+
const handleAuthorizeToken = useCallback(async (_walletId, tokenAddress, chainId, tokenSymbol) => {
|
|
6693
|
+
if (!selectedAccountId) {
|
|
6694
|
+
dispatch({ type: "SET_ERROR", error: "No account selected." });
|
|
6695
|
+
return;
|
|
6696
|
+
}
|
|
6697
|
+
if (!activeCredentialId) {
|
|
6698
|
+
dispatch({ type: "SET_ERROR", error: "Create or verify a passkey on this device before continuing." });
|
|
6699
|
+
dispatch({ type: "NAVIGATE", step: "create-passkey" });
|
|
6700
|
+
return;
|
|
6701
|
+
}
|
|
6702
|
+
const acct = accounts.find((a) => a.id === selectedAccountId);
|
|
6703
|
+
const matchedProvider = acct ? providers.find((p) => p.name === acct.name) : void 0;
|
|
6704
|
+
if (matchedProvider) {
|
|
6705
|
+
dispatch({ type: "SELECT_PROVIDER", providerId: matchedProvider.id });
|
|
6706
|
+
}
|
|
6707
|
+
dispatch({ type: "SET_ERROR", error: null });
|
|
6708
|
+
dispatch({ type: "SET_INCREASING_LIMIT", value: true });
|
|
6709
|
+
try {
|
|
6710
|
+
const token = await getAccessToken();
|
|
6711
|
+
if (!token) throw new Error("Not authenticated");
|
|
6712
|
+
const session = await createAccountAuthorizationSession(
|
|
6713
|
+
apiBaseUrl,
|
|
6714
|
+
token,
|
|
6715
|
+
selectedAccountId,
|
|
6716
|
+
activeCredentialId,
|
|
6717
|
+
{ tokenAddress, chainId }
|
|
6718
|
+
);
|
|
6719
|
+
const isMobile = !shouldUseWalletConnector({
|
|
6720
|
+
useWalletConnector: useWalletConnectorProp,
|
|
6721
|
+
userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
|
|
6722
|
+
});
|
|
6723
|
+
if (isMobile) {
|
|
6724
|
+
handlingMobileReturnRef.current = false;
|
|
6725
|
+
mobileSetupFlowRef.current = true;
|
|
6726
|
+
setupAccountIdRef.current = selectedAccountId;
|
|
6727
|
+
reauthSessionIdRef.current = session.id;
|
|
6728
|
+
reauthTokenRef.current = { walletId: _walletId, tokenSymbol };
|
|
6729
|
+
persistMobileFlowState({
|
|
6730
|
+
accountId: selectedAccountId,
|
|
6731
|
+
sessionId: session.id,
|
|
6732
|
+
deeplinkUri: session.uri,
|
|
6733
|
+
providerId: matchedProvider?.id ?? null,
|
|
6734
|
+
isSetup: true,
|
|
6735
|
+
isReauthorization: true,
|
|
6736
|
+
reauthorizationToken: { walletId: _walletId, tokenSymbol }
|
|
6737
|
+
});
|
|
6738
|
+
dispatch({ type: "MOBILE_DEEPLINK_READY", deeplinkUri: session.uri });
|
|
6739
|
+
triggerDeeplink(session.uri);
|
|
6740
|
+
} else {
|
|
6741
|
+
dispatch({ type: "NAVIGATE", step: "setup-status" });
|
|
6742
|
+
await authExecutor.executeSessionById(session.id);
|
|
6743
|
+
await reloadAccounts();
|
|
6744
|
+
dispatch({ type: "SELECT_TOKEN", walletId: _walletId, tokenSymbol });
|
|
6745
|
+
}
|
|
6746
|
+
} catch (err) {
|
|
6747
|
+
captureException(err);
|
|
6748
|
+
const msg = err instanceof Error ? err.message : "Failed to authorize token";
|
|
6749
|
+
dispatch({ type: "SET_ERROR", error: msg });
|
|
6750
|
+
onError?.(msg);
|
|
6751
|
+
} finally {
|
|
6752
|
+
dispatch({ type: "SET_INCREASING_LIMIT", value: false });
|
|
6753
|
+
}
|
|
6754
|
+
}, [
|
|
6755
|
+
selectedAccountId,
|
|
6756
|
+
activeCredentialId,
|
|
6757
|
+
accounts,
|
|
6758
|
+
providers,
|
|
6759
|
+
apiBaseUrl,
|
|
6760
|
+
getAccessToken,
|
|
6761
|
+
authExecutor,
|
|
6762
|
+
useWalletConnectorProp,
|
|
6763
|
+
reloadAccounts,
|
|
6764
|
+
onError,
|
|
6765
|
+
dispatch,
|
|
6766
|
+
mobileSetupFlowRef,
|
|
6767
|
+
handlingMobileReturnRef,
|
|
6768
|
+
setupAccountIdRef,
|
|
6769
|
+
reauthSessionIdRef,
|
|
6770
|
+
reauthTokenRef
|
|
6771
|
+
]);
|
|
6772
|
+
return {
|
|
6773
|
+
handleSelectProvider,
|
|
6774
|
+
handleContinueConnection,
|
|
6775
|
+
handleSelectAccount,
|
|
6776
|
+
handleIncreaseLimit,
|
|
6777
|
+
handleNavigateToTokenPicker,
|
|
6778
|
+
handleSelectAuthorizedToken,
|
|
6779
|
+
handleAuthorizeToken
|
|
6780
|
+
};
|
|
6781
|
+
}
|
|
6782
|
+
function useOneTapSetupHandlers(deps) {
|
|
6783
|
+
const {
|
|
6784
|
+
dispatch,
|
|
6785
|
+
getAccessToken,
|
|
6786
|
+
apiBaseUrl,
|
|
6787
|
+
authExecutor,
|
|
6788
|
+
selectSourceChainName,
|
|
6789
|
+
selectSourceTokenSymbol
|
|
6790
|
+
} = deps;
|
|
6791
|
+
const [savingOneTapLimit, setSavingOneTapLimit] = useState(false);
|
|
6792
|
+
const oneTapLimitSavedDuringSetupRef = useRef(false);
|
|
6714
6793
|
const handleSetupOneTap = useCallback(async (limit) => {
|
|
6715
6794
|
setSavingOneTapLimit(true);
|
|
6716
6795
|
try {
|
|
@@ -6718,39 +6797,24 @@ function SwypePaymentInner({
|
|
|
6718
6797
|
if (!token) throw new Error("Not authenticated");
|
|
6719
6798
|
await updateUserConfig(apiBaseUrl, token, { defaultAllowance: limit });
|
|
6720
6799
|
if (authExecutor.pendingSelectSource) {
|
|
6721
|
-
authExecutor.
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6800
|
+
const action = authExecutor.pendingSelectSource;
|
|
6801
|
+
const recommended = action.metadata?.recommended;
|
|
6802
|
+
let chainName;
|
|
6803
|
+
let tokenSymbol;
|
|
6804
|
+
if (selectSourceChainName && selectSourceTokenSymbol) {
|
|
6805
|
+
chainName = selectSourceChainName;
|
|
6806
|
+
tokenSymbol = selectSourceTokenSymbol;
|
|
6807
|
+
} else {
|
|
6808
|
+
const options = action.metadata?.options ?? [];
|
|
6809
|
+
const choices = buildSelectSourceChoices(options);
|
|
6810
|
+
chainName = recommended?.chainName ?? choices[0]?.chainName ?? "Base";
|
|
6811
|
+
tokenSymbol = recommended?.tokenSymbol ?? choices[0]?.tokens[0]?.tokenSymbol ?? "USDC";
|
|
6812
|
+
}
|
|
6813
|
+
oneTapLimitSavedDuringSetupRef.current = true;
|
|
6814
|
+
authExecutor.resolveSelectSource({ chainName, tokenSymbol });
|
|
6725
6815
|
dispatch({ type: "NAVIGATE", step: "setup-status" });
|
|
6726
6816
|
} else if (authExecutor.pendingOneTapSetup) {
|
|
6727
6817
|
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
6818
|
} else {
|
|
6755
6819
|
dispatch({ type: "NAVIGATE", step: "deposit" });
|
|
6756
6820
|
}
|
|
@@ -6763,76 +6827,118 @@ function SwypePaymentInner({
|
|
|
6763
6827
|
} finally {
|
|
6764
6828
|
setSavingOneTapLimit(false);
|
|
6765
6829
|
}
|
|
6766
|
-
}, [getAccessToken, apiBaseUrl, authExecutor,
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6830
|
+
}, [getAccessToken, apiBaseUrl, authExecutor, dispatch, selectSourceChainName, selectSourceTokenSymbol]);
|
|
6831
|
+
return {
|
|
6832
|
+
handleSetupOneTap,
|
|
6833
|
+
savingOneTapLimit,
|
|
6834
|
+
oneTapLimitSavedDuringSetupRef
|
|
6835
|
+
};
|
|
6836
|
+
}
|
|
6837
|
+
|
|
6838
|
+
// src/dataLoading.ts
|
|
6839
|
+
function resolveDataLoadAction({
|
|
6840
|
+
authenticated,
|
|
6841
|
+
step,
|
|
6842
|
+
accountsCount,
|
|
6843
|
+
hasActiveCredential,
|
|
6844
|
+
loading
|
|
6845
|
+
}) {
|
|
6846
|
+
if (!authenticated || step === "login" || step === "otp-verify" || accountsCount > 0 || !hasActiveCredential) {
|
|
6847
|
+
return "reset";
|
|
6848
|
+
}
|
|
6849
|
+
if (loading) {
|
|
6850
|
+
return "wait";
|
|
6851
|
+
}
|
|
6852
|
+
return "load";
|
|
6853
|
+
}
|
|
6854
|
+
|
|
6855
|
+
// src/processingStatus.ts
|
|
6856
|
+
var PROCESSING_TIMEOUT_MS = 18e4;
|
|
6857
|
+
function resolvePreferredTransfer(polledTransfer, localTransfer) {
|
|
6858
|
+
return polledTransfer ?? localTransfer;
|
|
6859
|
+
}
|
|
6860
|
+
function getTransferStatus(polledTransfer, localTransfer) {
|
|
6861
|
+
const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
|
|
6862
|
+
return transfer?.status ?? "UNKNOWN";
|
|
6863
|
+
}
|
|
6864
|
+
function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
|
|
6865
|
+
if (!processingStartedAtMs) return false;
|
|
6866
|
+
return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
|
|
6867
|
+
}
|
|
6868
|
+
var STATUS_DISPLAY_LABELS = {
|
|
6869
|
+
CREATED: "created",
|
|
6870
|
+
AUTHORIZED: "authorized",
|
|
6871
|
+
SENDING: "sending",
|
|
6872
|
+
SENT: "confirming delivery",
|
|
6873
|
+
COMPLETED: "completed",
|
|
6874
|
+
FAILED: "failed"
|
|
6875
|
+
};
|
|
6876
|
+
function getStatusDisplayLabel(status) {
|
|
6877
|
+
return STATUS_DISPLAY_LABELS[status] ?? status;
|
|
6878
|
+
}
|
|
6879
|
+
function buildProcessingTimeoutMessage(status) {
|
|
6880
|
+
const label = getStatusDisplayLabel(status);
|
|
6881
|
+
return `Payment is taking longer than expected (status: ${label}). Please try again.`;
|
|
6882
|
+
}
|
|
6883
|
+
|
|
6884
|
+
// src/hooks/usePaymentEffects.ts
|
|
6885
|
+
function usePaymentEffects(deps) {
|
|
6886
|
+
const {
|
|
6887
|
+
state,
|
|
6888
|
+
dispatch,
|
|
6889
|
+
ready,
|
|
6890
|
+
authenticated,
|
|
6891
|
+
apiBaseUrl,
|
|
6892
|
+
depositAmount,
|
|
6893
|
+
useWalletConnectorProp,
|
|
6894
|
+
onComplete,
|
|
6895
|
+
onError,
|
|
6896
|
+
polling,
|
|
6897
|
+
authExecutor,
|
|
6898
|
+
reloadAccounts,
|
|
6899
|
+
activeOtpStatus,
|
|
6900
|
+
activeOtpErrorMessage,
|
|
6901
|
+
otpCode,
|
|
6902
|
+
handleVerifyLoginCode,
|
|
6903
|
+
setAuthInput,
|
|
6904
|
+
setOtpCode,
|
|
6905
|
+
mobileSetupFlowRef,
|
|
6906
|
+
handlingMobileReturnRef,
|
|
6907
|
+
setupAccountIdRef,
|
|
6908
|
+
reauthSessionIdRef,
|
|
6909
|
+
reauthTokenRef,
|
|
6910
|
+
loadingDataRef,
|
|
6911
|
+
pollingTransferIdRef,
|
|
6912
|
+
processingStartedAtRef,
|
|
6913
|
+
checkingPasskeyRef,
|
|
6914
|
+
pendingSelectSourceAction,
|
|
6915
|
+
selectSourceChoices,
|
|
6916
|
+
selectSourceRecommended,
|
|
6917
|
+
setSelectSourceChainName,
|
|
6918
|
+
setSelectSourceTokenSymbol,
|
|
6919
|
+
initializedSelectSourceActionRef,
|
|
6920
|
+
preSelectSourceStepRef,
|
|
6921
|
+
oneTapLimitSavedDuringSetupRef,
|
|
6922
|
+
handleAuthorizedMobileReturn
|
|
6923
|
+
} = deps;
|
|
6924
|
+
const { getAccessToken } = usePrivy();
|
|
6925
|
+
const onCompleteRef = useRef(onComplete);
|
|
6926
|
+
onCompleteRef.current = onComplete;
|
|
6927
|
+
const getAccessTokenRef = useRef(getAccessToken);
|
|
6928
|
+
getAccessTokenRef.current = getAccessToken;
|
|
6929
|
+
const pollingRef = useRef(polling);
|
|
6930
|
+
pollingRef.current = polling;
|
|
6931
|
+
const handleAuthorizedMobileReturnRef = useRef(handleAuthorizedMobileReturn);
|
|
6932
|
+
handleAuthorizedMobileReturnRef.current = handleAuthorizedMobileReturn;
|
|
6827
6933
|
useEffect(() => {
|
|
6828
6934
|
if (depositAmount != null) {
|
|
6829
6935
|
dispatch({ type: "SYNC_AMOUNT", amount: depositAmount.toString() });
|
|
6830
6936
|
}
|
|
6831
|
-
}, [depositAmount]);
|
|
6937
|
+
}, [depositAmount, dispatch]);
|
|
6832
6938
|
useEffect(() => {
|
|
6833
6939
|
if (authenticated || state.step !== "otp-verify") return;
|
|
6834
6940
|
if (activeOtpErrorMessage) dispatch({ type: "SET_ERROR", error: activeOtpErrorMessage });
|
|
6835
|
-
}, [activeOtpErrorMessage, authenticated, state.step]);
|
|
6941
|
+
}, [activeOtpErrorMessage, authenticated, state.step, dispatch]);
|
|
6836
6942
|
useEffect(() => {
|
|
6837
6943
|
if (state.step === "otp-verify" && /^\d{6}$/.test(otpCode.trim()) && activeOtpStatus === "awaiting-code-input") {
|
|
6838
6944
|
handleVerifyLoginCode();
|
|
@@ -7059,7 +7165,7 @@ function SwypePaymentInner({
|
|
|
7059
7165
|
const load = async () => {
|
|
7060
7166
|
dispatch({ type: "DATA_LOAD_START" });
|
|
7061
7167
|
try {
|
|
7062
|
-
const token = await
|
|
7168
|
+
const token = await getAccessTokenRef.current();
|
|
7063
7169
|
if (!token) throw new Error("Not authenticated");
|
|
7064
7170
|
const [prov, accts, chn] = await Promise.all([
|
|
7065
7171
|
fetchProviders(apiBaseUrl, token),
|
|
@@ -7113,7 +7219,6 @@ function SwypePaymentInner({
|
|
|
7113
7219
|
state.step,
|
|
7114
7220
|
state.accounts.length,
|
|
7115
7221
|
apiBaseUrl,
|
|
7116
|
-
getAccessToken,
|
|
7117
7222
|
state.activeCredentialId,
|
|
7118
7223
|
state.selectedAccountId,
|
|
7119
7224
|
depositAmount
|
|
@@ -7128,7 +7233,7 @@ function SwypePaymentInner({
|
|
|
7128
7233
|
clearMobileFlowState();
|
|
7129
7234
|
dispatch({ type: "TRANSFER_FAILED", transfer: polling.transfer, error: "Transfer failed." });
|
|
7130
7235
|
}
|
|
7131
|
-
}, [polling.transfer, onComplete]);
|
|
7236
|
+
}, [polling.transfer, onComplete, dispatch]);
|
|
7132
7237
|
useEffect(() => {
|
|
7133
7238
|
if (state.step !== "processing") {
|
|
7134
7239
|
processingStartedAtRef.current = null;
|
|
@@ -7154,7 +7259,7 @@ function SwypePaymentInner({
|
|
|
7154
7259
|
}
|
|
7155
7260
|
const timeoutId = window.setTimeout(handleTimeout, remainingMs);
|
|
7156
7261
|
return () => window.clearTimeout(timeoutId);
|
|
7157
|
-
}, [state.step, polling.transfer, state.transfer, polling.stopPolling, onError]);
|
|
7262
|
+
}, [state.step, polling.transfer, state.transfer, polling.stopPolling, onError, dispatch, processingStartedAtRef]);
|
|
7158
7263
|
useEffect(() => {
|
|
7159
7264
|
if (!state.mobileFlow) {
|
|
7160
7265
|
handlingMobileReturnRef.current = false;
|
|
@@ -7164,7 +7269,7 @@ function SwypePaymentInner({
|
|
|
7164
7269
|
const polledTransfer = polling.transfer;
|
|
7165
7270
|
if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
|
|
7166
7271
|
void handleAuthorizedMobileReturn(polledTransfer, mobileSetupFlowRef.current);
|
|
7167
|
-
}, [state.mobileFlow, polling.transfer, handleAuthorizedMobileReturn]);
|
|
7272
|
+
}, [state.mobileFlow, polling.transfer, handleAuthorizedMobileReturn, handlingMobileReturnRef, mobileSetupFlowRef]);
|
|
7168
7273
|
useEffect(() => {
|
|
7169
7274
|
if (!state.mobileFlow || !mobileSetupFlowRef.current) return;
|
|
7170
7275
|
if (state.step !== "open-wallet") return;
|
|
@@ -7235,7 +7340,18 @@ function SwypePaymentInner({
|
|
|
7235
7340
|
window.clearInterval(intervalId);
|
|
7236
7341
|
document.removeEventListener("visibilitychange", handleVisibility);
|
|
7237
7342
|
};
|
|
7238
|
-
}, [
|
|
7343
|
+
}, [
|
|
7344
|
+
state.mobileFlow,
|
|
7345
|
+
state.step,
|
|
7346
|
+
state.activeCredentialId,
|
|
7347
|
+
apiBaseUrl,
|
|
7348
|
+
reloadAccounts,
|
|
7349
|
+
dispatch,
|
|
7350
|
+
mobileSetupFlowRef,
|
|
7351
|
+
setupAccountIdRef,
|
|
7352
|
+
reauthSessionIdRef,
|
|
7353
|
+
reauthTokenRef
|
|
7354
|
+
]);
|
|
7239
7355
|
useEffect(() => {
|
|
7240
7356
|
if (!state.mobileFlow) return;
|
|
7241
7357
|
if (handlingMobileReturnRef.current) return;
|
|
@@ -7249,7 +7365,14 @@ function SwypePaymentInner({
|
|
|
7249
7365
|
};
|
|
7250
7366
|
document.addEventListener("visibilitychange", handleVisibility);
|
|
7251
7367
|
return () => document.removeEventListener("visibilitychange", handleVisibility);
|
|
7252
|
-
}, [
|
|
7368
|
+
}, [
|
|
7369
|
+
state.mobileFlow,
|
|
7370
|
+
state.transfer?.id,
|
|
7371
|
+
polling.isPolling,
|
|
7372
|
+
polling.startPolling,
|
|
7373
|
+
handlingMobileReturnRef,
|
|
7374
|
+
pollingTransferIdRef
|
|
7375
|
+
]);
|
|
7253
7376
|
useEffect(() => {
|
|
7254
7377
|
if (!pendingSelectSourceAction) {
|
|
7255
7378
|
initializedSelectSourceActionRef.current = null;
|
|
@@ -7258,20 +7381,6 @@ function SwypePaymentInner({
|
|
|
7258
7381
|
return;
|
|
7259
7382
|
}
|
|
7260
7383
|
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
7384
|
const hasRecommended = !!selectSourceRecommended && selectSourceChoices.some(
|
|
7276
7385
|
(chain) => chain.chainName === selectSourceRecommended.chainName && chain.tokens.some((t) => t.tokenSymbol === selectSourceRecommended.tokenSymbol)
|
|
7277
7386
|
);
|
|
@@ -7286,7 +7395,14 @@ function SwypePaymentInner({
|
|
|
7286
7395
|
setSelectSourceTokenSymbol("USDC");
|
|
7287
7396
|
}
|
|
7288
7397
|
initializedSelectSourceActionRef.current = pendingSelectSourceAction.id;
|
|
7289
|
-
}, [
|
|
7398
|
+
}, [
|
|
7399
|
+
pendingSelectSourceAction,
|
|
7400
|
+
selectSourceChoices,
|
|
7401
|
+
selectSourceRecommended,
|
|
7402
|
+
setSelectSourceChainName,
|
|
7403
|
+
setSelectSourceTokenSymbol,
|
|
7404
|
+
initializedSelectSourceActionRef
|
|
7405
|
+
]);
|
|
7290
7406
|
useEffect(() => {
|
|
7291
7407
|
if (pendingSelectSourceAction && (state.step === "processing" || state.step === "open-wallet" || state.step === "setup-status")) {
|
|
7292
7408
|
const isDesktop = shouldUseWalletConnector({
|
|
@@ -7294,9 +7410,8 @@ function SwypePaymentInner({
|
|
|
7294
7410
|
userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
|
|
7295
7411
|
});
|
|
7296
7412
|
if (isDesktop && state.step === "setup-status") {
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
});
|
|
7413
|
+
preSelectSourceStepRef.current = state.step;
|
|
7414
|
+
dispatch({ type: "NAVIGATE", step: "setup" });
|
|
7300
7415
|
return;
|
|
7301
7416
|
}
|
|
7302
7417
|
preSelectSourceStepRef.current = state.step;
|
|
@@ -7305,75 +7420,246 @@ function SwypePaymentInner({
|
|
|
7305
7420
|
dispatch({ type: "NAVIGATE", step: preSelectSourceStepRef.current ?? "processing" });
|
|
7306
7421
|
preSelectSourceStepRef.current = null;
|
|
7307
7422
|
}
|
|
7308
|
-
}, [pendingSelectSourceAction, state.step,
|
|
7423
|
+
}, [pendingSelectSourceAction, state.step, useWalletConnectorProp, dispatch, preSelectSourceStepRef, authExecutor]);
|
|
7309
7424
|
const pendingOneTapSetupAction = authExecutor.pendingOneTapSetup;
|
|
7310
7425
|
const preOneTapSetupStepRef = useRef(null);
|
|
7311
7426
|
useEffect(() => {
|
|
7312
7427
|
if (pendingOneTapSetupAction && state.step === "setup-status") {
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
}
|
|
7428
|
+
if (oneTapLimitSavedDuringSetupRef.current) {
|
|
7429
|
+
oneTapLimitSavedDuringSetupRef.current = false;
|
|
7430
|
+
authExecutor.resolveOneTapSetup();
|
|
7431
|
+
} else {
|
|
7432
|
+
preOneTapSetupStepRef.current = state.step;
|
|
7433
|
+
reloadAccounts().then(() => {
|
|
7434
|
+
dispatch({ type: "NAVIGATE", step: "setup" });
|
|
7435
|
+
});
|
|
7436
|
+
}
|
|
7317
7437
|
} else if (!pendingOneTapSetupAction && state.step === "setup" && preOneTapSetupStepRef.current) {
|
|
7318
7438
|
dispatch({ type: "NAVIGATE", step: preOneTapSetupStepRef.current });
|
|
7319
7439
|
preOneTapSetupStepRef.current = null;
|
|
7320
7440
|
}
|
|
7321
|
-
}, [pendingOneTapSetupAction, state.step, reloadAccounts]);
|
|
7441
|
+
}, [pendingOneTapSetupAction, state.step, reloadAccounts, authExecutor, dispatch, oneTapLimitSavedDuringSetupRef]);
|
|
7442
|
+
}
|
|
7443
|
+
function SwypePayment(props) {
|
|
7444
|
+
const resetKey = useRef(0);
|
|
7445
|
+
const handleBoundaryReset = useCallback(() => {
|
|
7446
|
+
resetKey.current += 1;
|
|
7447
|
+
}, []);
|
|
7448
|
+
return /* @__PURE__ */ jsx(PaymentErrorBoundary, { onReset: handleBoundaryReset, children: /* @__PURE__ */ jsx(SwypePaymentInner, { ...props }) }, resetKey.current);
|
|
7449
|
+
}
|
|
7450
|
+
function SwypePaymentInner({
|
|
7451
|
+
destination,
|
|
7452
|
+
onComplete,
|
|
7453
|
+
onError,
|
|
7454
|
+
useWalletConnector: useWalletConnectorProp,
|
|
7455
|
+
idempotencyKey,
|
|
7456
|
+
merchantAuthorization,
|
|
7457
|
+
merchantName,
|
|
7458
|
+
onBack,
|
|
7459
|
+
onDismiss,
|
|
7460
|
+
autoCloseSeconds
|
|
7461
|
+
}) {
|
|
7462
|
+
const { apiBaseUrl, depositAmount } = useSwypeConfig();
|
|
7463
|
+
const { ready, authenticated, logout, getAccessToken } = usePrivy();
|
|
7464
|
+
useLoginWithOAuth();
|
|
7465
|
+
const [state, dispatch] = useReducer(
|
|
7466
|
+
paymentReducer,
|
|
7467
|
+
{
|
|
7468
|
+
depositAmount,
|
|
7469
|
+
passkeyPopupNeeded: isSafari() && isInCrossOriginIframe(),
|
|
7470
|
+
activeCredentialId: typeof window === "undefined" ? null : window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY)
|
|
7471
|
+
},
|
|
7472
|
+
createInitialState
|
|
7473
|
+
);
|
|
7474
|
+
const authExecutor = useAuthorizationExecutor();
|
|
7475
|
+
const polling = useTransferPolling();
|
|
7476
|
+
const transferSigning = useTransferSigning();
|
|
7477
|
+
const mobileFlowRefs = {
|
|
7478
|
+
mobileSetupFlowRef: useRef(false),
|
|
7479
|
+
handlingMobileReturnRef: useRef(false),
|
|
7480
|
+
setupAccountIdRef: useRef(null),
|
|
7481
|
+
reauthSessionIdRef: useRef(null),
|
|
7482
|
+
reauthTokenRef: useRef(null),
|
|
7483
|
+
loadingDataRef: useRef(false)
|
|
7484
|
+
};
|
|
7485
|
+
const derived = useDerivedState(state);
|
|
7486
|
+
const auth = useAuthHandlers(dispatch, state.verificationTarget);
|
|
7487
|
+
const passkey = usePasskeyHandlers(
|
|
7488
|
+
dispatch,
|
|
7489
|
+
apiBaseUrl,
|
|
7490
|
+
state.accounts,
|
|
7491
|
+
state.knownCredentialIds,
|
|
7492
|
+
mobileFlowRefs.mobileSetupFlowRef
|
|
7493
|
+
);
|
|
7494
|
+
const transfer = useTransferHandlers({
|
|
7495
|
+
dispatch,
|
|
7496
|
+
getAccessToken,
|
|
7497
|
+
apiBaseUrl,
|
|
7498
|
+
depositAmount,
|
|
7499
|
+
destination,
|
|
7500
|
+
idempotencyKey,
|
|
7501
|
+
merchantAuthorization,
|
|
7502
|
+
onComplete,
|
|
7503
|
+
onError,
|
|
7504
|
+
polling,
|
|
7505
|
+
transferSigning,
|
|
7506
|
+
sourceType: derived.sourceType,
|
|
7507
|
+
sourceId: derived.sourceId,
|
|
7508
|
+
sourceTokenAddress: derived.selectedSource?.address,
|
|
7509
|
+
activeCredentialId: state.activeCredentialId,
|
|
7510
|
+
selectedAccountId: state.selectedAccountId,
|
|
7511
|
+
transfer: state.transfer,
|
|
7512
|
+
accounts: state.accounts
|
|
7513
|
+
});
|
|
7514
|
+
const mobileFlow = useMobileFlowHandlers(
|
|
7515
|
+
dispatch,
|
|
7516
|
+
polling,
|
|
7517
|
+
transfer.reloadAccounts,
|
|
7518
|
+
transfer.pollingTransferIdRef,
|
|
7519
|
+
state.transfer,
|
|
7520
|
+
mobileFlowRefs
|
|
7521
|
+
);
|
|
7522
|
+
const sourceSelection = useSourceSelectionHandlers(dispatch, authExecutor);
|
|
7523
|
+
const provider = useProviderHandlers({
|
|
7524
|
+
dispatch,
|
|
7525
|
+
getAccessToken,
|
|
7526
|
+
apiBaseUrl,
|
|
7527
|
+
depositAmount,
|
|
7528
|
+
useWalletConnectorProp,
|
|
7529
|
+
activeCredentialId: state.activeCredentialId,
|
|
7530
|
+
selectedAccountId: state.selectedAccountId,
|
|
7531
|
+
selectedWalletId: state.selectedWalletId,
|
|
7532
|
+
selectedTokenSymbol: state.selectedTokenSymbol,
|
|
7533
|
+
chains: state.chains,
|
|
7534
|
+
accounts: state.accounts,
|
|
7535
|
+
providers: state.providers,
|
|
7536
|
+
authExecutor,
|
|
7537
|
+
reloadAccounts: transfer.reloadAccounts,
|
|
7538
|
+
onError,
|
|
7539
|
+
mobileSetupFlowRef: mobileFlowRefs.mobileSetupFlowRef,
|
|
7540
|
+
handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
|
|
7541
|
+
setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
|
|
7542
|
+
reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
|
|
7543
|
+
reauthTokenRef: mobileFlowRefs.reauthTokenRef
|
|
7544
|
+
});
|
|
7545
|
+
const oneTapSetup = useOneTapSetupHandlers({
|
|
7546
|
+
dispatch,
|
|
7547
|
+
getAccessToken,
|
|
7548
|
+
apiBaseUrl,
|
|
7549
|
+
authExecutor,
|
|
7550
|
+
selectSourceChainName: sourceSelection.selectSourceChainName,
|
|
7551
|
+
selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol
|
|
7552
|
+
});
|
|
7553
|
+
const handleNewPayment = useCallback(() => {
|
|
7554
|
+
clearMobileFlowState();
|
|
7555
|
+
transfer.processingStartedAtRef.current = null;
|
|
7556
|
+
transfer.pollingTransferIdRef.current = null;
|
|
7557
|
+
sourceSelection.preSelectSourceStepRef.current = null;
|
|
7558
|
+
oneTapSetup.oneTapLimitSavedDuringSetupRef.current = false;
|
|
7559
|
+
dispatch({
|
|
7560
|
+
type: "NEW_PAYMENT",
|
|
7561
|
+
depositAmount,
|
|
7562
|
+
firstAccountId: state.accounts.length > 0 ? state.accounts[0].id : null
|
|
7563
|
+
});
|
|
7564
|
+
}, [depositAmount, state.accounts, transfer, sourceSelection, provider, oneTapSetup]);
|
|
7565
|
+
const handleLogout = useCallback(async () => {
|
|
7566
|
+
try {
|
|
7567
|
+
await logout();
|
|
7568
|
+
} catch {
|
|
7569
|
+
}
|
|
7570
|
+
clearMobileFlowState();
|
|
7571
|
+
if (typeof window !== "undefined") {
|
|
7572
|
+
window.localStorage.removeItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
|
|
7573
|
+
}
|
|
7574
|
+
polling.stopPolling();
|
|
7575
|
+
sourceSelection.preSelectSourceStepRef.current = null;
|
|
7576
|
+
passkey.checkingPasskeyRef.current = false;
|
|
7577
|
+
oneTapSetup.oneTapLimitSavedDuringSetupRef.current = false;
|
|
7578
|
+
auth.setAuthInput("");
|
|
7579
|
+
auth.setOtpCode("");
|
|
7580
|
+
dispatch({ type: "LOGOUT", depositAmount });
|
|
7581
|
+
}, [logout, polling, depositAmount, auth, sourceSelection, provider, passkey, oneTapSetup]);
|
|
7582
|
+
usePaymentEffects({
|
|
7583
|
+
state,
|
|
7584
|
+
dispatch,
|
|
7585
|
+
ready,
|
|
7586
|
+
authenticated,
|
|
7587
|
+
apiBaseUrl,
|
|
7588
|
+
depositAmount,
|
|
7589
|
+
useWalletConnectorProp,
|
|
7590
|
+
onComplete,
|
|
7591
|
+
onError,
|
|
7592
|
+
polling,
|
|
7593
|
+
authExecutor,
|
|
7594
|
+
reloadAccounts: transfer.reloadAccounts,
|
|
7595
|
+
activeOtpStatus: auth.activeOtpStatus,
|
|
7596
|
+
activeOtpErrorMessage: auth.activeOtpErrorMessage,
|
|
7597
|
+
otpCode: auth.otpCode,
|
|
7598
|
+
handleVerifyLoginCode: auth.handleVerifyLoginCode,
|
|
7599
|
+
setAuthInput: auth.setAuthInput,
|
|
7600
|
+
setOtpCode: auth.setOtpCode,
|
|
7601
|
+
mobileSetupFlowRef: mobileFlowRefs.mobileSetupFlowRef,
|
|
7602
|
+
handlingMobileReturnRef: mobileFlowRefs.handlingMobileReturnRef,
|
|
7603
|
+
setupAccountIdRef: mobileFlowRefs.setupAccountIdRef,
|
|
7604
|
+
reauthSessionIdRef: mobileFlowRefs.reauthSessionIdRef,
|
|
7605
|
+
reauthTokenRef: mobileFlowRefs.reauthTokenRef,
|
|
7606
|
+
loadingDataRef: mobileFlowRefs.loadingDataRef,
|
|
7607
|
+
pollingTransferIdRef: transfer.pollingTransferIdRef,
|
|
7608
|
+
processingStartedAtRef: transfer.processingStartedAtRef,
|
|
7609
|
+
checkingPasskeyRef: passkey.checkingPasskeyRef,
|
|
7610
|
+
pendingSelectSourceAction: sourceSelection.pendingSelectSourceAction,
|
|
7611
|
+
selectSourceChoices: sourceSelection.selectSourceChoices,
|
|
7612
|
+
selectSourceRecommended: sourceSelection.selectSourceRecommended,
|
|
7613
|
+
setSelectSourceChainName: sourceSelection.setSelectSourceChainName,
|
|
7614
|
+
setSelectSourceTokenSymbol: sourceSelection.setSelectSourceTokenSymbol,
|
|
7615
|
+
initializedSelectSourceActionRef: sourceSelection.initializedSelectSourceActionRef,
|
|
7616
|
+
preSelectSourceStepRef: sourceSelection.preSelectSourceStepRef,
|
|
7617
|
+
oneTapLimitSavedDuringSetupRef: oneTapSetup.oneTapLimitSavedDuringSetupRef,
|
|
7618
|
+
handleAuthorizedMobileReturn: mobileFlow.handleAuthorizedMobileReturn
|
|
7619
|
+
});
|
|
7322
7620
|
const handlers = useMemo(() => ({
|
|
7323
|
-
onSendLoginCode: handleSendLoginCode,
|
|
7324
|
-
onVerifyLoginCode: handleVerifyLoginCode,
|
|
7325
|
-
onResendLoginCode: handleResendLoginCode,
|
|
7621
|
+
onSendLoginCode: auth.handleSendLoginCode,
|
|
7622
|
+
onVerifyLoginCode: auth.handleVerifyLoginCode,
|
|
7623
|
+
onResendLoginCode: auth.handleResendLoginCode,
|
|
7326
7624
|
onBackFromOtp: () => {
|
|
7327
|
-
setOtpCode("");
|
|
7625
|
+
auth.setOtpCode("");
|
|
7328
7626
|
dispatch({ type: "BACK_TO_LOGIN" });
|
|
7329
7627
|
},
|
|
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,
|
|
7628
|
+
onRegisterPasskey: passkey.handleRegisterPasskey,
|
|
7629
|
+
onCreatePasskeyViaPopup: passkey.handleCreatePasskeyViaPopup,
|
|
7630
|
+
onVerifyPasskeyViaPopup: passkey.handleVerifyPasskeyViaPopup,
|
|
7631
|
+
onSelectProvider: provider.handleSelectProvider,
|
|
7632
|
+
onContinueConnection: provider.handleContinueConnection,
|
|
7633
|
+
onSelectAccount: provider.handleSelectAccount,
|
|
7634
|
+
onPay: transfer.handlePay,
|
|
7635
|
+
onIncreaseLimit: provider.handleIncreaseLimit,
|
|
7636
|
+
onConfirmSign: transfer.handleConfirmSign,
|
|
7637
|
+
onRetryMobileStatus: mobileFlow.handleRetryMobileStatus,
|
|
7340
7638
|
onLogout: handleLogout,
|
|
7341
7639
|
onNewPayment: handleNewPayment,
|
|
7342
7640
|
onNavigate: (step) => dispatch({ type: "NAVIGATE", step }),
|
|
7343
|
-
onSetAuthInput: setAuthInput,
|
|
7641
|
+
onSetAuthInput: auth.setAuthInput,
|
|
7344
7642
|
onSetOtpCode: (code) => {
|
|
7345
|
-
setOtpCode(code);
|
|
7643
|
+
auth.setOtpCode(code);
|
|
7346
7644
|
dispatch({ type: "SET_ERROR", error: null });
|
|
7347
7645
|
},
|
|
7348
|
-
onSelectSourceChainChange: handleSelectSourceChainChange,
|
|
7349
|
-
onSetSelectSourceTokenSymbol: setSelectSourceTokenSymbol,
|
|
7350
|
-
onConfirmSelectSource: handleConfirmSelectSource,
|
|
7351
|
-
onSetupOneTap: handleSetupOneTap,
|
|
7352
|
-
onSelectToken: handleNavigateToTokenPicker,
|
|
7353
|
-
onSelectAuthorizedToken: handleSelectAuthorizedToken,
|
|
7354
|
-
onAuthorizeToken: handleAuthorizeToken
|
|
7646
|
+
onSelectSourceChainChange: sourceSelection.handleSelectSourceChainChange,
|
|
7647
|
+
onSetSelectSourceTokenSymbol: sourceSelection.setSelectSourceTokenSymbol,
|
|
7648
|
+
onConfirmSelectSource: sourceSelection.handleConfirmSelectSource,
|
|
7649
|
+
onSetupOneTap: oneTapSetup.handleSetupOneTap,
|
|
7650
|
+
onSelectToken: provider.handleNavigateToTokenPicker,
|
|
7651
|
+
onSelectAuthorizedToken: provider.handleSelectAuthorizedToken,
|
|
7652
|
+
onAuthorizeToken: provider.handleAuthorizeToken
|
|
7355
7653
|
}), [
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
handleContinueConnection,
|
|
7364
|
-
handleSelectAccount,
|
|
7365
|
-
handlePay,
|
|
7366
|
-
handleIncreaseLimit,
|
|
7367
|
-
handleConfirmSign,
|
|
7368
|
-
handleRetryMobileStatus,
|
|
7654
|
+
auth,
|
|
7655
|
+
passkey,
|
|
7656
|
+
provider,
|
|
7657
|
+
transfer,
|
|
7658
|
+
mobileFlow,
|
|
7659
|
+
sourceSelection,
|
|
7660
|
+
oneTapSetup,
|
|
7369
7661
|
handleLogout,
|
|
7370
|
-
handleNewPayment
|
|
7371
|
-
handleSelectSourceChainChange,
|
|
7372
|
-
handleConfirmSelectSource,
|
|
7373
|
-
handleSetupOneTap,
|
|
7374
|
-
handleNavigateToTokenPicker,
|
|
7375
|
-
handleSelectAuthorizedToken,
|
|
7376
|
-
handleAuthorizeToken
|
|
7662
|
+
handleNewPayment
|
|
7377
7663
|
]);
|
|
7378
7664
|
return /* @__PURE__ */ jsx(
|
|
7379
7665
|
StepRenderer,
|
|
@@ -7381,29 +7667,29 @@ function SwypePaymentInner({
|
|
|
7381
7667
|
state,
|
|
7382
7668
|
ready,
|
|
7383
7669
|
authenticated,
|
|
7384
|
-
activeOtpStatus,
|
|
7670
|
+
activeOtpStatus: auth.activeOtpStatus,
|
|
7385
7671
|
pollingTransfer: polling.transfer,
|
|
7386
7672
|
pollingError: polling.error,
|
|
7387
7673
|
authExecutorError: authExecutor.error,
|
|
7388
7674
|
transferSigningSigning: transferSigning.signing,
|
|
7389
7675
|
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
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7676
|
+
pendingConnections: derived.pendingConnections,
|
|
7677
|
+
depositEligibleAccounts: derived.depositEligibleAccounts,
|
|
7678
|
+
sourceName: derived.sourceName,
|
|
7679
|
+
sourceAddress: derived.sourceAddress,
|
|
7680
|
+
sourceVerified: derived.sourceVerified,
|
|
7681
|
+
maxSourceBalance: derived.maxSourceBalance,
|
|
7682
|
+
tokenCount: derived.tokenCount,
|
|
7683
|
+
selectedAccount: derived.selectedAccount,
|
|
7684
|
+
selectedSource: derived.selectedSource,
|
|
7685
|
+
selectSourceChoices: sourceSelection.selectSourceChoices,
|
|
7686
|
+
selectSourceRecommended: sourceSelection.selectSourceRecommended,
|
|
7687
|
+
selectSourceAvailableBalance: sourceSelection.selectSourceAvailableBalance,
|
|
7688
|
+
authInput: auth.authInput,
|
|
7689
|
+
otpCode: auth.otpCode,
|
|
7690
|
+
selectSourceChainName: sourceSelection.selectSourceChainName,
|
|
7691
|
+
selectSourceTokenSymbol: sourceSelection.selectSourceTokenSymbol,
|
|
7692
|
+
savingOneTapLimit: oneTapSetup.savingOneTapLimit,
|
|
7407
7693
|
merchantName,
|
|
7408
7694
|
onBack,
|
|
7409
7695
|
onDismiss,
|