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