@swype-org/react-sdk 0.1.2 → 0.1.4
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 +682 -446
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -20
- package/dist/index.d.ts +37 -20
- package/dist/index.js +684 -448
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createContext, useRef, useState, useCallback, useMemo, useContext, useEffect } from 'react';
|
|
2
2
|
import { PrivyProvider, usePrivy } from '@privy-io/react-auth';
|
|
3
|
-
import { createConfig, http, WagmiProvider,
|
|
3
|
+
import { createConfig, http, WagmiProvider, useConfig, useConnect, useSwitchChain } from 'wagmi';
|
|
4
4
|
import { mainnet, arbitrum, base } from 'wagmi/chains';
|
|
5
5
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { recoverTypedDataAddress, walletActions, createClient, custom } from 'viem';
|
|
8
|
+
import { parseAccount, getAddress } from 'viem/utils';
|
|
9
9
|
|
|
10
10
|
var __defProp = Object.defineProperty;
|
|
11
11
|
var __export = (target, all) => {
|
|
@@ -143,6 +143,7 @@ __export(api_exports, {
|
|
|
143
143
|
fetchProviders: () => fetchProviders,
|
|
144
144
|
fetchTransfer: () => fetchTransfer,
|
|
145
145
|
reportActionCompletion: () => reportActionCompletion,
|
|
146
|
+
signTransfer: () => signTransfer,
|
|
146
147
|
updateUserConfig: () => updateUserConfig,
|
|
147
148
|
updateUserConfigBySession: () => updateUserConfigBySession
|
|
148
149
|
});
|
|
@@ -211,6 +212,18 @@ async function fetchTransfer(apiBaseUrl, token, transferId) {
|
|
|
211
212
|
if (!res.ok) await throwApiError(res);
|
|
212
213
|
return await res.json();
|
|
213
214
|
}
|
|
215
|
+
async function signTransfer(apiBaseUrl, token, transferId, signedUserOp) {
|
|
216
|
+
const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
|
|
217
|
+
method: "PATCH",
|
|
218
|
+
headers: {
|
|
219
|
+
"Content-Type": "application/json",
|
|
220
|
+
Authorization: `Bearer ${token}`
|
|
221
|
+
},
|
|
222
|
+
body: JSON.stringify({ signedUserOp })
|
|
223
|
+
});
|
|
224
|
+
if (!res.ok) await throwApiError(res);
|
|
225
|
+
return await res.json();
|
|
226
|
+
}
|
|
214
227
|
async function fetchAuthorizationSession(apiBaseUrl, sessionId) {
|
|
215
228
|
const res = await fetch(
|
|
216
229
|
`${apiBaseUrl}/v1/authorization-sessions/${sessionId}`
|
|
@@ -252,25 +265,302 @@ async function reportActionCompletion(apiBaseUrl, actionId, result) {
|
|
|
252
265
|
if (!res.ok) await throwApiError(res);
|
|
253
266
|
return await res.json();
|
|
254
267
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
268
|
+
|
|
269
|
+
// node_modules/@wagmi/core/dist/esm/version.js
|
|
270
|
+
var version = "2.22.1";
|
|
271
|
+
|
|
272
|
+
// node_modules/@wagmi/core/dist/esm/utils/getVersion.js
|
|
273
|
+
var getVersion = () => `@wagmi/core@${version}`;
|
|
274
|
+
|
|
275
|
+
// node_modules/@wagmi/core/dist/esm/errors/base.js
|
|
276
|
+
var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
277
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
278
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
279
|
+
};
|
|
280
|
+
var _BaseError_instances;
|
|
281
|
+
var _BaseError_walk;
|
|
282
|
+
var BaseError = class _BaseError extends Error {
|
|
283
|
+
get docsBaseUrl() {
|
|
284
|
+
return "https://wagmi.sh/core";
|
|
285
|
+
}
|
|
286
|
+
get version() {
|
|
287
|
+
return getVersion();
|
|
288
|
+
}
|
|
289
|
+
constructor(shortMessage, options = {}) {
|
|
290
|
+
super();
|
|
291
|
+
_BaseError_instances.add(this);
|
|
292
|
+
Object.defineProperty(this, "details", {
|
|
293
|
+
enumerable: true,
|
|
294
|
+
configurable: true,
|
|
295
|
+
writable: true,
|
|
296
|
+
value: void 0
|
|
297
|
+
});
|
|
298
|
+
Object.defineProperty(this, "docsPath", {
|
|
299
|
+
enumerable: true,
|
|
300
|
+
configurable: true,
|
|
301
|
+
writable: true,
|
|
302
|
+
value: void 0
|
|
303
|
+
});
|
|
304
|
+
Object.defineProperty(this, "metaMessages", {
|
|
305
|
+
enumerable: true,
|
|
306
|
+
configurable: true,
|
|
307
|
+
writable: true,
|
|
308
|
+
value: void 0
|
|
309
|
+
});
|
|
310
|
+
Object.defineProperty(this, "shortMessage", {
|
|
311
|
+
enumerable: true,
|
|
312
|
+
configurable: true,
|
|
313
|
+
writable: true,
|
|
314
|
+
value: void 0
|
|
315
|
+
});
|
|
316
|
+
Object.defineProperty(this, "name", {
|
|
317
|
+
enumerable: true,
|
|
318
|
+
configurable: true,
|
|
319
|
+
writable: true,
|
|
320
|
+
value: "WagmiCoreError"
|
|
321
|
+
});
|
|
322
|
+
const details = options.cause instanceof _BaseError ? options.cause.details : options.cause?.message ? options.cause.message : options.details;
|
|
323
|
+
const docsPath = options.cause instanceof _BaseError ? options.cause.docsPath || options.docsPath : options.docsPath;
|
|
324
|
+
this.message = [
|
|
325
|
+
shortMessage || "An error occurred.",
|
|
326
|
+
"",
|
|
327
|
+
...options.metaMessages ? [...options.metaMessages, ""] : [],
|
|
328
|
+
...docsPath ? [
|
|
329
|
+
`Docs: ${this.docsBaseUrl}${docsPath}.html${options.docsSlug ? `#${options.docsSlug}` : ""}`
|
|
330
|
+
] : [],
|
|
331
|
+
...details ? [`Details: ${details}`] : [],
|
|
332
|
+
`Version: ${this.version}`
|
|
333
|
+
].join("\n");
|
|
334
|
+
if (options.cause)
|
|
335
|
+
this.cause = options.cause;
|
|
336
|
+
this.details = details;
|
|
337
|
+
this.docsPath = docsPath;
|
|
338
|
+
this.metaMessages = options.metaMessages;
|
|
339
|
+
this.shortMessage = shortMessage;
|
|
340
|
+
}
|
|
341
|
+
walk(fn) {
|
|
342
|
+
return __classPrivateFieldGet(this, _BaseError_instances, "m", _BaseError_walk).call(this, this, fn);
|
|
343
|
+
}
|
|
259
344
|
};
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
345
|
+
_BaseError_instances = /* @__PURE__ */ new WeakSet(), _BaseError_walk = function _BaseError_walk2(err, fn) {
|
|
346
|
+
if (fn?.(err))
|
|
347
|
+
return err;
|
|
348
|
+
if (err.cause)
|
|
349
|
+
return __classPrivateFieldGet(this, _BaseError_instances, "m", _BaseError_walk2).call(this, err.cause, fn);
|
|
350
|
+
return err;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// node_modules/@wagmi/core/dist/esm/errors/config.js
|
|
354
|
+
var ConnectorNotConnectedError = class extends BaseError {
|
|
355
|
+
constructor() {
|
|
356
|
+
super("Connector not connected.");
|
|
357
|
+
Object.defineProperty(this, "name", {
|
|
358
|
+
enumerable: true,
|
|
359
|
+
configurable: true,
|
|
360
|
+
writable: true,
|
|
361
|
+
value: "ConnectorNotConnectedError"
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
var ConnectorAccountNotFoundError = class extends BaseError {
|
|
366
|
+
constructor({ address, connector }) {
|
|
367
|
+
super(`Account "${address}" not found for connector "${connector.name}".`);
|
|
368
|
+
Object.defineProperty(this, "name", {
|
|
369
|
+
enumerable: true,
|
|
370
|
+
configurable: true,
|
|
371
|
+
writable: true,
|
|
372
|
+
value: "ConnectorAccountNotFoundError"
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
var ConnectorChainMismatchError = class extends BaseError {
|
|
377
|
+
constructor({ connectionChainId, connectorChainId }) {
|
|
378
|
+
super(`The current chain of the connector (id: ${connectorChainId}) does not match the connection's chain (id: ${connectionChainId}).`, {
|
|
379
|
+
metaMessages: [
|
|
380
|
+
`Current Chain ID: ${connectorChainId}`,
|
|
381
|
+
`Expected Chain ID: ${connectionChainId}`
|
|
382
|
+
]
|
|
383
|
+
});
|
|
384
|
+
Object.defineProperty(this, "name", {
|
|
385
|
+
enumerable: true,
|
|
386
|
+
configurable: true,
|
|
387
|
+
writable: true,
|
|
388
|
+
value: "ConnectorChainMismatchError"
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
var ConnectorUnavailableReconnectingError = class extends BaseError {
|
|
393
|
+
constructor({ connector }) {
|
|
394
|
+
super(`Connector "${connector.name}" unavailable while reconnecting.`, {
|
|
395
|
+
details: [
|
|
396
|
+
"During the reconnection step, the only connector methods guaranteed to be available are: `id`, `name`, `type`, `uid`.",
|
|
397
|
+
"All other methods are not guaranteed to be available until reconnection completes and connectors are fully restored.",
|
|
398
|
+
"This error commonly occurs for connectors that asynchronously inject after reconnection has already started."
|
|
399
|
+
].join(" ")
|
|
400
|
+
});
|
|
401
|
+
Object.defineProperty(this, "name", {
|
|
402
|
+
enumerable: true,
|
|
403
|
+
configurable: true,
|
|
404
|
+
writable: true,
|
|
405
|
+
value: "ConnectorUnavailableReconnectingError"
|
|
406
|
+
});
|
|
267
407
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
408
|
+
};
|
|
409
|
+
async function getConnectorClient(config, parameters = {}) {
|
|
410
|
+
const { assertChainId = true } = parameters;
|
|
411
|
+
let connection;
|
|
412
|
+
if (parameters.connector) {
|
|
413
|
+
const { connector: connector2 } = parameters;
|
|
414
|
+
if (config.state.status === "reconnecting" && !connector2.getAccounts && !connector2.getChainId)
|
|
415
|
+
throw new ConnectorUnavailableReconnectingError({ connector: connector2 });
|
|
416
|
+
const [accounts, chainId2] = await Promise.all([
|
|
417
|
+
connector2.getAccounts().catch((e) => {
|
|
418
|
+
if (parameters.account === null)
|
|
419
|
+
return [];
|
|
420
|
+
throw e;
|
|
421
|
+
}),
|
|
422
|
+
connector2.getChainId()
|
|
423
|
+
]);
|
|
424
|
+
connection = {
|
|
425
|
+
accounts,
|
|
426
|
+
chainId: chainId2,
|
|
427
|
+
connector: connector2
|
|
428
|
+
};
|
|
429
|
+
} else
|
|
430
|
+
connection = config.state.connections.get(config.state.current);
|
|
431
|
+
if (!connection)
|
|
432
|
+
throw new ConnectorNotConnectedError();
|
|
433
|
+
const chainId = parameters.chainId ?? connection.chainId;
|
|
434
|
+
const connectorChainId = await connection.connector.getChainId();
|
|
435
|
+
if (assertChainId && connectorChainId !== chainId)
|
|
436
|
+
throw new ConnectorChainMismatchError({
|
|
437
|
+
connectionChainId: chainId,
|
|
438
|
+
connectorChainId
|
|
439
|
+
});
|
|
440
|
+
const connector = connection.connector;
|
|
441
|
+
if (connector.getClient)
|
|
442
|
+
return connector.getClient({ chainId });
|
|
443
|
+
const account = parseAccount(parameters.account ?? connection.accounts[0]);
|
|
444
|
+
if (account)
|
|
445
|
+
account.address = getAddress(account.address);
|
|
446
|
+
if (parameters.account && !connection.accounts.some((x) => x.toLowerCase() === account.address.toLowerCase()))
|
|
447
|
+
throw new ConnectorAccountNotFoundError({
|
|
448
|
+
address: account.address,
|
|
449
|
+
connector
|
|
450
|
+
});
|
|
451
|
+
const chain = config.chains.find((chain2) => chain2.id === chainId);
|
|
452
|
+
const provider = await connection.connector.getProvider({ chainId });
|
|
453
|
+
return createClient({
|
|
454
|
+
account,
|
|
455
|
+
chain,
|
|
456
|
+
name: "Connector Client",
|
|
457
|
+
transport: (opts) => custom(provider)({ ...opts, retryCount: 0 })
|
|
271
458
|
});
|
|
272
|
-
|
|
273
|
-
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// node_modules/@wagmi/core/dist/esm/actions/getAccount.js
|
|
462
|
+
function getAccount(config) {
|
|
463
|
+
const uid = config.state.current;
|
|
464
|
+
const connection = config.state.connections.get(uid);
|
|
465
|
+
const addresses = connection?.accounts;
|
|
466
|
+
const address = addresses?.[0];
|
|
467
|
+
const chain = config.chains.find((chain2) => chain2.id === connection?.chainId);
|
|
468
|
+
const status = config.state.status;
|
|
469
|
+
switch (status) {
|
|
470
|
+
case "connected":
|
|
471
|
+
return {
|
|
472
|
+
address,
|
|
473
|
+
addresses,
|
|
474
|
+
chain,
|
|
475
|
+
chainId: connection?.chainId,
|
|
476
|
+
connector: connection?.connector,
|
|
477
|
+
isConnected: true,
|
|
478
|
+
isConnecting: false,
|
|
479
|
+
isDisconnected: false,
|
|
480
|
+
isReconnecting: false,
|
|
481
|
+
status
|
|
482
|
+
};
|
|
483
|
+
case "reconnecting":
|
|
484
|
+
return {
|
|
485
|
+
address,
|
|
486
|
+
addresses,
|
|
487
|
+
chain,
|
|
488
|
+
chainId: connection?.chainId,
|
|
489
|
+
connector: connection?.connector,
|
|
490
|
+
isConnected: !!address,
|
|
491
|
+
isConnecting: false,
|
|
492
|
+
isDisconnected: false,
|
|
493
|
+
isReconnecting: true,
|
|
494
|
+
status
|
|
495
|
+
};
|
|
496
|
+
case "connecting":
|
|
497
|
+
return {
|
|
498
|
+
address,
|
|
499
|
+
addresses,
|
|
500
|
+
chain,
|
|
501
|
+
chainId: connection?.chainId,
|
|
502
|
+
connector: connection?.connector,
|
|
503
|
+
isConnected: false,
|
|
504
|
+
isConnecting: true,
|
|
505
|
+
isDisconnected: false,
|
|
506
|
+
isReconnecting: false,
|
|
507
|
+
status
|
|
508
|
+
};
|
|
509
|
+
case "disconnected":
|
|
510
|
+
return {
|
|
511
|
+
address: void 0,
|
|
512
|
+
addresses: void 0,
|
|
513
|
+
chain: void 0,
|
|
514
|
+
chainId: void 0,
|
|
515
|
+
connector: void 0,
|
|
516
|
+
isConnected: false,
|
|
517
|
+
isConnecting: false,
|
|
518
|
+
isDisconnected: true,
|
|
519
|
+
isReconnecting: false,
|
|
520
|
+
status
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
async function getWalletClient(config, parameters = {}) {
|
|
525
|
+
const client = await getConnectorClient(config, parameters);
|
|
526
|
+
return client.extend(walletActions);
|
|
527
|
+
}
|
|
528
|
+
async function waitForWalletClient(wagmiConfig2, walletClientParams = {}, maxAttempts = 15, intervalMs = 200) {
|
|
529
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
530
|
+
try {
|
|
531
|
+
return await getWalletClient(wagmiConfig2, walletClientParams);
|
|
532
|
+
} catch {
|
|
533
|
+
if (i === maxAttempts - 1) {
|
|
534
|
+
throw new Error("Wallet not ready. Please try again.");
|
|
535
|
+
}
|
|
536
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
throw new Error("Wallet not ready. Please try again.");
|
|
540
|
+
}
|
|
541
|
+
function parseSignTypedDataPayload(typedData) {
|
|
542
|
+
const domain = typedData.domain;
|
|
543
|
+
const types = typedData.types;
|
|
544
|
+
const primaryType = typedData.primaryType;
|
|
545
|
+
const message = typedData.message;
|
|
546
|
+
if (!domain || typeof domain !== "object" || Array.isArray(domain)) {
|
|
547
|
+
throw new Error("SIGN_PERMIT2 typedData is missing a valid domain object.");
|
|
548
|
+
}
|
|
549
|
+
if (!types || typeof types !== "object" || Array.isArray(types)) {
|
|
550
|
+
throw new Error("SIGN_PERMIT2 typedData is missing a valid types object.");
|
|
551
|
+
}
|
|
552
|
+
if (typeof primaryType !== "string") {
|
|
553
|
+
throw new Error("SIGN_PERMIT2 typedData is missing primaryType.");
|
|
554
|
+
}
|
|
555
|
+
if (!message || typeof message !== "object" || Array.isArray(message)) {
|
|
556
|
+
throw new Error("SIGN_PERMIT2 typedData is missing a valid message object.");
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
domain,
|
|
560
|
+
types,
|
|
561
|
+
primaryType,
|
|
562
|
+
message
|
|
563
|
+
};
|
|
274
564
|
}
|
|
275
565
|
function useTransferPolling(intervalMs = 3e3) {
|
|
276
566
|
const { apiBaseUrl } = useSwypeConfig();
|
|
@@ -322,14 +612,13 @@ function useTransferPolling(intervalMs = 3e3) {
|
|
|
322
612
|
}
|
|
323
613
|
function useAuthorizationExecutor() {
|
|
324
614
|
const { apiBaseUrl } = useSwypeConfig();
|
|
325
|
-
const
|
|
615
|
+
const wagmiConfig2 = useConfig();
|
|
326
616
|
const { connectAsync, connectors } = useConnect();
|
|
327
617
|
const { switchChainAsync } = useSwitchChain();
|
|
328
|
-
const { signTypedDataAsync } = useSignTypedData();
|
|
329
|
-
const { data: walletClient } = useWalletClient();
|
|
330
618
|
const [executing, setExecuting] = useState(false);
|
|
331
619
|
const [results, setResults] = useState([]);
|
|
332
620
|
const [error, setError] = useState(null);
|
|
621
|
+
const [currentAction, setCurrentAction] = useState(null);
|
|
333
622
|
const executingRef = useRef(false);
|
|
334
623
|
const [pendingSelectSource, setPendingSelectSource] = useState(null);
|
|
335
624
|
const selectSourceResolverRef = useRef(null);
|
|
@@ -340,31 +629,28 @@ function useAuthorizationExecutor() {
|
|
|
340
629
|
setPendingSelectSource(null);
|
|
341
630
|
}
|
|
342
631
|
}, []);
|
|
343
|
-
const [pendingAllowanceSelection, setPendingAllowanceSelection] = useState(null);
|
|
344
|
-
const allowanceSelectionResolverRef = useRef(null);
|
|
345
632
|
const sessionIdRef = useRef(null);
|
|
346
|
-
const resolveAllowanceSelection = useCallback((selection) => {
|
|
347
|
-
if (allowanceSelectionResolverRef.current) {
|
|
348
|
-
allowanceSelectionResolverRef.current(selection);
|
|
349
|
-
allowanceSelectionResolverRef.current = null;
|
|
350
|
-
setPendingAllowanceSelection(null);
|
|
351
|
-
}
|
|
352
|
-
}, []);
|
|
353
633
|
const executeOpenProvider = useCallback(
|
|
354
634
|
async (action) => {
|
|
355
635
|
try {
|
|
356
|
-
|
|
357
|
-
|
|
636
|
+
const account = getAccount(wagmiConfig2);
|
|
637
|
+
if (account.isConnected && account.address) {
|
|
638
|
+
const hexChainId2 = account.chainId ? `0x${account.chainId.toString(16)}` : void 0;
|
|
358
639
|
return {
|
|
359
640
|
actionId: action.id,
|
|
360
641
|
type: action.type,
|
|
361
642
|
status: "success",
|
|
362
|
-
message: `Connected. Account: ${address}, Chain: ${hexChainId2}`,
|
|
363
|
-
data: { accounts: [address], chainId: hexChainId2 }
|
|
643
|
+
message: `Connected. Account: ${account.address}, Chain: ${hexChainId2}`,
|
|
644
|
+
data: { accounts: [account.address], chainId: hexChainId2 }
|
|
364
645
|
};
|
|
365
646
|
}
|
|
366
647
|
const targetId = action.metadata?.wagmiConnectorId;
|
|
367
|
-
const
|
|
648
|
+
const metaMaskConnector = connectors.find((c) => {
|
|
649
|
+
const id = c.id.toLowerCase();
|
|
650
|
+
const name = c.name.toLowerCase();
|
|
651
|
+
return id.includes("metamask") || name.includes("metamask");
|
|
652
|
+
});
|
|
653
|
+
const connector = targetId ? connectors.find((c) => c.id === targetId) ?? metaMaskConnector ?? connectors[0] : metaMaskConnector ?? connectors[0];
|
|
368
654
|
if (!connector) {
|
|
369
655
|
return {
|
|
370
656
|
actionId: action.id,
|
|
@@ -391,7 +677,7 @@ function useAuthorizationExecutor() {
|
|
|
391
677
|
};
|
|
392
678
|
}
|
|
393
679
|
},
|
|
394
|
-
[
|
|
680
|
+
[wagmiConfig2, connectors, connectAsync]
|
|
395
681
|
);
|
|
396
682
|
const executeSelectSource = useCallback(
|
|
397
683
|
async (action) => {
|
|
@@ -439,6 +725,7 @@ function useAuthorizationExecutor() {
|
|
|
439
725
|
const executeSwitchChain = useCallback(
|
|
440
726
|
async (action) => {
|
|
441
727
|
try {
|
|
728
|
+
const account = getAccount(wagmiConfig2);
|
|
442
729
|
const targetChainIdHex = action.metadata?.targetChainId;
|
|
443
730
|
if (!targetChainIdHex) {
|
|
444
731
|
return {
|
|
@@ -450,7 +737,7 @@ function useAuthorizationExecutor() {
|
|
|
450
737
|
}
|
|
451
738
|
const targetChainIdNum = parseInt(targetChainIdHex, 16);
|
|
452
739
|
const hexChainId = `0x${targetChainIdNum.toString(16)}`;
|
|
453
|
-
if (
|
|
740
|
+
if (account.chainId === targetChainIdNum) {
|
|
454
741
|
return {
|
|
455
742
|
actionId: action.id,
|
|
456
743
|
type: action.type,
|
|
@@ -476,252 +763,253 @@ function useAuthorizationExecutor() {
|
|
|
476
763
|
};
|
|
477
764
|
}
|
|
478
765
|
},
|
|
479
|
-
[
|
|
766
|
+
[wagmiConfig2, switchChainAsync]
|
|
480
767
|
);
|
|
481
|
-
const
|
|
768
|
+
const executeRegisterPasskey = useCallback(
|
|
482
769
|
async (action) => {
|
|
483
770
|
try {
|
|
484
|
-
const
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
771
|
+
const account = getAccount(wagmiConfig2);
|
|
772
|
+
const challenge = new Uint8Array(32);
|
|
773
|
+
crypto.getRandomValues(challenge);
|
|
774
|
+
const credential = await navigator.credentials.create({
|
|
775
|
+
publicKey: {
|
|
776
|
+
challenge,
|
|
777
|
+
rp: {
|
|
778
|
+
name: "Swype",
|
|
779
|
+
id: window.location.hostname
|
|
780
|
+
},
|
|
781
|
+
user: {
|
|
782
|
+
id: new TextEncoder().encode(account.address ?? "user"),
|
|
783
|
+
name: account.address ?? "Swype User",
|
|
784
|
+
displayName: "Swype User"
|
|
785
|
+
},
|
|
786
|
+
pubKeyCredParams: [
|
|
787
|
+
{ alg: -7, type: "public-key" },
|
|
788
|
+
// ES256 (P-256)
|
|
789
|
+
{ alg: -257, type: "public-key" }
|
|
790
|
+
// RS256
|
|
791
|
+
],
|
|
792
|
+
authenticatorSelection: {
|
|
793
|
+
authenticatorAttachment: "platform",
|
|
794
|
+
residentKey: "preferred",
|
|
795
|
+
userVerification: "required"
|
|
796
|
+
},
|
|
797
|
+
timeout: 6e4
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
if (!credential) {
|
|
488
801
|
return {
|
|
489
802
|
actionId: action.id,
|
|
490
803
|
type: action.type,
|
|
491
804
|
status: "error",
|
|
492
|
-
message: "
|
|
805
|
+
message: "Passkey creation was cancelled."
|
|
493
806
|
};
|
|
494
807
|
}
|
|
495
|
-
|
|
808
|
+
const response = credential.response;
|
|
809
|
+
const publicKeyBytes = response.getPublicKey?.();
|
|
810
|
+
const credentialId = btoa(
|
|
811
|
+
String.fromCharCode(...new Uint8Array(credential.rawId))
|
|
812
|
+
);
|
|
813
|
+
const publicKey = publicKeyBytes ? btoa(String.fromCharCode(...new Uint8Array(publicKeyBytes))) : "";
|
|
814
|
+
return {
|
|
815
|
+
actionId: action.id,
|
|
816
|
+
type: action.type,
|
|
817
|
+
status: "success",
|
|
818
|
+
message: "Passkey created successfully.",
|
|
819
|
+
data: {
|
|
820
|
+
credentialId,
|
|
821
|
+
publicKey
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
} catch (err) {
|
|
825
|
+
return {
|
|
826
|
+
actionId: action.id,
|
|
827
|
+
type: action.type,
|
|
828
|
+
status: "error",
|
|
829
|
+
message: err instanceof Error ? err.message : "Failed to create passkey"
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
[wagmiConfig2]
|
|
834
|
+
);
|
|
835
|
+
const executeCreateSmartAccount = useCallback(
|
|
836
|
+
async (action) => {
|
|
837
|
+
return {
|
|
838
|
+
actionId: action.id,
|
|
839
|
+
type: action.type,
|
|
840
|
+
status: "success",
|
|
841
|
+
message: "Smart account creation acknowledged. Server is deploying.",
|
|
842
|
+
data: {}
|
|
843
|
+
};
|
|
844
|
+
},
|
|
845
|
+
[]
|
|
846
|
+
);
|
|
847
|
+
const executeApprovePermit2 = useCallback(
|
|
848
|
+
async (action) => {
|
|
849
|
+
try {
|
|
850
|
+
const walletClient = await waitForWalletClient(wagmiConfig2);
|
|
851
|
+
const account = getAccount(wagmiConfig2);
|
|
852
|
+
const sender = account.address ?? walletClient.account?.address;
|
|
853
|
+
const expectedWalletAddress = action.metadata?.walletAddress;
|
|
854
|
+
if (!sender) {
|
|
855
|
+
throw new Error("Wallet account not available. Please connect your wallet.");
|
|
856
|
+
}
|
|
857
|
+
if (expectedWalletAddress && sender.toLowerCase() !== expectedWalletAddress.toLowerCase()) {
|
|
496
858
|
return {
|
|
497
859
|
actionId: action.id,
|
|
498
860
|
type: action.type,
|
|
499
861
|
status: "error",
|
|
500
|
-
message:
|
|
862
|
+
message: `Connected wallet ${sender} does not match the required source wallet ${expectedWalletAddress}. Please switch accounts in your wallet and retry.`
|
|
501
863
|
};
|
|
502
864
|
}
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
stateMutability: "view",
|
|
508
|
-
inputs: [
|
|
509
|
-
{ name: "owner", type: "address" },
|
|
510
|
-
{ name: "spender", type: "address" }
|
|
511
|
-
],
|
|
512
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
513
|
-
},
|
|
514
|
-
{
|
|
515
|
-
name: "approve",
|
|
516
|
-
type: "function",
|
|
517
|
-
stateMutability: "nonpayable",
|
|
518
|
-
inputs: [
|
|
519
|
-
{ name: "spender", type: "address" },
|
|
520
|
-
{ name: "amount", type: "uint256" }
|
|
521
|
-
],
|
|
522
|
-
outputs: [{ name: "", type: "bool" }]
|
|
523
|
-
}
|
|
524
|
-
];
|
|
525
|
-
const targetChainIdNum = metadataChainId ? parseInt(metadataChainId, 16) : currentChainId;
|
|
526
|
-
const chainClient = targetChainIdNum ? getPublicClientForChain(targetChainIdNum) : void 0;
|
|
527
|
-
if (chainClient) {
|
|
528
|
-
try {
|
|
529
|
-
const currentAllowance = await chainClient.readContract({
|
|
530
|
-
address: tokenAddress,
|
|
531
|
-
abi: ERC20_ABI,
|
|
532
|
-
functionName: "allowance",
|
|
533
|
-
args: [address, permit2Address]
|
|
534
|
-
});
|
|
535
|
-
if (currentAllowance > 0n) {
|
|
536
|
-
return {
|
|
537
|
-
actionId: action.id,
|
|
538
|
-
type: action.type,
|
|
539
|
-
status: "success",
|
|
540
|
-
message: `Permit2 already approved (allowance: ${currentAllowance.toString()}). Skipped.`,
|
|
541
|
-
data: { skipped: true, existingAllowance: currentAllowance.toString() }
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
} catch {
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
if (!walletClient) {
|
|
865
|
+
const to = action.metadata?.to;
|
|
866
|
+
const data = action.metadata?.data;
|
|
867
|
+
const tokenSymbol = action.metadata?.tokenSymbol;
|
|
868
|
+
if (!to || !data) {
|
|
548
869
|
return {
|
|
549
870
|
actionId: action.id,
|
|
550
871
|
type: action.type,
|
|
551
872
|
status: "error",
|
|
552
|
-
message: "
|
|
873
|
+
message: "APPROVE_PERMIT2 metadata is missing transaction parameters (to, data)."
|
|
553
874
|
};
|
|
554
875
|
}
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
876
|
+
const txHash = await walletClient.request({
|
|
877
|
+
method: "eth_sendTransaction",
|
|
878
|
+
params: [
|
|
879
|
+
{
|
|
880
|
+
from: sender,
|
|
881
|
+
to,
|
|
882
|
+
data,
|
|
883
|
+
value: "0x0"
|
|
884
|
+
}
|
|
885
|
+
]
|
|
561
886
|
});
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
887
|
+
console.info(
|
|
888
|
+
`[swype-sdk][approve-permit2] ERC-20 approve tx sent. token=${tokenSymbol ?? to}, txHash=${txHash}`
|
|
889
|
+
);
|
|
565
890
|
return {
|
|
566
891
|
actionId: action.id,
|
|
567
892
|
type: action.type,
|
|
568
893
|
status: "success",
|
|
569
|
-
message: `Permit2
|
|
570
|
-
data: { txHash
|
|
894
|
+
message: `Approved Permit2 to spend ${tokenSymbol ?? "tokens"}.`,
|
|
895
|
+
data: { txHash }
|
|
571
896
|
};
|
|
572
897
|
} catch (err) {
|
|
898
|
+
const message = err instanceof Error ? err.message : "Failed to approve Permit2";
|
|
899
|
+
const isRejected = message.includes("rejected") || message.includes("denied") || message.includes("user rejected");
|
|
573
900
|
return {
|
|
574
901
|
actionId: action.id,
|
|
575
902
|
type: action.type,
|
|
576
903
|
status: "error",
|
|
577
|
-
message:
|
|
904
|
+
message: isRejected ? "You rejected the approval transaction. Please approve the Permit2 spending allowance in your wallet to continue." : message
|
|
578
905
|
};
|
|
579
906
|
}
|
|
580
907
|
},
|
|
581
|
-
[
|
|
908
|
+
[wagmiConfig2]
|
|
582
909
|
);
|
|
583
910
|
const executeSignPermit2 = useCallback(
|
|
584
911
|
async (action) => {
|
|
585
912
|
try {
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
{ name: "amount", type: "uint160" },
|
|
599
|
-
{ name: "expiration", type: "uint48" },
|
|
600
|
-
{ name: "nonce", type: "uint48" }
|
|
601
|
-
]
|
|
602
|
-
}
|
|
603
|
-
];
|
|
604
|
-
const spenderAddress = action.metadata?.spenderAddress;
|
|
605
|
-
const tokenAddress = action.metadata?.tokenAddress;
|
|
606
|
-
const metadataChainId = action.metadata?.chainId;
|
|
607
|
-
const metadataAmount = action.metadata?.amount;
|
|
608
|
-
if (!spenderAddress || !tokenAddress) {
|
|
913
|
+
const expectedWalletAddress = action.metadata?.walletAddress;
|
|
914
|
+
const walletClient = await waitForWalletClient(
|
|
915
|
+
wagmiConfig2,
|
|
916
|
+
expectedWalletAddress ? { account: expectedWalletAddress } : {}
|
|
917
|
+
);
|
|
918
|
+
const account = getAccount(wagmiConfig2);
|
|
919
|
+
const connectedAddress = account.address ?? walletClient.account?.address;
|
|
920
|
+
const sender = expectedWalletAddress ?? connectedAddress;
|
|
921
|
+
if (!sender) {
|
|
922
|
+
throw new Error("Wallet account not available. Please connect your wallet.");
|
|
923
|
+
}
|
|
924
|
+
if (expectedWalletAddress && connectedAddress && connectedAddress.toLowerCase() !== expectedWalletAddress.toLowerCase()) {
|
|
609
925
|
return {
|
|
610
926
|
actionId: action.id,
|
|
611
927
|
type: action.type,
|
|
612
928
|
status: "error",
|
|
613
|
-
message:
|
|
929
|
+
message: `Connected wallet ${sender} does not match the required source wallet ${expectedWalletAddress}. Please switch accounts in your wallet and retry.`
|
|
614
930
|
};
|
|
615
931
|
}
|
|
616
|
-
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
functionName: "allowance",
|
|
625
|
-
args: [address, tokenAddress, spenderAddress]
|
|
626
|
-
});
|
|
627
|
-
onChainNonce = chainNonce;
|
|
628
|
-
if (metadataAmount) {
|
|
629
|
-
const requiredSmallestUnit = BigInt(metadataAmount);
|
|
630
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
631
|
-
if (existingAmount >= requiredSmallestUnit && existingExpiration > now) {
|
|
632
|
-
return {
|
|
633
|
-
actionId: action.id,
|
|
634
|
-
type: action.type,
|
|
635
|
-
status: "success",
|
|
636
|
-
message: `Permit2 allowance already sufficient (${existingAmount.toString()}). Skipped.`,
|
|
637
|
-
data: { skipped: true, existingAllowance: existingAmount.toString() }
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
} catch {
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
const allowanceSelection = await new Promise((resolve) => {
|
|
645
|
-
allowanceSelectionResolverRef.current = resolve;
|
|
646
|
-
setPendingAllowanceSelection(action);
|
|
647
|
-
});
|
|
648
|
-
if (allowanceSelection.topUpAmount > 0 && sessionIdRef.current) {
|
|
649
|
-
try {
|
|
650
|
-
await updateUserConfigBySession(
|
|
932
|
+
let typedData = action.metadata?.typedData;
|
|
933
|
+
const tokenSymbol = action.metadata?.tokenSymbol;
|
|
934
|
+
if (!typedData && sessionIdRef.current) {
|
|
935
|
+
const POLL_INTERVAL_MS = 1e3;
|
|
936
|
+
const MAX_POLLS = 15;
|
|
937
|
+
for (let i = 0; i < MAX_POLLS; i++) {
|
|
938
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
939
|
+
const session = await fetchAuthorizationSession(
|
|
651
940
|
apiBaseUrl,
|
|
652
|
-
sessionIdRef.current
|
|
653
|
-
{ defaultAllowance: allowanceSelection.topUpAmount }
|
|
941
|
+
sessionIdRef.current
|
|
654
942
|
);
|
|
655
|
-
|
|
943
|
+
const updatedAction = session.actions.find((a) => a.id === action.id);
|
|
944
|
+
typedData = updatedAction?.metadata?.typedData;
|
|
945
|
+
if (typedData) break;
|
|
656
946
|
}
|
|
657
947
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
948
|
+
if (!typedData) {
|
|
949
|
+
return {
|
|
950
|
+
actionId: action.id,
|
|
951
|
+
type: action.type,
|
|
952
|
+
status: "error",
|
|
953
|
+
message: "SIGN_PERMIT2 metadata is missing typedData. The server may still be preparing the signing payload."
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
const parsedTypedData = parseSignTypedDataPayload(typedData);
|
|
957
|
+
console.info(
|
|
958
|
+
`[swype-sdk][sign-permit2] Signing typed data. expectedOwner=${expectedWalletAddress ?? "N/A"}, senderParam=${sender}, connectedAddress=${connectedAddress ?? "N/A"}, primaryType=${parsedTypedData.primaryType}, domainChainId=${String(parsedTypedData.domain.chainId ?? "N/A")}, verifyingContract=${String(parsedTypedData.domain.verifyingContract ?? "N/A")}`
|
|
661
959
|
);
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
domain: {
|
|
669
|
-
name: "Permit2",
|
|
670
|
-
chainId: permit2ChainId,
|
|
671
|
-
verifyingContract: PERMIT2_ADDRESS
|
|
672
|
-
},
|
|
673
|
-
types: {
|
|
674
|
-
PermitSingle: [
|
|
675
|
-
{ name: "details", type: "PermitDetails" },
|
|
676
|
-
{ name: "spender", type: "address" },
|
|
677
|
-
{ name: "sigDeadline", type: "uint256" }
|
|
678
|
-
],
|
|
679
|
-
PermitDetails: [
|
|
680
|
-
{ name: "token", type: "address" },
|
|
681
|
-
{ name: "amount", type: "uint160" },
|
|
682
|
-
{ name: "expiration", type: "uint48" },
|
|
683
|
-
{ name: "nonce", type: "uint48" }
|
|
684
|
-
]
|
|
685
|
-
},
|
|
686
|
-
primaryType: "PermitSingle",
|
|
687
|
-
message: {
|
|
688
|
-
details: {
|
|
689
|
-
token: tokenAddress,
|
|
690
|
-
amount: permitAmount,
|
|
691
|
-
expiration,
|
|
692
|
-
nonce
|
|
693
|
-
},
|
|
694
|
-
spender: spenderAddress,
|
|
695
|
-
sigDeadline
|
|
696
|
-
}
|
|
960
|
+
const signature = await walletClient.signTypedData({
|
|
961
|
+
account: sender,
|
|
962
|
+
domain: parsedTypedData.domain,
|
|
963
|
+
types: parsedTypedData.types,
|
|
964
|
+
primaryType: parsedTypedData.primaryType,
|
|
965
|
+
message: parsedTypedData.message
|
|
697
966
|
});
|
|
967
|
+
const recoverInput = {
|
|
968
|
+
domain: parsedTypedData.domain,
|
|
969
|
+
types: parsedTypedData.types,
|
|
970
|
+
primaryType: parsedTypedData.primaryType,
|
|
971
|
+
message: parsedTypedData.message,
|
|
972
|
+
signature
|
|
973
|
+
};
|
|
974
|
+
const recoveredSigner = await recoverTypedDataAddress(recoverInput);
|
|
975
|
+
const expectedSigner = (expectedWalletAddress ?? sender).toLowerCase();
|
|
976
|
+
console.info(
|
|
977
|
+
`[swype-sdk][sign-permit2] Signature recovered. recoveredSigner=${recoveredSigner}, expectedSigner=${expectedSigner}`
|
|
978
|
+
);
|
|
979
|
+
if (recoveredSigner.toLowerCase() !== expectedSigner) {
|
|
980
|
+
return {
|
|
981
|
+
actionId: action.id,
|
|
982
|
+
type: action.type,
|
|
983
|
+
status: "error",
|
|
984
|
+
message: `Wallet signed with ${recoveredSigner}, but source wallet is ${expectedWalletAddress ?? sender}. Please switch to the source wallet in MetaMask and retry.`
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
console.info(
|
|
988
|
+
`[swype-sdk][sign-permit2] Permit2 EIP-712 signature obtained. token=${tokenSymbol ?? "unknown"}`
|
|
989
|
+
);
|
|
698
990
|
return {
|
|
699
991
|
actionId: action.id,
|
|
700
992
|
type: action.type,
|
|
701
993
|
status: "success",
|
|
702
|
-
message:
|
|
703
|
-
data: {
|
|
704
|
-
signature,
|
|
705
|
-
signer: address,
|
|
706
|
-
nonce: nonce.toString(),
|
|
707
|
-
sigDeadline: sigDeadline.toString(),
|
|
708
|
-
expiration: expiration.toString(),
|
|
709
|
-
amount: permitAmount.toString()
|
|
710
|
-
}
|
|
994
|
+
message: `Permit2 allowance signed for ${tokenSymbol ?? "tokens"}.`,
|
|
995
|
+
data: { signature }
|
|
711
996
|
};
|
|
712
997
|
} catch (err) {
|
|
998
|
+
const message = err instanceof Error ? err.message : "Failed to sign Permit2 allowance";
|
|
999
|
+
const isRejected = message.includes("rejected") || message.includes("denied") || message.includes("user rejected");
|
|
713
1000
|
return {
|
|
714
1001
|
actionId: action.id,
|
|
715
1002
|
type: action.type,
|
|
716
1003
|
status: "error",
|
|
717
|
-
message:
|
|
1004
|
+
message: isRejected ? "You rejected the Permit2 signature request. Please approve the signature in your wallet to allow fund transfers." : message
|
|
718
1005
|
};
|
|
719
1006
|
}
|
|
720
1007
|
},
|
|
721
|
-
[
|
|
1008
|
+
[wagmiConfig2, apiBaseUrl]
|
|
722
1009
|
);
|
|
723
1010
|
const executeAction = useCallback(
|
|
724
1011
|
async (action) => {
|
|
1012
|
+
setCurrentAction(action);
|
|
725
1013
|
switch (action.type) {
|
|
726
1014
|
case "OPEN_PROVIDER":
|
|
727
1015
|
return executeOpenProvider(action);
|
|
@@ -729,7 +1017,11 @@ function useAuthorizationExecutor() {
|
|
|
729
1017
|
return executeSelectSource(action);
|
|
730
1018
|
case "SWITCH_CHAIN":
|
|
731
1019
|
return executeSwitchChain(action);
|
|
732
|
-
case "
|
|
1020
|
+
case "REGISTER_PASSKEY":
|
|
1021
|
+
return executeRegisterPasskey(action);
|
|
1022
|
+
case "CREATE_SMART_ACCOUNT":
|
|
1023
|
+
return executeCreateSmartAccount(action);
|
|
1024
|
+
case "APPROVE_PERMIT2":
|
|
733
1025
|
return executeApprovePermit2(action);
|
|
734
1026
|
case "SIGN_PERMIT2":
|
|
735
1027
|
return executeSignPermit2(action);
|
|
@@ -742,16 +1034,15 @@ function useAuthorizationExecutor() {
|
|
|
742
1034
|
};
|
|
743
1035
|
}
|
|
744
1036
|
},
|
|
745
|
-
[executeOpenProvider, executeSelectSource, executeSwitchChain, executeApprovePermit2, executeSignPermit2]
|
|
1037
|
+
[executeOpenProvider, executeSelectSource, executeSwitchChain, executeRegisterPasskey, executeCreateSmartAccount, executeApprovePermit2, executeSignPermit2]
|
|
746
1038
|
);
|
|
747
1039
|
const executeSession = useCallback(
|
|
748
1040
|
async (transfer) => {
|
|
749
1041
|
if (executingRef.current) return;
|
|
750
1042
|
executingRef.current = true;
|
|
751
1043
|
if (!transfer.authorizationSessions || transfer.authorizationSessions.length === 0) {
|
|
752
|
-
setError("No authorization sessions available.");
|
|
753
1044
|
executingRef.current = false;
|
|
754
|
-
|
|
1045
|
+
throw new Error("No authorization sessions available.");
|
|
755
1046
|
}
|
|
756
1047
|
const sessionId = transfer.authorizationSessions[0].id;
|
|
757
1048
|
sessionIdRef.current = sessionId;
|
|
@@ -773,8 +1064,7 @@ function useAuthorizationExecutor() {
|
|
|
773
1064
|
actionPollRetries++;
|
|
774
1065
|
}
|
|
775
1066
|
if (pendingActions.length === 0 && currentSession.status !== "AUTHORIZED") {
|
|
776
|
-
|
|
777
|
-
return;
|
|
1067
|
+
throw new Error("Authorization actions were not created in time. Please try again.");
|
|
778
1068
|
}
|
|
779
1069
|
while (pendingActions.length > 0) {
|
|
780
1070
|
const action = pendingActions[0];
|
|
@@ -783,8 +1073,7 @@ function useAuthorizationExecutor() {
|
|
|
783
1073
|
if (result.status === "error") {
|
|
784
1074
|
allResults.push(result);
|
|
785
1075
|
setResults([...allResults]);
|
|
786
|
-
|
|
787
|
-
break;
|
|
1076
|
+
throw new Error(result.message);
|
|
788
1077
|
}
|
|
789
1078
|
completedActionIds.add(action.id);
|
|
790
1079
|
const updatedSession = await reportActionCompletion(
|
|
@@ -796,7 +1085,6 @@ function useAuthorizationExecutor() {
|
|
|
796
1085
|
pendingActions = currentSession.actions.filter((a) => a.status === "PENDING" && !completedActionIds.has(a.id)).sort((a, b) => a.orderIndex - b.orderIndex);
|
|
797
1086
|
if (action.type === "OPEN_PROVIDER" && pendingActions.length > 0) {
|
|
798
1087
|
const chainResults = [result];
|
|
799
|
-
let chainBroken = false;
|
|
800
1088
|
while (pendingActions.length > 0) {
|
|
801
1089
|
const nextAction = pendingActions[0];
|
|
802
1090
|
const nextResult = await executeAction(nextAction);
|
|
@@ -804,9 +1092,7 @@ function useAuthorizationExecutor() {
|
|
|
804
1092
|
chainResults.push(nextResult);
|
|
805
1093
|
allResults.push(...chainResults);
|
|
806
1094
|
setResults([...allResults]);
|
|
807
|
-
|
|
808
|
-
chainBroken = true;
|
|
809
|
-
break;
|
|
1095
|
+
throw new Error(nextResult.message);
|
|
810
1096
|
}
|
|
811
1097
|
completedActionIds.add(nextAction.id);
|
|
812
1098
|
const nextSession = await reportActionCompletion(
|
|
@@ -818,7 +1104,6 @@ function useAuthorizationExecutor() {
|
|
|
818
1104
|
chainResults.push(nextResult);
|
|
819
1105
|
pendingActions = currentSession.actions.filter((a) => a.status === "PENDING" && !completedActionIds.has(a.id)).sort((a, b) => a.orderIndex - b.orderIndex);
|
|
820
1106
|
}
|
|
821
|
-
if (chainBroken) break;
|
|
822
1107
|
allResults.push(...chainResults);
|
|
823
1108
|
setResults([...allResults]);
|
|
824
1109
|
continue;
|
|
@@ -827,8 +1112,11 @@ function useAuthorizationExecutor() {
|
|
|
827
1112
|
setResults([...allResults]);
|
|
828
1113
|
}
|
|
829
1114
|
} catch (err) {
|
|
830
|
-
|
|
1115
|
+
const msg = err instanceof Error ? err.message : "Authorization failed";
|
|
1116
|
+
setError(msg);
|
|
1117
|
+
throw err;
|
|
831
1118
|
} finally {
|
|
1119
|
+
setCurrentAction(null);
|
|
832
1120
|
setExecuting(false);
|
|
833
1121
|
executingRef.current = false;
|
|
834
1122
|
}
|
|
@@ -839,13 +1127,99 @@ function useAuthorizationExecutor() {
|
|
|
839
1127
|
executing,
|
|
840
1128
|
results,
|
|
841
1129
|
error,
|
|
1130
|
+
currentAction,
|
|
842
1131
|
pendingSelectSource,
|
|
843
1132
|
resolveSelectSource,
|
|
844
|
-
pendingAllowanceSelection,
|
|
845
|
-
resolveAllowanceSelection,
|
|
846
1133
|
executeSession
|
|
847
1134
|
};
|
|
848
1135
|
}
|
|
1136
|
+
function useTransferSigning(pollIntervalMs = 2e3) {
|
|
1137
|
+
const { apiBaseUrl } = useSwypeConfig();
|
|
1138
|
+
const { getAccessToken } = usePrivy();
|
|
1139
|
+
const [signing, setSigning] = useState(false);
|
|
1140
|
+
const [signPayload, setSignPayload] = useState(null);
|
|
1141
|
+
const [error, setError] = useState(null);
|
|
1142
|
+
const signTransfer2 = useCallback(
|
|
1143
|
+
async (transferId) => {
|
|
1144
|
+
setSigning(true);
|
|
1145
|
+
setError(null);
|
|
1146
|
+
setSignPayload(null);
|
|
1147
|
+
try {
|
|
1148
|
+
const token = await getAccessToken();
|
|
1149
|
+
if (!token) {
|
|
1150
|
+
throw new Error("Could not get access token");
|
|
1151
|
+
}
|
|
1152
|
+
const MAX_POLLS = 60;
|
|
1153
|
+
let payload = null;
|
|
1154
|
+
for (let i = 0; i < MAX_POLLS; i++) {
|
|
1155
|
+
const transfer = await fetchTransfer(apiBaseUrl, token, transferId);
|
|
1156
|
+
if (transfer.signPayload) {
|
|
1157
|
+
payload = transfer.signPayload;
|
|
1158
|
+
setSignPayload(payload);
|
|
1159
|
+
break;
|
|
1160
|
+
}
|
|
1161
|
+
if (transfer.status !== "AUTHORIZED" && transfer.status !== "CREATED") {
|
|
1162
|
+
throw new Error(`Unexpected transfer status: ${transfer.status}`);
|
|
1163
|
+
}
|
|
1164
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
1165
|
+
}
|
|
1166
|
+
if (!payload) {
|
|
1167
|
+
throw new Error("Timed out waiting for sign payload. Please try again.");
|
|
1168
|
+
}
|
|
1169
|
+
const userOpHashHex = payload.userOpHash;
|
|
1170
|
+
const hashBytes = new Uint8Array(
|
|
1171
|
+
(userOpHashHex.startsWith("0x") ? userOpHashHex.slice(2) : userOpHashHex).match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
|
|
1172
|
+
);
|
|
1173
|
+
const assertion = await navigator.credentials.get({
|
|
1174
|
+
publicKey: {
|
|
1175
|
+
challenge: hashBytes,
|
|
1176
|
+
rpId: window.location.hostname,
|
|
1177
|
+
userVerification: "required",
|
|
1178
|
+
timeout: 6e4
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
if (!assertion) {
|
|
1182
|
+
throw new Error("Passkey authentication was cancelled.");
|
|
1183
|
+
}
|
|
1184
|
+
const response = assertion.response;
|
|
1185
|
+
const signature = btoa(
|
|
1186
|
+
String.fromCharCode(...new Uint8Array(response.signature))
|
|
1187
|
+
);
|
|
1188
|
+
const authenticatorData = btoa(
|
|
1189
|
+
String.fromCharCode(
|
|
1190
|
+
...new Uint8Array(response.authenticatorData)
|
|
1191
|
+
)
|
|
1192
|
+
);
|
|
1193
|
+
const clientDataJSON = btoa(
|
|
1194
|
+
String.fromCharCode(
|
|
1195
|
+
...new Uint8Array(response.clientDataJSON)
|
|
1196
|
+
)
|
|
1197
|
+
);
|
|
1198
|
+
const signedUserOp = {
|
|
1199
|
+
...payload.userOp,
|
|
1200
|
+
signature,
|
|
1201
|
+
authenticatorData,
|
|
1202
|
+
clientDataJSON
|
|
1203
|
+
};
|
|
1204
|
+
const updatedTransfer = await signTransfer(
|
|
1205
|
+
apiBaseUrl,
|
|
1206
|
+
token,
|
|
1207
|
+
transferId,
|
|
1208
|
+
signedUserOp
|
|
1209
|
+
);
|
|
1210
|
+
return updatedTransfer;
|
|
1211
|
+
} catch (err) {
|
|
1212
|
+
const msg = err instanceof Error ? err.message : "Failed to sign transfer";
|
|
1213
|
+
setError(msg);
|
|
1214
|
+
throw err;
|
|
1215
|
+
} finally {
|
|
1216
|
+
setSigning(false);
|
|
1217
|
+
}
|
|
1218
|
+
},
|
|
1219
|
+
[apiBaseUrl, getAccessToken, pollIntervalMs]
|
|
1220
|
+
);
|
|
1221
|
+
return { signing, signPayload, error, signTransfer: signTransfer2 };
|
|
1222
|
+
}
|
|
849
1223
|
function Spinner({ size = 40, label }) {
|
|
850
1224
|
const { tokens } = useSwypeConfig();
|
|
851
1225
|
return /* @__PURE__ */ jsxs(
|
|
@@ -1577,204 +1951,6 @@ function AdvancedSettings({
|
|
|
1577
1951
|
)
|
|
1578
1952
|
] });
|
|
1579
1953
|
}
|
|
1580
|
-
var TOP_UP_OPTIONS = [0, 25, 50, 100, 500];
|
|
1581
|
-
function AllowanceSelector({ action, onSelect }) {
|
|
1582
|
-
const { tokens } = useSwypeConfig();
|
|
1583
|
-
const metadataAmount = action.metadata?.amount;
|
|
1584
|
-
const tokenDecimals = Number(action.metadata?.tokenDecimals ?? 6);
|
|
1585
|
-
const currency = action.metadata?.currency ?? "USD";
|
|
1586
|
-
const transferAmountRaw = metadataAmount ? Number(BigInt(metadataAmount)) / 10 ** tokenDecimals : 0;
|
|
1587
|
-
const [selectedTopUp, setSelectedTopUp] = useState(0);
|
|
1588
|
-
const totalAllowance = transferAmountRaw + selectedTopUp;
|
|
1589
|
-
const formatAmount = (amount) => `$${amount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
1590
|
-
return /* @__PURE__ */ jsxs(
|
|
1591
|
-
"div",
|
|
1592
|
-
{
|
|
1593
|
-
style: {
|
|
1594
|
-
padding: "4px 0",
|
|
1595
|
-
textAlign: "left"
|
|
1596
|
-
},
|
|
1597
|
-
children: [
|
|
1598
|
-
/* @__PURE__ */ jsx(
|
|
1599
|
-
"h3",
|
|
1600
|
-
{
|
|
1601
|
-
style: {
|
|
1602
|
-
fontSize: "1rem",
|
|
1603
|
-
fontWeight: 600,
|
|
1604
|
-
color: tokens.text,
|
|
1605
|
-
margin: "0 0 6px 0",
|
|
1606
|
-
textAlign: "center"
|
|
1607
|
-
},
|
|
1608
|
-
children: "Set spending limit"
|
|
1609
|
-
}
|
|
1610
|
-
),
|
|
1611
|
-
/* @__PURE__ */ jsx(
|
|
1612
|
-
"p",
|
|
1613
|
-
{
|
|
1614
|
-
style: {
|
|
1615
|
-
fontSize: "0.8rem",
|
|
1616
|
-
color: tokens.textMuted,
|
|
1617
|
-
margin: "0 0 16px 0",
|
|
1618
|
-
lineHeight: 1.5,
|
|
1619
|
-
textAlign: "center"
|
|
1620
|
-
},
|
|
1621
|
-
children: "Pre-authorize a higher amount so future payments go through instantly without wallet prompts."
|
|
1622
|
-
}
|
|
1623
|
-
),
|
|
1624
|
-
/* @__PURE__ */ jsxs(
|
|
1625
|
-
"div",
|
|
1626
|
-
{
|
|
1627
|
-
style: {
|
|
1628
|
-
display: "flex",
|
|
1629
|
-
justifyContent: "space-between",
|
|
1630
|
-
alignItems: "center",
|
|
1631
|
-
padding: "10px 14px",
|
|
1632
|
-
background: tokens.bgInput,
|
|
1633
|
-
borderRadius: tokens.radius,
|
|
1634
|
-
marginBottom: "12px",
|
|
1635
|
-
fontSize: "0.825rem"
|
|
1636
|
-
},
|
|
1637
|
-
children: [
|
|
1638
|
-
/* @__PURE__ */ jsx("span", { style: { color: tokens.textSecondary }, children: "This payment" }),
|
|
1639
|
-
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 600, color: tokens.text }, children: [
|
|
1640
|
-
formatAmount(transferAmountRaw),
|
|
1641
|
-
" ",
|
|
1642
|
-
currency
|
|
1643
|
-
] })
|
|
1644
|
-
]
|
|
1645
|
-
}
|
|
1646
|
-
),
|
|
1647
|
-
/* @__PURE__ */ jsx(
|
|
1648
|
-
"div",
|
|
1649
|
-
{
|
|
1650
|
-
style: {
|
|
1651
|
-
display: "flex",
|
|
1652
|
-
flexDirection: "column",
|
|
1653
|
-
gap: "6px",
|
|
1654
|
-
marginBottom: "16px"
|
|
1655
|
-
},
|
|
1656
|
-
children: TOP_UP_OPTIONS.map((topUp) => {
|
|
1657
|
-
const isSelected = selectedTopUp === topUp;
|
|
1658
|
-
const total = transferAmountRaw + topUp;
|
|
1659
|
-
const label = topUp === 0 ? "Just this payment" : `+${formatAmount(topUp)} for future payments`;
|
|
1660
|
-
return /* @__PURE__ */ jsxs(
|
|
1661
|
-
"button",
|
|
1662
|
-
{
|
|
1663
|
-
onClick: () => setSelectedTopUp(topUp),
|
|
1664
|
-
style: {
|
|
1665
|
-
display: "flex",
|
|
1666
|
-
alignItems: "center",
|
|
1667
|
-
justifyContent: "space-between",
|
|
1668
|
-
width: "100%",
|
|
1669
|
-
padding: "12px 14px",
|
|
1670
|
-
background: isSelected ? tokens.accent + "14" : "transparent",
|
|
1671
|
-
border: `1.5px solid ${isSelected ? tokens.accent : tokens.border}`,
|
|
1672
|
-
borderRadius: tokens.radius,
|
|
1673
|
-
cursor: "pointer",
|
|
1674
|
-
color: tokens.text,
|
|
1675
|
-
fontFamily: "inherit",
|
|
1676
|
-
fontSize: "0.825rem",
|
|
1677
|
-
textAlign: "left",
|
|
1678
|
-
outline: "none",
|
|
1679
|
-
transition: "all 0.12s ease"
|
|
1680
|
-
},
|
|
1681
|
-
children: [
|
|
1682
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
1683
|
-
/* @__PURE__ */ jsx(
|
|
1684
|
-
"div",
|
|
1685
|
-
{
|
|
1686
|
-
style: {
|
|
1687
|
-
width: 16,
|
|
1688
|
-
height: 16,
|
|
1689
|
-
borderRadius: "50%",
|
|
1690
|
-
border: `2px solid ${isSelected ? tokens.accent : tokens.border}`,
|
|
1691
|
-
display: "flex",
|
|
1692
|
-
alignItems: "center",
|
|
1693
|
-
justifyContent: "center",
|
|
1694
|
-
flexShrink: 0
|
|
1695
|
-
},
|
|
1696
|
-
children: isSelected && /* @__PURE__ */ jsx(
|
|
1697
|
-
"div",
|
|
1698
|
-
{
|
|
1699
|
-
style: {
|
|
1700
|
-
width: 8,
|
|
1701
|
-
height: 8,
|
|
1702
|
-
borderRadius: "50%",
|
|
1703
|
-
background: tokens.accent
|
|
1704
|
-
}
|
|
1705
|
-
}
|
|
1706
|
-
)
|
|
1707
|
-
}
|
|
1708
|
-
),
|
|
1709
|
-
/* @__PURE__ */ jsx("span", { style: { fontWeight: isSelected ? 600 : 400 }, children: label })
|
|
1710
|
-
] }),
|
|
1711
|
-
/* @__PURE__ */ jsx(
|
|
1712
|
-
"span",
|
|
1713
|
-
{
|
|
1714
|
-
style: {
|
|
1715
|
-
fontWeight: 600,
|
|
1716
|
-
color: isSelected ? tokens.accent : tokens.textMuted,
|
|
1717
|
-
fontSize: "0.8rem",
|
|
1718
|
-
flexShrink: 0,
|
|
1719
|
-
marginLeft: "8px"
|
|
1720
|
-
},
|
|
1721
|
-
children: formatAmount(total)
|
|
1722
|
-
}
|
|
1723
|
-
)
|
|
1724
|
-
]
|
|
1725
|
-
},
|
|
1726
|
-
topUp
|
|
1727
|
-
);
|
|
1728
|
-
})
|
|
1729
|
-
}
|
|
1730
|
-
),
|
|
1731
|
-
/* @__PURE__ */ jsxs(
|
|
1732
|
-
"div",
|
|
1733
|
-
{
|
|
1734
|
-
style: {
|
|
1735
|
-
display: "flex",
|
|
1736
|
-
justifyContent: "space-between",
|
|
1737
|
-
alignItems: "center",
|
|
1738
|
-
padding: "10px 14px",
|
|
1739
|
-
background: tokens.bgInput,
|
|
1740
|
-
borderRadius: tokens.radius,
|
|
1741
|
-
marginBottom: "14px",
|
|
1742
|
-
fontSize: "0.825rem"
|
|
1743
|
-
},
|
|
1744
|
-
children: [
|
|
1745
|
-
/* @__PURE__ */ jsx("span", { style: { color: tokens.textSecondary }, children: "Total authorization" }),
|
|
1746
|
-
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 700, color: tokens.text, fontSize: "0.9rem" }, children: [
|
|
1747
|
-
formatAmount(totalAllowance),
|
|
1748
|
-
" ",
|
|
1749
|
-
currency
|
|
1750
|
-
] })
|
|
1751
|
-
]
|
|
1752
|
-
}
|
|
1753
|
-
),
|
|
1754
|
-
/* @__PURE__ */ jsx(
|
|
1755
|
-
"button",
|
|
1756
|
-
{
|
|
1757
|
-
onClick: () => onSelect({ topUpAmount: selectedTopUp }),
|
|
1758
|
-
style: {
|
|
1759
|
-
width: "100%",
|
|
1760
|
-
padding: "14px",
|
|
1761
|
-
background: tokens.accent,
|
|
1762
|
-
color: tokens.accentText,
|
|
1763
|
-
border: "none",
|
|
1764
|
-
borderRadius: tokens.radius,
|
|
1765
|
-
fontSize: "1rem",
|
|
1766
|
-
fontWeight: 600,
|
|
1767
|
-
cursor: "pointer",
|
|
1768
|
-
transition: "background 0.15s ease",
|
|
1769
|
-
fontFamily: "inherit"
|
|
1770
|
-
},
|
|
1771
|
-
children: "Authorize & Sign"
|
|
1772
|
-
}
|
|
1773
|
-
)
|
|
1774
|
-
]
|
|
1775
|
-
}
|
|
1776
|
-
);
|
|
1777
|
-
}
|
|
1778
1954
|
function isMobile() {
|
|
1779
1955
|
if (typeof navigator === "undefined") return false;
|
|
1780
1956
|
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
@@ -1785,11 +1961,11 @@ function computeSmartDefaults(accts, transferAmount) {
|
|
|
1785
1961
|
if (accts.length === 0) return null;
|
|
1786
1962
|
for (const acct of accts) {
|
|
1787
1963
|
for (const wallet of acct.wallets) {
|
|
1788
|
-
if (wallet.status === "ACTIVE"
|
|
1789
|
-
const
|
|
1790
|
-
(s) => s.
|
|
1964
|
+
if (wallet.status === "ACTIVE") {
|
|
1965
|
+
const bestSource = wallet.sources.find(
|
|
1966
|
+
(s) => s.balance.available.amount >= transferAmount
|
|
1791
1967
|
);
|
|
1792
|
-
if (
|
|
1968
|
+
if (bestSource) {
|
|
1793
1969
|
return { accountId: acct.id, walletId: wallet.id };
|
|
1794
1970
|
}
|
|
1795
1971
|
}
|
|
@@ -1846,6 +2022,7 @@ function SwypePayment({
|
|
|
1846
2022
|
const pollingTransferIdRef = useRef(null);
|
|
1847
2023
|
const authExecutor = useAuthorizationExecutor();
|
|
1848
2024
|
const polling = useTransferPolling();
|
|
2025
|
+
const transferSigning = useTransferSigning();
|
|
1849
2026
|
const sourceType = connectingNewAccount ? "providerId" : selectedWalletId ? "walletId" : selectedAccountId ? "accountId" : "providerId";
|
|
1850
2027
|
const sourceId = connectingNewAccount ? selectedProviderId ?? "" : selectedWalletId ? selectedWalletId : selectedAccountId ? selectedAccountId : selectedProviderId ?? "";
|
|
1851
2028
|
useEffect(() => {
|
|
@@ -2025,9 +2202,11 @@ function SwypePayment({
|
|
|
2025
2202
|
await authExecutor.executeSession(t);
|
|
2026
2203
|
}
|
|
2027
2204
|
}
|
|
2205
|
+
const signedTransfer = await transferSigning.signTransfer(t.id);
|
|
2206
|
+
setTransfer(signedTransfer);
|
|
2028
2207
|
polling.startPolling(t.id);
|
|
2029
2208
|
} catch (err) {
|
|
2030
|
-
const msg = err instanceof Error ? err.message : "Transfer
|
|
2209
|
+
const msg = err instanceof Error ? err.message : "Transfer failed";
|
|
2031
2210
|
setError(msg);
|
|
2032
2211
|
onError?.(msg);
|
|
2033
2212
|
setStep("ready");
|
|
@@ -2042,6 +2221,7 @@ function SwypePayment({
|
|
|
2042
2221
|
apiBaseUrl,
|
|
2043
2222
|
getAccessToken,
|
|
2044
2223
|
authExecutor,
|
|
2224
|
+
transferSigning,
|
|
2045
2225
|
polling,
|
|
2046
2226
|
onError
|
|
2047
2227
|
]);
|
|
@@ -2510,17 +2690,73 @@ function SwypePayment({
|
|
|
2510
2690
|
] });
|
|
2511
2691
|
}
|
|
2512
2692
|
if (step === "processing") {
|
|
2513
|
-
if (
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
{
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
}
|
|
2520
|
-
|
|
2693
|
+
if (transferSigning.signing && transferSigning.signPayload) {
|
|
2694
|
+
const payload = transferSigning.signPayload;
|
|
2695
|
+
return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "16px 0" }, children: [
|
|
2696
|
+
/* @__PURE__ */ jsxs("svg", { width: "48", height: "48", viewBox: "0 0 48 48", fill: "none", style: { margin: "0 auto 16px" }, children: [
|
|
2697
|
+
/* @__PURE__ */ jsx("rect", { width: "48", height: "48", rx: "12", fill: tokens.accent + "20" }),
|
|
2698
|
+
/* @__PURE__ */ jsx("path", { d: "M24 14v8M20 18h8M24 26v2M24 32v2", stroke: tokens.accent, strokeWidth: "2", strokeLinecap: "round" })
|
|
2699
|
+
] }),
|
|
2700
|
+
/* @__PURE__ */ jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Authorize Transfer" }),
|
|
2701
|
+
/* @__PURE__ */ jsx("p", { style: { fontSize: "0.85rem", color: tokens.textSecondary, margin: "0 0 16px 0", lineHeight: 1.5 }, children: "Use your passkey to confirm this payment." }),
|
|
2702
|
+
/* @__PURE__ */ jsxs("div", { style: { fontSize: "0.825rem", color: tokens.textSecondary, padding: "12px 14px", background: tokens.bgInput, borderRadius: tokens.radius, textAlign: "left", lineHeight: 1.7, marginBottom: "16px" }, children: [
|
|
2703
|
+
payload.amount && payload.tokenSymbol && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
2704
|
+
/* @__PURE__ */ jsx("span", { children: "Amount" }),
|
|
2705
|
+
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 600, color: tokens.text }, children: [
|
|
2706
|
+
payload.amount,
|
|
2707
|
+
" ",
|
|
2708
|
+
payload.tokenSymbol
|
|
2709
|
+
] })
|
|
2710
|
+
] }),
|
|
2711
|
+
payload.bridgeRelayAddress && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
2712
|
+
/* @__PURE__ */ jsx("span", { children: "Bridge relay" }),
|
|
2713
|
+
/* @__PURE__ */ jsxs("span", { style: { fontFamily: '"SF Mono", "Fira Code", monospace', fontSize: "0.75rem" }, children: [
|
|
2714
|
+
payload.bridgeRelayAddress.slice(0, 6),
|
|
2715
|
+
"...",
|
|
2716
|
+
payload.bridgeRelayAddress.slice(-4)
|
|
2717
|
+
] })
|
|
2718
|
+
] }),
|
|
2719
|
+
payload.estimatedFeeUsd && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
2720
|
+
/* @__PURE__ */ jsx("span", { children: "Est. fee" }),
|
|
2721
|
+
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
|
|
2722
|
+
"$",
|
|
2723
|
+
payload.estimatedFeeUsd
|
|
2724
|
+
] })
|
|
2725
|
+
] })
|
|
2726
|
+
] }),
|
|
2727
|
+
/* @__PURE__ */ jsx(Spinner, { label: "Waiting for passkey..." })
|
|
2728
|
+
] }) });
|
|
2521
2729
|
}
|
|
2522
|
-
const
|
|
2523
|
-
const
|
|
2730
|
+
const currentActionType = authExecutor.currentAction?.type;
|
|
2731
|
+
const getRegistrationMessage = () => {
|
|
2732
|
+
switch (currentActionType) {
|
|
2733
|
+
case "REGISTER_PASSKEY":
|
|
2734
|
+
return {
|
|
2735
|
+
label: "Creating your passkey...",
|
|
2736
|
+
description: "Set up a passkey for secure, one-touch payments."
|
|
2737
|
+
};
|
|
2738
|
+
case "CREATE_SMART_ACCOUNT":
|
|
2739
|
+
return {
|
|
2740
|
+
label: "Creating your smart account...",
|
|
2741
|
+
description: "Setting up your smart account for gasless payments."
|
|
2742
|
+
};
|
|
2743
|
+
case "APPROVE_PERMIT2":
|
|
2744
|
+
return {
|
|
2745
|
+
label: "Approving token access...",
|
|
2746
|
+
description: "Approve the prompt in your wallet to allow secure token transfers."
|
|
2747
|
+
};
|
|
2748
|
+
case "SIGN_PERMIT2":
|
|
2749
|
+
return {
|
|
2750
|
+
label: "Signing transfer permission...",
|
|
2751
|
+
description: "Sign the permit to allow your smart account to transfer tokens on your behalf."
|
|
2752
|
+
};
|
|
2753
|
+
default:
|
|
2754
|
+
return { label: "", description: "" };
|
|
2755
|
+
}
|
|
2756
|
+
};
|
|
2757
|
+
const regMsg = getRegistrationMessage();
|
|
2758
|
+
const statusLabel = creatingTransfer ? "Creating transfer..." : mobileFlow ? "Waiting for authorization..." : authExecutor.executing && regMsg.label ? regMsg.label : authExecutor.executing ? "Authorizing..." : transferSigning.signing ? "Preparing transfer..." : polling.isPolling ? "Processing payment..." : "Please wait...";
|
|
2759
|
+
const statusDescription = creatingTransfer ? "Setting up your transfer..." : mobileFlow ? "Complete the authorization in your wallet app, then return here." : authExecutor.executing && regMsg.description ? regMsg.description : authExecutor.executing ? "Complete the wallet prompts to authorize this payment." : transferSigning.signing ? "Waiting for backend to prepare your transfer payload..." : polling.isPolling ? "Your payment is being processed. This usually takes a few moments." : "Hang tight...";
|
|
2524
2760
|
return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "16px 0" }, children: [
|
|
2525
2761
|
/* @__PURE__ */ jsx(Spinner, { size: 48 }),
|
|
2526
2762
|
/* @__PURE__ */ jsx(
|
|
@@ -2564,11 +2800,11 @@ function SwypePayment({
|
|
|
2564
2800
|
},
|
|
2565
2801
|
r.actionId
|
|
2566
2802
|
)) }),
|
|
2567
|
-
(error || authExecutor.error || polling.error) && /* @__PURE__ */ jsx(
|
|
2803
|
+
(error || authExecutor.error || transferSigning.error || polling.error) && /* @__PURE__ */ jsx(
|
|
2568
2804
|
"div",
|
|
2569
2805
|
{
|
|
2570
2806
|
style: { ...errorStyle, marginTop: "16px", textAlign: "left" },
|
|
2571
|
-
children: error || authExecutor.error || polling.error
|
|
2807
|
+
children: error || authExecutor.error || transferSigning.error || polling.error
|
|
2572
2808
|
}
|
|
2573
2809
|
)
|
|
2574
2810
|
] }) });
|