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