@swype-org/react-sdk 0.1.1 → 0.1.3
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 +1766 -623
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -5
- package/dist/index.d.ts +87 -5
- package/dist/index.js +1768 -626
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,8 @@ var wagmi = require('wagmi');
|
|
|
6
6
|
var chains = require('wagmi/chains');
|
|
7
7
|
var reactQuery = require('@tanstack/react-query');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
var viem = require('viem');
|
|
10
|
+
var utils = require('viem/utils');
|
|
9
11
|
|
|
10
12
|
var __defProp = Object.defineProperty;
|
|
11
13
|
var __export = (target, all) => {
|
|
@@ -84,13 +86,19 @@ function SwypeProvider({
|
|
|
84
86
|
if (!queryClientRef.current) {
|
|
85
87
|
queryClientRef.current = new reactQuery.QueryClient();
|
|
86
88
|
}
|
|
89
|
+
const [depositAmount, setDepositAmountRaw] = react.useState(null);
|
|
90
|
+
const setDepositAmount = react.useCallback((amount) => {
|
|
91
|
+
setDepositAmountRaw(amount);
|
|
92
|
+
}, []);
|
|
87
93
|
const value = react.useMemo(
|
|
88
94
|
() => ({
|
|
89
95
|
apiBaseUrl,
|
|
90
96
|
theme,
|
|
91
|
-
tokens: getTheme(theme)
|
|
97
|
+
tokens: getTheme(theme),
|
|
98
|
+
depositAmount,
|
|
99
|
+
setDepositAmount
|
|
92
100
|
}),
|
|
93
|
-
[apiBaseUrl, theme]
|
|
101
|
+
[apiBaseUrl, theme, depositAmount, setDepositAmount]
|
|
94
102
|
);
|
|
95
103
|
return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClientRef.current, children: /* @__PURE__ */ jsxRuntime.jsx(wagmi.WagmiProvider, { config: wagmiConfig, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
104
|
reactAuth.PrivyProvider,
|
|
@@ -112,6 +120,20 @@ function useSwypeConfig() {
|
|
|
112
120
|
}
|
|
113
121
|
return ctx;
|
|
114
122
|
}
|
|
123
|
+
function useSwypeDepositAmount() {
|
|
124
|
+
const ctx = react.useContext(SwypeContext);
|
|
125
|
+
if (!ctx) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
"useSwypeDepositAmount must be used within a <SwypeProvider>"
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
/** Current deposit amount, or null if not set */
|
|
132
|
+
amount: ctx.depositAmount,
|
|
133
|
+
/** Set the deposit amount (pass null to clear) */
|
|
134
|
+
setAmount: ctx.setDepositAmount
|
|
135
|
+
};
|
|
136
|
+
}
|
|
115
137
|
|
|
116
138
|
// src/api.ts
|
|
117
139
|
var api_exports = {};
|
|
@@ -123,7 +145,9 @@ __export(api_exports, {
|
|
|
123
145
|
fetchProviders: () => fetchProviders,
|
|
124
146
|
fetchTransfer: () => fetchTransfer,
|
|
125
147
|
reportActionCompletion: () => reportActionCompletion,
|
|
126
|
-
|
|
148
|
+
signTransfer: () => signTransfer,
|
|
149
|
+
updateUserConfig: () => updateUserConfig,
|
|
150
|
+
updateUserConfigBySession: () => updateUserConfigBySession
|
|
127
151
|
});
|
|
128
152
|
async function throwApiError(res) {
|
|
129
153
|
const body = await res.json().catch(() => null);
|
|
@@ -190,6 +214,18 @@ async function fetchTransfer(apiBaseUrl, token, transferId) {
|
|
|
190
214
|
if (!res.ok) await throwApiError(res);
|
|
191
215
|
return await res.json();
|
|
192
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
|
+
}
|
|
193
229
|
async function fetchAuthorizationSession(apiBaseUrl, sessionId) {
|
|
194
230
|
const res = await fetch(
|
|
195
231
|
`${apiBaseUrl}/v1/authorization-sessions/${sessionId}`
|
|
@@ -208,6 +244,17 @@ async function updateUserConfig(apiBaseUrl, token, config) {
|
|
|
208
244
|
});
|
|
209
245
|
if (!res.ok) await throwApiError(res);
|
|
210
246
|
}
|
|
247
|
+
async function updateUserConfigBySession(apiBaseUrl, sessionId, config) {
|
|
248
|
+
const res = await fetch(
|
|
249
|
+
`${apiBaseUrl}/v1/authorization-sessions/${sessionId}/user-config`,
|
|
250
|
+
{
|
|
251
|
+
method: "PATCH",
|
|
252
|
+
headers: { "Content-Type": "application/json" },
|
|
253
|
+
body: JSON.stringify({ config })
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
if (!res.ok) await throwApiError(res);
|
|
257
|
+
}
|
|
211
258
|
async function reportActionCompletion(apiBaseUrl, actionId, result) {
|
|
212
259
|
const res = await fetch(
|
|
213
260
|
`${apiBaseUrl}/v1/authorization-actions/${actionId}`,
|
|
@@ -220,6 +267,443 @@ async function reportActionCompletion(apiBaseUrl, actionId, result) {
|
|
|
220
267
|
if (!res.ok) await throwApiError(res);
|
|
221
268
|
return await res.json();
|
|
222
269
|
}
|
|
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
|
+
}
|
|
346
|
+
};
|
|
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
|
+
});
|
|
409
|
+
}
|
|
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 })
|
|
460
|
+
});
|
|
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
|
+
|
|
531
|
+
// src/authorization/upgrade.ts
|
|
532
|
+
function isNonEmptyString(value) {
|
|
533
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
534
|
+
}
|
|
535
|
+
function isValidChainId(value) {
|
|
536
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
537
|
+
}
|
|
538
|
+
function isRpcClient(value) {
|
|
539
|
+
return typeof value === "object" && value !== null && "request" in value && typeof value.request === "function";
|
|
540
|
+
}
|
|
541
|
+
function sleep(ms) {
|
|
542
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
543
|
+
}
|
|
544
|
+
async function pollCallsStatus(client, bundleId, label, timeoutMs = 12e4, intervalMs = 3e3) {
|
|
545
|
+
const deadline = Date.now() + timeoutMs;
|
|
546
|
+
while (Date.now() < deadline) {
|
|
547
|
+
const raw = await client.request({
|
|
548
|
+
method: "wallet_getCallsStatus",
|
|
549
|
+
params: [bundleId]
|
|
550
|
+
});
|
|
551
|
+
const result = raw;
|
|
552
|
+
const status = result.status;
|
|
553
|
+
console.info(`[swype-sdk][upgrade] ${label} status:`, status);
|
|
554
|
+
if (status === 200 || status === "CONFIRMED" || status === "confirmed") {
|
|
555
|
+
const txHash = result.receipts?.[0]?.transactionHash ?? "";
|
|
556
|
+
if (!txHash) {
|
|
557
|
+
console.warn(`[swype-sdk][upgrade] ${label}: confirmed but no receipt txHash.`);
|
|
558
|
+
}
|
|
559
|
+
return txHash;
|
|
560
|
+
}
|
|
561
|
+
if (typeof status === "number" && status >= 400) {
|
|
562
|
+
throw new Error(
|
|
563
|
+
`${label} failed with status ${status}. Receipts: ${JSON.stringify(result.receipts ?? [])}`
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
if (typeof status === "string" && (status.toLowerCase().includes("fail") || status.toLowerCase().includes("error"))) {
|
|
567
|
+
throw new Error(
|
|
568
|
+
`${label} failed: ${status}. Receipts: ${JSON.stringify(result.receipts ?? [])}`
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
await sleep(intervalMs);
|
|
572
|
+
}
|
|
573
|
+
throw new Error(`${label} timed out after ${timeoutMs / 1e3}s.`);
|
|
574
|
+
}
|
|
575
|
+
async function sendCalls(client, callsParams, label) {
|
|
576
|
+
try {
|
|
577
|
+
const result = await client.request({
|
|
578
|
+
method: "wallet_sendCalls",
|
|
579
|
+
params: [callsParams]
|
|
580
|
+
});
|
|
581
|
+
const bundleId = typeof result === "string" ? result : result?.id;
|
|
582
|
+
if (!bundleId) {
|
|
583
|
+
throw new Error(`${label}: wallet_sendCalls returned an unexpected result: ${JSON.stringify(result)}`);
|
|
584
|
+
}
|
|
585
|
+
return bundleId;
|
|
586
|
+
} catch (err) {
|
|
587
|
+
const msg = err.message ?? "";
|
|
588
|
+
if (msg.includes("Unauthorized") || msg.includes("-32006")) {
|
|
589
|
+
throw new Error(
|
|
590
|
+
"MetaMask smart accounts may not be enabled or may not be supported on this chain. Please ensure you are using a supported network and that smart accounts are enabled in MetaMask Settings \u2192 Experimental."
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
throw new Error(`${label} failed: ${msg}`);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
async function submitUpgradeTransaction(params) {
|
|
597
|
+
const { walletClient, sender, metadata } = params;
|
|
598
|
+
const addKeyCalldata = metadata?.addKeyCalldata;
|
|
599
|
+
if (!isNonEmptyString(addKeyCalldata)) {
|
|
600
|
+
throw new Error("Incomplete upgrade metadata: missing addKeyCalldata.");
|
|
601
|
+
}
|
|
602
|
+
const resolvedSmartAccountAddress = metadata?.smartAccountAddress ?? sender;
|
|
603
|
+
if (!isNonEmptyString(resolvedSmartAccountAddress)) {
|
|
604
|
+
throw new Error("No connected account address found for smart account upgrade.");
|
|
605
|
+
}
|
|
606
|
+
const chainId = metadata?.upgradePayload?.authorization?.chainId;
|
|
607
|
+
if (!isValidChainId(chainId)) {
|
|
608
|
+
throw new Error("Invalid or missing chainId in upgrade metadata.");
|
|
609
|
+
}
|
|
610
|
+
if (!isRpcClient(walletClient)) {
|
|
611
|
+
throw new Error(
|
|
612
|
+
"Connected wallet client does not support request(). EIP-7702 upgrade requires a wallet client with raw RPC access."
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
const hexChainId = `0x${chainId.toString(16)}`;
|
|
616
|
+
console.info(
|
|
617
|
+
"[swype-sdk][upgrade] Step 1/2: Triggering EIP-7702 upgrade via wallet_sendCalls.",
|
|
618
|
+
{ from: resolvedSmartAccountAddress, chainId: hexChainId }
|
|
619
|
+
);
|
|
620
|
+
const upgradeBundleId = await sendCalls(
|
|
621
|
+
walletClient,
|
|
622
|
+
{
|
|
623
|
+
version: "2.0.0",
|
|
624
|
+
from: resolvedSmartAccountAddress,
|
|
625
|
+
chainId: hexChainId,
|
|
626
|
+
atomicRequired: false,
|
|
627
|
+
calls: [{ to: resolvedSmartAccountAddress, value: "0x0" }]
|
|
628
|
+
},
|
|
629
|
+
"EIP-7702 upgrade"
|
|
630
|
+
);
|
|
631
|
+
console.info("[swype-sdk][upgrade] Upgrade bundle submitted. Polling for confirmation\u2026", {
|
|
632
|
+
bundleId: upgradeBundleId
|
|
633
|
+
});
|
|
634
|
+
const upgradeTxHash = await pollCallsStatus(
|
|
635
|
+
walletClient,
|
|
636
|
+
upgradeBundleId,
|
|
637
|
+
"EIP-7702 upgrade"
|
|
638
|
+
);
|
|
639
|
+
console.info("[swype-sdk][upgrade] Step 1/2 complete: account upgraded.", {
|
|
640
|
+
txHash: upgradeTxHash
|
|
641
|
+
});
|
|
642
|
+
console.info(
|
|
643
|
+
"[swype-sdk][upgrade] Step 2/2: Registering passkey via wallet_sendCalls (addKey)."
|
|
644
|
+
);
|
|
645
|
+
const addKeyBundleId = await sendCalls(
|
|
646
|
+
walletClient,
|
|
647
|
+
{
|
|
648
|
+
version: "2.0.0",
|
|
649
|
+
from: resolvedSmartAccountAddress,
|
|
650
|
+
chainId: hexChainId,
|
|
651
|
+
atomicRequired: false,
|
|
652
|
+
calls: [
|
|
653
|
+
{
|
|
654
|
+
to: resolvedSmartAccountAddress,
|
|
655
|
+
value: "0x0",
|
|
656
|
+
data: addKeyCalldata
|
|
657
|
+
}
|
|
658
|
+
]
|
|
659
|
+
},
|
|
660
|
+
"Passkey registration (addKey)"
|
|
661
|
+
);
|
|
662
|
+
console.info("[swype-sdk][upgrade] addKey bundle submitted. Polling for confirmation\u2026", {
|
|
663
|
+
bundleId: addKeyBundleId
|
|
664
|
+
});
|
|
665
|
+
const addKeyTxHash = await pollCallsStatus(
|
|
666
|
+
walletClient,
|
|
667
|
+
addKeyBundleId,
|
|
668
|
+
"Passkey registration"
|
|
669
|
+
);
|
|
670
|
+
console.info("[swype-sdk][upgrade] Step 2/2 complete: passkey registered.", {
|
|
671
|
+
txHash: addKeyTxHash
|
|
672
|
+
});
|
|
673
|
+
return {
|
|
674
|
+
txHash: addKeyTxHash || upgradeTxHash,
|
|
675
|
+
smartAccountAddress: resolvedSmartAccountAddress
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// src/hooks.ts
|
|
680
|
+
async function waitForWalletClient(wagmiConfig2, maxAttempts = 15, intervalMs = 200) {
|
|
681
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
682
|
+
try {
|
|
683
|
+
return await getWalletClient(wagmiConfig2);
|
|
684
|
+
} catch {
|
|
685
|
+
if (i === maxAttempts - 1) {
|
|
686
|
+
throw new Error("Wallet not ready. Please try again.");
|
|
687
|
+
}
|
|
688
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
throw new Error("Wallet not ready. Please try again.");
|
|
692
|
+
}
|
|
693
|
+
function extractErrorMessage(err) {
|
|
694
|
+
if (err instanceof Error) return err.message;
|
|
695
|
+
if (typeof err === "string") return err;
|
|
696
|
+
if (err && typeof err === "object") {
|
|
697
|
+
const maybeMessage = err.message;
|
|
698
|
+
if (typeof maybeMessage === "string") return maybeMessage;
|
|
699
|
+
}
|
|
700
|
+
return "Failed to upgrade account";
|
|
701
|
+
}
|
|
702
|
+
function isMetaMaskConnector(account) {
|
|
703
|
+
const connectorName = account.connector?.name?.toLowerCase() ?? "";
|
|
704
|
+
const connectorId = account.connector?.id?.toLowerCase() ?? "";
|
|
705
|
+
return connectorName.includes("metamask") || connectorId.includes("metamask");
|
|
706
|
+
}
|
|
223
707
|
function useTransferPolling(intervalMs = 3e3) {
|
|
224
708
|
const { apiBaseUrl } = useSwypeConfig();
|
|
225
709
|
const { getAccessToken } = reactAuth.usePrivy();
|
|
@@ -270,31 +754,45 @@ function useTransferPolling(intervalMs = 3e3) {
|
|
|
270
754
|
}
|
|
271
755
|
function useAuthorizationExecutor() {
|
|
272
756
|
const { apiBaseUrl } = useSwypeConfig();
|
|
273
|
-
const
|
|
757
|
+
const wagmiConfig2 = wagmi.useConfig();
|
|
274
758
|
const { connectAsync, connectors } = wagmi.useConnect();
|
|
275
759
|
const { switchChainAsync } = wagmi.useSwitchChain();
|
|
276
|
-
const { signTypedDataAsync } = wagmi.useSignTypedData();
|
|
277
|
-
const publicClient = wagmi.usePublicClient();
|
|
278
|
-
const { data: walletClient } = wagmi.useWalletClient();
|
|
279
760
|
const [executing, setExecuting] = react.useState(false);
|
|
280
761
|
const [results, setResults] = react.useState([]);
|
|
281
762
|
const [error, setError] = react.useState(null);
|
|
763
|
+
const [currentAction, setCurrentAction] = react.useState(null);
|
|
282
764
|
const executingRef = react.useRef(false);
|
|
765
|
+
const [pendingSelectSource, setPendingSelectSource] = react.useState(null);
|
|
766
|
+
const selectSourceResolverRef = react.useRef(null);
|
|
767
|
+
const resolveSelectSource = react.useCallback((selection) => {
|
|
768
|
+
if (selectSourceResolverRef.current) {
|
|
769
|
+
selectSourceResolverRef.current(selection);
|
|
770
|
+
selectSourceResolverRef.current = null;
|
|
771
|
+
setPendingSelectSource(null);
|
|
772
|
+
}
|
|
773
|
+
}, []);
|
|
774
|
+
const sessionIdRef = react.useRef(null);
|
|
283
775
|
const executeOpenProvider = react.useCallback(
|
|
284
776
|
async (action) => {
|
|
285
777
|
try {
|
|
286
|
-
|
|
287
|
-
|
|
778
|
+
const account = getAccount(wagmiConfig2);
|
|
779
|
+
if (account.isConnected && account.address) {
|
|
780
|
+
const hexChainId2 = account.chainId ? `0x${account.chainId.toString(16)}` : void 0;
|
|
288
781
|
return {
|
|
289
782
|
actionId: action.id,
|
|
290
783
|
type: action.type,
|
|
291
784
|
status: "success",
|
|
292
|
-
message: `Connected. Account: ${address}, Chain: ${hexChainId2}`,
|
|
293
|
-
data: { accounts: [address], chainId: hexChainId2 }
|
|
785
|
+
message: `Connected. Account: ${account.address}, Chain: ${hexChainId2}`,
|
|
786
|
+
data: { accounts: [account.address], chainId: hexChainId2 }
|
|
294
787
|
};
|
|
295
788
|
}
|
|
296
789
|
const targetId = action.metadata?.wagmiConnectorId;
|
|
297
|
-
const
|
|
790
|
+
const metaMaskConnector = connectors.find((c) => {
|
|
791
|
+
const id = c.id.toLowerCase();
|
|
792
|
+
const name = c.name.toLowerCase();
|
|
793
|
+
return id.includes("metamask") || name.includes("metamask");
|
|
794
|
+
});
|
|
795
|
+
const connector = targetId ? connectors.find((c) => c.id === targetId) ?? metaMaskConnector ?? connectors[0] : metaMaskConnector ?? connectors[0];
|
|
298
796
|
if (!connector) {
|
|
299
797
|
return {
|
|
300
798
|
actionId: action.id,
|
|
@@ -321,243 +819,231 @@ function useAuthorizationExecutor() {
|
|
|
321
819
|
};
|
|
322
820
|
}
|
|
323
821
|
},
|
|
324
|
-
[
|
|
822
|
+
[wagmiConfig2, connectors, connectAsync]
|
|
325
823
|
);
|
|
326
|
-
const
|
|
824
|
+
const executeSelectSource = react.useCallback(
|
|
327
825
|
async (action) => {
|
|
328
826
|
try {
|
|
329
|
-
const
|
|
330
|
-
|
|
827
|
+
const options = action.metadata?.options;
|
|
828
|
+
const recommended = action.metadata?.recommended;
|
|
829
|
+
if (!options || options.length <= 1) {
|
|
830
|
+
const selection2 = recommended ?? { chainName: "Base", tokenSymbol: "USDC" };
|
|
331
831
|
return {
|
|
332
832
|
actionId: action.id,
|
|
333
833
|
type: action.type,
|
|
334
|
-
status: "
|
|
335
|
-
message:
|
|
834
|
+
status: "success",
|
|
835
|
+
message: `Auto-selected ${selection2.tokenSymbol} on ${selection2.chainName}.`,
|
|
836
|
+
data: {
|
|
837
|
+
selectedChainName: selection2.chainName,
|
|
838
|
+
selectedTokenSymbol: selection2.tokenSymbol
|
|
839
|
+
}
|
|
336
840
|
};
|
|
337
841
|
}
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
842
|
+
const selection = await new Promise((resolve) => {
|
|
843
|
+
selectSourceResolverRef.current = resolve;
|
|
844
|
+
setPendingSelectSource(action);
|
|
845
|
+
});
|
|
341
846
|
return {
|
|
342
847
|
actionId: action.id,
|
|
343
848
|
type: action.type,
|
|
344
849
|
status: "success",
|
|
345
|
-
message: `
|
|
346
|
-
data: {
|
|
850
|
+
message: `Selected ${selection.tokenSymbol} on ${selection.chainName}.`,
|
|
851
|
+
data: {
|
|
852
|
+
selectedChainName: selection.chainName,
|
|
853
|
+
selectedTokenSymbol: selection.tokenSymbol
|
|
854
|
+
}
|
|
347
855
|
};
|
|
348
856
|
} catch (err) {
|
|
349
857
|
return {
|
|
350
858
|
actionId: action.id,
|
|
351
859
|
type: action.type,
|
|
352
860
|
status: "error",
|
|
353
|
-
message: err instanceof Error ? err.message : "Failed to
|
|
861
|
+
message: err instanceof Error ? err.message : "Failed to select source"
|
|
354
862
|
};
|
|
355
863
|
}
|
|
356
864
|
},
|
|
357
|
-
[
|
|
865
|
+
[]
|
|
358
866
|
);
|
|
359
|
-
const
|
|
867
|
+
const executeSwitchChain = react.useCallback(
|
|
360
868
|
async (action) => {
|
|
361
869
|
try {
|
|
362
|
-
const
|
|
363
|
-
const
|
|
364
|
-
if (!
|
|
870
|
+
const account = getAccount(wagmiConfig2);
|
|
871
|
+
const targetChainIdHex = action.metadata?.targetChainId;
|
|
872
|
+
if (!targetChainIdHex) {
|
|
365
873
|
return {
|
|
366
874
|
actionId: action.id,
|
|
367
875
|
type: action.type,
|
|
368
876
|
status: "error",
|
|
369
|
-
message: "
|
|
877
|
+
message: "No targetChainId in action metadata."
|
|
370
878
|
};
|
|
371
879
|
}
|
|
372
|
-
|
|
880
|
+
const targetChainIdNum = parseInt(targetChainIdHex, 16);
|
|
881
|
+
const hexChainId = `0x${targetChainIdNum.toString(16)}`;
|
|
882
|
+
if (account.chainId === targetChainIdNum) {
|
|
373
883
|
return {
|
|
374
884
|
actionId: action.id,
|
|
375
885
|
type: action.type,
|
|
376
|
-
status: "
|
|
377
|
-
message:
|
|
886
|
+
status: "success",
|
|
887
|
+
message: `Already on chain ${hexChainId}. Skipped.`,
|
|
888
|
+
data: { chainId: hexChainId, switched: false }
|
|
378
889
|
};
|
|
379
890
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
891
|
+
await switchChainAsync({ chainId: targetChainIdNum });
|
|
892
|
+
return {
|
|
893
|
+
actionId: action.id,
|
|
894
|
+
type: action.type,
|
|
895
|
+
status: "success",
|
|
896
|
+
message: `Switched to chain ${hexChainId}.`,
|
|
897
|
+
data: { chainId: hexChainId, switched: true }
|
|
898
|
+
};
|
|
899
|
+
} catch (err) {
|
|
900
|
+
return {
|
|
901
|
+
actionId: action.id,
|
|
902
|
+
type: action.type,
|
|
903
|
+
status: "error",
|
|
904
|
+
message: err instanceof Error ? err.message : "Failed to switch chain"
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
[wagmiConfig2, switchChainAsync]
|
|
909
|
+
);
|
|
910
|
+
const executeRegisterPasskey = react.useCallback(
|
|
911
|
+
async (action) => {
|
|
912
|
+
try {
|
|
913
|
+
const account = getAccount(wagmiConfig2);
|
|
914
|
+
const challenge = new Uint8Array(32);
|
|
915
|
+
crypto.getRandomValues(challenge);
|
|
916
|
+
const credential = await navigator.credentials.create({
|
|
917
|
+
publicKey: {
|
|
918
|
+
challenge,
|
|
919
|
+
rp: {
|
|
920
|
+
name: "Swype",
|
|
921
|
+
id: window.location.hostname
|
|
922
|
+
},
|
|
923
|
+
user: {
|
|
924
|
+
id: new TextEncoder().encode(account.address ?? "user"),
|
|
925
|
+
name: account.address ?? "Swype User",
|
|
926
|
+
displayName: "Swype User"
|
|
927
|
+
},
|
|
928
|
+
pubKeyCredParams: [
|
|
929
|
+
{ alg: -7, type: "public-key" },
|
|
930
|
+
// ES256 (P-256)
|
|
931
|
+
{ alg: -257, type: "public-key" }
|
|
932
|
+
// RS256
|
|
398
933
|
],
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
abi: ERC20_ABI,
|
|
406
|
-
functionName: "allowance",
|
|
407
|
-
args: [address, permit2Address]
|
|
408
|
-
});
|
|
409
|
-
if (currentAllowance > 0n) {
|
|
410
|
-
return {
|
|
411
|
-
actionId: action.id,
|
|
412
|
-
type: action.type,
|
|
413
|
-
status: "success",
|
|
414
|
-
message: `Permit2 already approved (allowance: ${currentAllowance.toString()}). Skipped.`,
|
|
415
|
-
data: { skipped: true, existingAllowance: currentAllowance.toString() }
|
|
416
|
-
};
|
|
934
|
+
authenticatorSelection: {
|
|
935
|
+
authenticatorAttachment: "platform",
|
|
936
|
+
residentKey: "preferred",
|
|
937
|
+
userVerification: "required"
|
|
938
|
+
},
|
|
939
|
+
timeout: 6e4
|
|
417
940
|
}
|
|
418
|
-
}
|
|
419
|
-
if (!
|
|
941
|
+
});
|
|
942
|
+
if (!credential) {
|
|
420
943
|
return {
|
|
421
944
|
actionId: action.id,
|
|
422
945
|
type: action.type,
|
|
423
946
|
status: "error",
|
|
424
|
-
message: "
|
|
947
|
+
message: "Passkey creation was cancelled."
|
|
425
948
|
};
|
|
426
949
|
}
|
|
427
|
-
const
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
});
|
|
434
|
-
if (publicClient) {
|
|
435
|
-
await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
436
|
-
}
|
|
950
|
+
const response = credential.response;
|
|
951
|
+
const publicKeyBytes = response.getPublicKey?.();
|
|
952
|
+
const credentialId = btoa(
|
|
953
|
+
String.fromCharCode(...new Uint8Array(credential.rawId))
|
|
954
|
+
);
|
|
955
|
+
const publicKey = publicKeyBytes ? btoa(String.fromCharCode(...new Uint8Array(publicKeyBytes))) : "";
|
|
437
956
|
return {
|
|
438
957
|
actionId: action.id,
|
|
439
958
|
type: action.type,
|
|
440
959
|
status: "success",
|
|
441
|
-
message:
|
|
442
|
-
data: {
|
|
960
|
+
message: "Passkey created successfully.",
|
|
961
|
+
data: {
|
|
962
|
+
credentialId,
|
|
963
|
+
publicKey
|
|
964
|
+
}
|
|
443
965
|
};
|
|
444
966
|
} catch (err) {
|
|
445
967
|
return {
|
|
446
968
|
actionId: action.id,
|
|
447
969
|
type: action.type,
|
|
448
970
|
status: "error",
|
|
449
|
-
message: err instanceof Error ? err.message : "Failed to
|
|
971
|
+
message: err instanceof Error ? err.message : "Failed to create passkey"
|
|
450
972
|
};
|
|
451
973
|
}
|
|
452
974
|
},
|
|
453
|
-
[
|
|
975
|
+
[wagmiConfig2]
|
|
454
976
|
);
|
|
455
|
-
const
|
|
977
|
+
const executeUpgradeSmartAccount = react.useCallback(
|
|
456
978
|
async (action) => {
|
|
457
979
|
try {
|
|
458
|
-
const
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
980
|
+
const account = getAccount(wagmiConfig2);
|
|
981
|
+
const walletClient = await waitForWalletClient(wagmiConfig2);
|
|
982
|
+
const sender = account.address ?? walletClient.account?.address;
|
|
983
|
+
if (!sender) {
|
|
984
|
+
throw new Error("Wallet account not available. Please connect your wallet.");
|
|
985
|
+
}
|
|
986
|
+
if (!isMetaMaskConnector(account)) {
|
|
987
|
+
throw new Error(
|
|
988
|
+
"EIP-7702 smart account upgrade requires a MetaMask-compatible wallet. Please reconnect using MetaMask and try again."
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
const metadata = action.metadata;
|
|
992
|
+
const { txHash, smartAccountAddress } = await submitUpgradeTransaction({
|
|
993
|
+
walletClient,
|
|
994
|
+
sender,
|
|
995
|
+
metadata
|
|
996
|
+
});
|
|
997
|
+
return {
|
|
998
|
+
actionId: action.id,
|
|
999
|
+
type: action.type,
|
|
1000
|
+
status: "success",
|
|
1001
|
+
message: "Account upgrade transaction submitted.",
|
|
1002
|
+
data: {
|
|
1003
|
+
txHash,
|
|
1004
|
+
smartAccountAddress
|
|
474
1005
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
const
|
|
479
|
-
const
|
|
480
|
-
|
|
1006
|
+
};
|
|
1007
|
+
} catch (err) {
|
|
1008
|
+
console.error("Failed to upgrade account", err);
|
|
1009
|
+
const message = extractErrorMessage(err);
|
|
1010
|
+
const isRejected = message.includes("rejected") || message.includes("denied") || message.includes("user rejected");
|
|
1011
|
+
return {
|
|
1012
|
+
actionId: action.id,
|
|
1013
|
+
type: action.type,
|
|
1014
|
+
status: "error",
|
|
1015
|
+
message: isRejected ? "You rejected the upgrade transaction. Please approve the transaction prompt in your wallet to continue." : message
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
[wagmiConfig2]
|
|
1020
|
+
);
|
|
1021
|
+
const executeGrantPermissions = react.useCallback(
|
|
1022
|
+
async (action) => {
|
|
1023
|
+
try {
|
|
1024
|
+
const walletClient = await waitForWalletClient(wagmiConfig2);
|
|
1025
|
+
const signingPayload = action.metadata?.signingPayload;
|
|
1026
|
+
const tokens = action.metadata?.tokens;
|
|
1027
|
+
if (!signingPayload) {
|
|
481
1028
|
return {
|
|
482
1029
|
actionId: action.id,
|
|
483
1030
|
type: action.type,
|
|
484
1031
|
status: "error",
|
|
485
|
-
message: "
|
|
1032
|
+
message: "No signing payload in action metadata."
|
|
486
1033
|
};
|
|
487
1034
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const [existingAmount, existingExpiration] = await publicClient.readContract({
|
|
491
|
-
address: PERMIT2_ADDRESS,
|
|
492
|
-
abi: PERMIT2_ALLOWANCE_ABI,
|
|
493
|
-
functionName: "allowance",
|
|
494
|
-
args: [address, tokenAddress, spenderAddress]
|
|
495
|
-
});
|
|
496
|
-
const requiredSmallestUnit = BigInt(
|
|
497
|
-
Math.ceil(metadataAmount * 1e6)
|
|
498
|
-
);
|
|
499
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
500
|
-
if (existingAmount >= requiredSmallestUnit && existingExpiration > now) {
|
|
501
|
-
return {
|
|
502
|
-
actionId: action.id,
|
|
503
|
-
type: action.type,
|
|
504
|
-
status: "success",
|
|
505
|
-
message: `Permit2 allowance already sufficient (${existingAmount.toString()}). Skipped.`,
|
|
506
|
-
data: { skipped: true, existingAllowance: existingAmount.toString() }
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
} catch {
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
const metadataAllowance = action.metadata?.allowance;
|
|
513
|
-
const permitAmount = metadataAllowance ? BigInt(Math.ceil(metadataAllowance * 1e6)) : metadataAmount ? BigInt(Math.ceil(metadataAmount * 1e6)) : BigInt(5e6);
|
|
514
|
-
const permit2ChainId = metadataChainId ? parseInt(metadataChainId, 16) : currentChainId;
|
|
515
|
-
const nonce = Number(action.metadata?.nonce ?? 0);
|
|
516
|
-
const sigDeadline = BigInt(Math.floor(Date.now() / 1e3) + 3600);
|
|
517
|
-
const expiration = Math.floor(Date.now() / 1e3) + 30 * 24 * 60 * 60;
|
|
518
|
-
const signature = await signTypedDataAsync({
|
|
519
|
-
domain: {
|
|
520
|
-
name: "Permit2",
|
|
521
|
-
chainId: permit2ChainId,
|
|
522
|
-
verifyingContract: PERMIT2_ADDRESS
|
|
523
|
-
},
|
|
524
|
-
types: {
|
|
525
|
-
PermitSingle: [
|
|
526
|
-
{ name: "details", type: "PermitDetails" },
|
|
527
|
-
{ name: "spender", type: "address" },
|
|
528
|
-
{ name: "sigDeadline", type: "uint256" }
|
|
529
|
-
],
|
|
530
|
-
PermitDetails: [
|
|
531
|
-
{ name: "token", type: "address" },
|
|
532
|
-
{ name: "amount", type: "uint160" },
|
|
533
|
-
{ name: "expiration", type: "uint48" },
|
|
534
|
-
{ name: "nonce", type: "uint48" }
|
|
535
|
-
]
|
|
536
|
-
},
|
|
537
|
-
primaryType: "PermitSingle",
|
|
538
|
-
message: {
|
|
539
|
-
details: {
|
|
540
|
-
token: tokenAddress,
|
|
541
|
-
amount: permitAmount,
|
|
542
|
-
expiration,
|
|
543
|
-
nonce
|
|
544
|
-
},
|
|
545
|
-
spender: spenderAddress,
|
|
546
|
-
sigDeadline
|
|
547
|
-
}
|
|
1035
|
+
const signature = await walletClient.signMessage({
|
|
1036
|
+
message: JSON.stringify(signingPayload)
|
|
548
1037
|
});
|
|
1038
|
+
const tokenSummary = tokens?.map((t) => `${t.symbol} on ${t.chainName}`).join(", ") ?? "all tokens";
|
|
549
1039
|
return {
|
|
550
1040
|
actionId: action.id,
|
|
551
1041
|
type: action.type,
|
|
552
1042
|
status: "success",
|
|
553
|
-
message:
|
|
1043
|
+
message: `Permissions granted for ${tokenSummary}.`,
|
|
554
1044
|
data: {
|
|
555
|
-
signature,
|
|
556
|
-
|
|
557
|
-
nonce: nonce.toString(),
|
|
558
|
-
sigDeadline: sigDeadline.toString(),
|
|
559
|
-
expiration: expiration.toString(),
|
|
560
|
-
amount: permitAmount.toString()
|
|
1045
|
+
signedDelegation: signature,
|
|
1046
|
+
tokens
|
|
561
1047
|
}
|
|
562
1048
|
};
|
|
563
1049
|
} catch (err) {
|
|
@@ -565,23 +1051,28 @@ function useAuthorizationExecutor() {
|
|
|
565
1051
|
actionId: action.id,
|
|
566
1052
|
type: action.type,
|
|
567
1053
|
status: "error",
|
|
568
|
-
message: err instanceof Error ? err.message : "Failed to
|
|
1054
|
+
message: err instanceof Error ? err.message : "Failed to grant permissions"
|
|
569
1055
|
};
|
|
570
1056
|
}
|
|
571
1057
|
},
|
|
572
|
-
[
|
|
1058
|
+
[wagmiConfig2]
|
|
573
1059
|
);
|
|
574
1060
|
const executeAction = react.useCallback(
|
|
575
1061
|
async (action) => {
|
|
1062
|
+
setCurrentAction(action);
|
|
576
1063
|
switch (action.type) {
|
|
577
1064
|
case "OPEN_PROVIDER":
|
|
578
1065
|
return executeOpenProvider(action);
|
|
1066
|
+
case "SELECT_SOURCE":
|
|
1067
|
+
return executeSelectSource(action);
|
|
579
1068
|
case "SWITCH_CHAIN":
|
|
580
1069
|
return executeSwitchChain(action);
|
|
581
|
-
case "
|
|
582
|
-
return
|
|
583
|
-
case "
|
|
584
|
-
return
|
|
1070
|
+
case "REGISTER_PASSKEY":
|
|
1071
|
+
return executeRegisterPasskey(action);
|
|
1072
|
+
case "UPGRADE_SMART_ACCOUNT":
|
|
1073
|
+
return executeUpgradeSmartAccount(action);
|
|
1074
|
+
case "GRANT_PERMISSIONS":
|
|
1075
|
+
return executeGrantPermissions(action);
|
|
585
1076
|
default:
|
|
586
1077
|
return {
|
|
587
1078
|
actionId: action.id,
|
|
@@ -591,18 +1082,18 @@ function useAuthorizationExecutor() {
|
|
|
591
1082
|
};
|
|
592
1083
|
}
|
|
593
1084
|
},
|
|
594
|
-
[executeOpenProvider, executeSwitchChain,
|
|
1085
|
+
[executeOpenProvider, executeSelectSource, executeSwitchChain, executeRegisterPasskey, executeUpgradeSmartAccount, executeGrantPermissions]
|
|
595
1086
|
);
|
|
596
1087
|
const executeSession = react.useCallback(
|
|
597
1088
|
async (transfer) => {
|
|
598
1089
|
if (executingRef.current) return;
|
|
599
1090
|
executingRef.current = true;
|
|
600
1091
|
if (!transfer.authorizationSessions || transfer.authorizationSessions.length === 0) {
|
|
601
|
-
setError("No authorization sessions available.");
|
|
602
1092
|
executingRef.current = false;
|
|
603
|
-
|
|
1093
|
+
throw new Error("No authorization sessions available.");
|
|
604
1094
|
}
|
|
605
1095
|
const sessionId = transfer.authorizationSessions[0].id;
|
|
1096
|
+
sessionIdRef.current = sessionId;
|
|
606
1097
|
setExecuting(true);
|
|
607
1098
|
setError(null);
|
|
608
1099
|
setResults([]);
|
|
@@ -611,6 +1102,18 @@ function useAuthorizationExecutor() {
|
|
|
611
1102
|
const allResults = [];
|
|
612
1103
|
const completedActionIds = /* @__PURE__ */ new Set();
|
|
613
1104
|
let pendingActions = currentSession.actions.filter((a) => a.status === "PENDING").sort((a, b) => a.orderIndex - b.orderIndex);
|
|
1105
|
+
const ACTION_POLL_INTERVAL_MS = 500;
|
|
1106
|
+
const ACTION_POLL_MAX_RETRIES = 20;
|
|
1107
|
+
let actionPollRetries = 0;
|
|
1108
|
+
while (pendingActions.length === 0 && currentSession.status !== "AUTHORIZED" && actionPollRetries < ACTION_POLL_MAX_RETRIES) {
|
|
1109
|
+
await new Promise((r) => setTimeout(r, ACTION_POLL_INTERVAL_MS));
|
|
1110
|
+
currentSession = await fetchAuthorizationSession(apiBaseUrl, sessionId);
|
|
1111
|
+
pendingActions = currentSession.actions.filter((a) => a.status === "PENDING").sort((a, b) => a.orderIndex - b.orderIndex);
|
|
1112
|
+
actionPollRetries++;
|
|
1113
|
+
}
|
|
1114
|
+
if (pendingActions.length === 0 && currentSession.status !== "AUTHORIZED") {
|
|
1115
|
+
throw new Error("Authorization actions were not created in time. Please try again.");
|
|
1116
|
+
}
|
|
614
1117
|
while (pendingActions.length > 0) {
|
|
615
1118
|
const action = pendingActions[0];
|
|
616
1119
|
if (completedActionIds.has(action.id)) break;
|
|
@@ -618,8 +1121,7 @@ function useAuthorizationExecutor() {
|
|
|
618
1121
|
if (result.status === "error") {
|
|
619
1122
|
allResults.push(result);
|
|
620
1123
|
setResults([...allResults]);
|
|
621
|
-
|
|
622
|
-
break;
|
|
1124
|
+
throw new Error(result.message);
|
|
623
1125
|
}
|
|
624
1126
|
completedActionIds.add(action.id);
|
|
625
1127
|
const updatedSession = await reportActionCompletion(
|
|
@@ -631,7 +1133,6 @@ function useAuthorizationExecutor() {
|
|
|
631
1133
|
pendingActions = currentSession.actions.filter((a) => a.status === "PENDING" && !completedActionIds.has(a.id)).sort((a, b) => a.orderIndex - b.orderIndex);
|
|
632
1134
|
if (action.type === "OPEN_PROVIDER" && pendingActions.length > 0) {
|
|
633
1135
|
const chainResults = [result];
|
|
634
|
-
let chainBroken = false;
|
|
635
1136
|
while (pendingActions.length > 0) {
|
|
636
1137
|
const nextAction = pendingActions[0];
|
|
637
1138
|
const nextResult = await executeAction(nextAction);
|
|
@@ -639,9 +1140,7 @@ function useAuthorizationExecutor() {
|
|
|
639
1140
|
chainResults.push(nextResult);
|
|
640
1141
|
allResults.push(...chainResults);
|
|
641
1142
|
setResults([...allResults]);
|
|
642
|
-
|
|
643
|
-
chainBroken = true;
|
|
644
|
-
break;
|
|
1143
|
+
throw new Error(nextResult.message);
|
|
645
1144
|
}
|
|
646
1145
|
completedActionIds.add(nextAction.id);
|
|
647
1146
|
const nextSession = await reportActionCompletion(
|
|
@@ -653,7 +1152,6 @@ function useAuthorizationExecutor() {
|
|
|
653
1152
|
chainResults.push(nextResult);
|
|
654
1153
|
pendingActions = currentSession.actions.filter((a) => a.status === "PENDING" && !completedActionIds.has(a.id)).sort((a, b) => a.orderIndex - b.orderIndex);
|
|
655
1154
|
}
|
|
656
|
-
if (chainBroken) break;
|
|
657
1155
|
allResults.push(...chainResults);
|
|
658
1156
|
setResults([...allResults]);
|
|
659
1157
|
continue;
|
|
@@ -662,15 +1160,113 @@ function useAuthorizationExecutor() {
|
|
|
662
1160
|
setResults([...allResults]);
|
|
663
1161
|
}
|
|
664
1162
|
} catch (err) {
|
|
665
|
-
|
|
1163
|
+
const msg = err instanceof Error ? err.message : "Authorization failed";
|
|
1164
|
+
setError(msg);
|
|
1165
|
+
throw err;
|
|
666
1166
|
} finally {
|
|
1167
|
+
setCurrentAction(null);
|
|
667
1168
|
setExecuting(false);
|
|
668
1169
|
executingRef.current = false;
|
|
669
1170
|
}
|
|
670
1171
|
},
|
|
671
1172
|
[apiBaseUrl, executeAction]
|
|
672
1173
|
);
|
|
673
|
-
return {
|
|
1174
|
+
return {
|
|
1175
|
+
executing,
|
|
1176
|
+
results,
|
|
1177
|
+
error,
|
|
1178
|
+
currentAction,
|
|
1179
|
+
pendingSelectSource,
|
|
1180
|
+
resolveSelectSource,
|
|
1181
|
+
executeSession
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
function useTransferSigning(pollIntervalMs = 2e3) {
|
|
1185
|
+
const { apiBaseUrl } = useSwypeConfig();
|
|
1186
|
+
const { getAccessToken } = reactAuth.usePrivy();
|
|
1187
|
+
const [signing, setSigning] = react.useState(false);
|
|
1188
|
+
const [signPayload, setSignPayload] = react.useState(null);
|
|
1189
|
+
const [error, setError] = react.useState(null);
|
|
1190
|
+
const signTransfer2 = react.useCallback(
|
|
1191
|
+
async (transferId) => {
|
|
1192
|
+
setSigning(true);
|
|
1193
|
+
setError(null);
|
|
1194
|
+
setSignPayload(null);
|
|
1195
|
+
try {
|
|
1196
|
+
const token = await getAccessToken();
|
|
1197
|
+
if (!token) {
|
|
1198
|
+
throw new Error("Could not get access token");
|
|
1199
|
+
}
|
|
1200
|
+
const MAX_POLLS = 60;
|
|
1201
|
+
let payload = null;
|
|
1202
|
+
for (let i = 0; i < MAX_POLLS; i++) {
|
|
1203
|
+
const transfer = await fetchTransfer(apiBaseUrl, token, transferId);
|
|
1204
|
+
if (transfer.signPayload) {
|
|
1205
|
+
payload = transfer.signPayload;
|
|
1206
|
+
setSignPayload(payload);
|
|
1207
|
+
break;
|
|
1208
|
+
}
|
|
1209
|
+
if (transfer.status !== "AUTHORIZED" && transfer.status !== "CREATED") {
|
|
1210
|
+
throw new Error(`Unexpected transfer status: ${transfer.status}`);
|
|
1211
|
+
}
|
|
1212
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
1213
|
+
}
|
|
1214
|
+
if (!payload) {
|
|
1215
|
+
throw new Error("Timed out waiting for sign payload. Please try again.");
|
|
1216
|
+
}
|
|
1217
|
+
const userOpHashHex = payload.userOpHash;
|
|
1218
|
+
const hashBytes = new Uint8Array(
|
|
1219
|
+
(userOpHashHex.startsWith("0x") ? userOpHashHex.slice(2) : userOpHashHex).match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
|
|
1220
|
+
);
|
|
1221
|
+
const assertion = await navigator.credentials.get({
|
|
1222
|
+
publicKey: {
|
|
1223
|
+
challenge: hashBytes,
|
|
1224
|
+
rpId: window.location.hostname,
|
|
1225
|
+
userVerification: "required",
|
|
1226
|
+
timeout: 6e4
|
|
1227
|
+
}
|
|
1228
|
+
});
|
|
1229
|
+
if (!assertion) {
|
|
1230
|
+
throw new Error("Passkey authentication was cancelled.");
|
|
1231
|
+
}
|
|
1232
|
+
const response = assertion.response;
|
|
1233
|
+
const signature = btoa(
|
|
1234
|
+
String.fromCharCode(...new Uint8Array(response.signature))
|
|
1235
|
+
);
|
|
1236
|
+
const authenticatorData = btoa(
|
|
1237
|
+
String.fromCharCode(
|
|
1238
|
+
...new Uint8Array(response.authenticatorData)
|
|
1239
|
+
)
|
|
1240
|
+
);
|
|
1241
|
+
const clientDataJSON = btoa(
|
|
1242
|
+
String.fromCharCode(
|
|
1243
|
+
...new Uint8Array(response.clientDataJSON)
|
|
1244
|
+
)
|
|
1245
|
+
);
|
|
1246
|
+
const signedUserOp = {
|
|
1247
|
+
...payload.userOp,
|
|
1248
|
+
signature,
|
|
1249
|
+
authenticatorData,
|
|
1250
|
+
clientDataJSON
|
|
1251
|
+
};
|
|
1252
|
+
const updatedTransfer = await signTransfer(
|
|
1253
|
+
apiBaseUrl,
|
|
1254
|
+
token,
|
|
1255
|
+
transferId,
|
|
1256
|
+
signedUserOp
|
|
1257
|
+
);
|
|
1258
|
+
return updatedTransfer;
|
|
1259
|
+
} catch (err) {
|
|
1260
|
+
const msg = err instanceof Error ? err.message : "Failed to sign transfer";
|
|
1261
|
+
setError(msg);
|
|
1262
|
+
throw err;
|
|
1263
|
+
} finally {
|
|
1264
|
+
setSigning(false);
|
|
1265
|
+
}
|
|
1266
|
+
},
|
|
1267
|
+
[apiBaseUrl, getAccessToken, pollIntervalMs]
|
|
1268
|
+
);
|
|
1269
|
+
return { signing, signPayload, error, signTransfer: signTransfer2 };
|
|
674
1270
|
}
|
|
675
1271
|
function Spinner({ size = 40, label }) {
|
|
676
1272
|
const { tokens } = useSwypeConfig();
|
|
@@ -788,163 +1384,232 @@ function ProviderCard({ provider, selected, onClick }) {
|
|
|
788
1384
|
}
|
|
789
1385
|
);
|
|
790
1386
|
}
|
|
791
|
-
function
|
|
1387
|
+
function AccountDropdown({
|
|
792
1388
|
accounts,
|
|
793
|
-
|
|
794
|
-
onSelect
|
|
1389
|
+
selectedAccountId,
|
|
1390
|
+
onSelect,
|
|
1391
|
+
selectedWalletId,
|
|
1392
|
+
onWalletSelect
|
|
795
1393
|
}) {
|
|
796
1394
|
const { tokens } = useSwypeConfig();
|
|
797
|
-
const [
|
|
798
|
-
const
|
|
799
|
-
|
|
1395
|
+
const [open, setOpen] = react.useState(false);
|
|
1396
|
+
const containerRef = react.useRef(null);
|
|
1397
|
+
const selected = accounts.find((a) => a.id === selectedAccountId);
|
|
1398
|
+
const selectedWallet = selected?.wallets.find(
|
|
1399
|
+
(w) => w.id === selectedWalletId
|
|
800
1400
|
);
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
setExpandedAccountId(accountId);
|
|
807
|
-
}
|
|
808
|
-
};
|
|
809
|
-
const handleWalletClick = (account, wallet) => {
|
|
810
|
-
const isAlreadySelected = selection?.accountId === account.id && selection?.walletId === wallet.id;
|
|
811
|
-
if (isAlreadySelected) {
|
|
812
|
-
onSelect(null);
|
|
813
|
-
} else {
|
|
814
|
-
onSelect({
|
|
815
|
-
accountId: account.id,
|
|
816
|
-
walletId: wallet.id,
|
|
817
|
-
accountName: account.name,
|
|
818
|
-
walletName: wallet.name,
|
|
819
|
-
chainName: wallet.chain.name
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
|
-
const formatBalance = (wallet) => {
|
|
824
|
-
const parts = [];
|
|
825
|
-
for (const src of wallet.sources) {
|
|
826
|
-
if (src.token.status === "ACTIVE") {
|
|
827
|
-
parts.push(
|
|
828
|
-
`${src.balance.available.amount.toFixed(2)} ${src.balance.available.currency} (${src.token.symbol})`
|
|
829
|
-
);
|
|
1401
|
+
react.useEffect(() => {
|
|
1402
|
+
if (!open) return;
|
|
1403
|
+
const handleClick = (e) => {
|
|
1404
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
1405
|
+
setOpen(false);
|
|
830
1406
|
}
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
/* @__PURE__ */ jsxRuntime.
|
|
839
|
-
"
|
|
1407
|
+
};
|
|
1408
|
+
document.addEventListener("mousedown", handleClick);
|
|
1409
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
1410
|
+
}, [open]);
|
|
1411
|
+
if (accounts.length === 0) return null;
|
|
1412
|
+
const hasMultipleChoices = accounts.length > 1 || accounts.length === 1 && onWalletSelect && accounts[0].wallets.filter((w) => w.balance.available.amount > 0).length > 1;
|
|
1413
|
+
if (!hasMultipleChoices) {
|
|
1414
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1415
|
+
"div",
|
|
840
1416
|
{
|
|
841
1417
|
style: {
|
|
842
|
-
display: "
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
textTransform: "uppercase",
|
|
848
|
-
letterSpacing: "0.05em"
|
|
1418
|
+
display: "flex",
|
|
1419
|
+
alignItems: "center",
|
|
1420
|
+
gap: "6px",
|
|
1421
|
+
fontSize: "0.85rem",
|
|
1422
|
+
color: tokens.textSecondary
|
|
849
1423
|
},
|
|
850
|
-
children:
|
|
1424
|
+
children: [
|
|
1425
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: accounts[0].name }),
|
|
1426
|
+
(selectedWallet ?? accounts[0].wallets[0]) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1427
|
+
"span",
|
|
1428
|
+
{
|
|
1429
|
+
style: {
|
|
1430
|
+
fontSize: "0.75rem",
|
|
1431
|
+
color: tokens.textMuted,
|
|
1432
|
+
fontFamily: '"SF Mono", "Fira Code", monospace'
|
|
1433
|
+
},
|
|
1434
|
+
children: selectedWallet ? `${selectedWallet.chain.name} \xB7 ${selectedWallet.name}` : accounts[0].wallets[0]?.name
|
|
1435
|
+
}
|
|
1436
|
+
)
|
|
1437
|
+
]
|
|
851
1438
|
}
|
|
852
|
-
)
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
const getAccountBalance = (account) => {
|
|
1442
|
+
let total = 0;
|
|
1443
|
+
for (const w of account.wallets) {
|
|
1444
|
+
total += w.balance.available.amount;
|
|
1445
|
+
}
|
|
1446
|
+
return total > 0 ? `$${total.toFixed(2)}` : "";
|
|
1447
|
+
};
|
|
1448
|
+
const hasActiveWallet = (account) => account.wallets.some((w) => w.status === "ACTIVE");
|
|
1449
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, style: { position: "relative" }, children: [
|
|
1450
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1451
|
+
"button",
|
|
1452
|
+
{
|
|
1453
|
+
onClick: () => setOpen(!open),
|
|
1454
|
+
style: {
|
|
1455
|
+
display: "flex",
|
|
1456
|
+
alignItems: "center",
|
|
1457
|
+
gap: "6px",
|
|
1458
|
+
background: "transparent",
|
|
1459
|
+
border: "none",
|
|
1460
|
+
cursor: "pointer",
|
|
1461
|
+
padding: "4px 0",
|
|
1462
|
+
color: tokens.textSecondary,
|
|
1463
|
+
fontFamily: "inherit",
|
|
1464
|
+
fontSize: "0.85rem",
|
|
1465
|
+
outline: "none"
|
|
1466
|
+
},
|
|
1467
|
+
children: [
|
|
1468
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500, color: tokens.text }, children: selected?.name ?? "Select account" }),
|
|
1469
|
+
(selectedWallet ?? selected?.wallets?.[0]) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1470
|
+
"span",
|
|
1471
|
+
{
|
|
1472
|
+
style: {
|
|
1473
|
+
fontSize: "0.75rem",
|
|
1474
|
+
color: tokens.textMuted,
|
|
1475
|
+
fontFamily: '"SF Mono", "Fira Code", monospace'
|
|
1476
|
+
},
|
|
1477
|
+
children: selectedWallet ? `${selectedWallet.chain.name} \xB7 ${selectedWallet.name}` : selected.wallets[0].name
|
|
1478
|
+
}
|
|
1479
|
+
),
|
|
1480
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1481
|
+
"svg",
|
|
1482
|
+
{
|
|
1483
|
+
width: "12",
|
|
1484
|
+
height: "12",
|
|
1485
|
+
viewBox: "0 0 24 24",
|
|
1486
|
+
fill: "none",
|
|
1487
|
+
style: {
|
|
1488
|
+
transform: open ? "rotate(180deg)" : "rotate(0deg)",
|
|
1489
|
+
transition: "transform 0.15s ease",
|
|
1490
|
+
flexShrink: 0
|
|
1491
|
+
},
|
|
1492
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1493
|
+
"path",
|
|
1494
|
+
{
|
|
1495
|
+
d: "M7 10l5 5 5-5",
|
|
1496
|
+
stroke: tokens.textMuted,
|
|
1497
|
+
strokeWidth: "2",
|
|
1498
|
+
strokeLinecap: "round",
|
|
1499
|
+
strokeLinejoin: "round"
|
|
1500
|
+
}
|
|
1501
|
+
)
|
|
1502
|
+
}
|
|
1503
|
+
)
|
|
1504
|
+
]
|
|
1505
|
+
}
|
|
1506
|
+
),
|
|
1507
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1508
|
+
"div",
|
|
1509
|
+
{
|
|
1510
|
+
style: {
|
|
1511
|
+
position: "absolute",
|
|
1512
|
+
top: "100%",
|
|
1513
|
+
left: 0,
|
|
1514
|
+
right: 0,
|
|
1515
|
+
marginTop: "4px",
|
|
1516
|
+
background: tokens.bgCard,
|
|
1517
|
+
border: `1px solid ${tokens.border}`,
|
|
1518
|
+
borderRadius: tokens.radius,
|
|
1519
|
+
boxShadow: tokens.shadowLg,
|
|
1520
|
+
zIndex: 50,
|
|
1521
|
+
overflow: "hidden",
|
|
1522
|
+
minWidth: "220px"
|
|
1523
|
+
},
|
|
1524
|
+
children: accounts.map((account) => {
|
|
1525
|
+
const isAcctSelected = account.id === selectedAccountId;
|
|
1526
|
+
const balance = getAccountBalance(account);
|
|
1527
|
+
const active = hasActiveWallet(account);
|
|
1528
|
+
const walletsWithBalance = account.wallets.filter(
|
|
1529
|
+
(w) => w.balance.available.amount > 0
|
|
1530
|
+
);
|
|
1531
|
+
const showWallets = onWalletSelect && walletsWithBalance.length > 0;
|
|
1532
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
867
1533
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
868
1534
|
"button",
|
|
869
1535
|
{
|
|
870
|
-
onClick: () =>
|
|
1536
|
+
onClick: () => {
|
|
1537
|
+
onSelect(account.id);
|
|
1538
|
+
if (!showWallets) setOpen(false);
|
|
1539
|
+
},
|
|
871
1540
|
style: {
|
|
872
|
-
width: "100%",
|
|
873
1541
|
display: "flex",
|
|
874
1542
|
alignItems: "center",
|
|
875
1543
|
justifyContent: "space-between",
|
|
876
|
-
|
|
877
|
-
|
|
1544
|
+
width: "100%",
|
|
1545
|
+
padding: "10px 14px",
|
|
1546
|
+
background: isAcctSelected && !selectedWalletId ? tokens.accent + "12" : "transparent",
|
|
878
1547
|
border: "none",
|
|
1548
|
+
borderBottom: showWallets ? "none" : `1px solid ${tokens.border}`,
|
|
879
1549
|
cursor: "pointer",
|
|
880
1550
|
color: tokens.text,
|
|
881
1551
|
fontFamily: "inherit",
|
|
882
|
-
fontSize: "0.
|
|
883
|
-
fontWeight: 500,
|
|
1552
|
+
fontSize: "0.85rem",
|
|
884
1553
|
textAlign: "left",
|
|
885
1554
|
outline: "none",
|
|
886
|
-
transition: "background 0.
|
|
1555
|
+
transition: "background 0.1s ease"
|
|
887
1556
|
},
|
|
888
1557
|
children: [
|
|
889
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
890
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1558
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
1559
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
891
1560
|
"div",
|
|
892
1561
|
{
|
|
893
1562
|
style: {
|
|
894
|
-
width: 28,
|
|
895
|
-
height: 28,
|
|
896
|
-
borderRadius: "6px",
|
|
897
|
-
background: tokens.accent + "25",
|
|
898
1563
|
display: "flex",
|
|
899
1564
|
alignItems: "center",
|
|
900
|
-
|
|
901
|
-
fontSize: "0.75rem",
|
|
902
|
-
fontWeight: 700,
|
|
903
|
-
color: tokens.accent,
|
|
904
|
-
flexShrink: 0
|
|
1565
|
+
gap: "6px"
|
|
905
1566
|
},
|
|
906
|
-
children:
|
|
1567
|
+
children: [
|
|
1568
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: account.name }),
|
|
1569
|
+
active && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1570
|
+
"span",
|
|
1571
|
+
{
|
|
1572
|
+
style: {
|
|
1573
|
+
fontSize: "0.6rem",
|
|
1574
|
+
fontWeight: 600,
|
|
1575
|
+
color: tokens.success,
|
|
1576
|
+
background: tokens.successBg,
|
|
1577
|
+
padding: "1px 5px",
|
|
1578
|
+
borderRadius: "3px",
|
|
1579
|
+
textTransform: "uppercase",
|
|
1580
|
+
letterSpacing: "0.03em"
|
|
1581
|
+
},
|
|
1582
|
+
children: "Active"
|
|
1583
|
+
}
|
|
1584
|
+
)
|
|
1585
|
+
]
|
|
907
1586
|
}
|
|
908
1587
|
),
|
|
909
|
-
/* @__PURE__ */ jsxRuntime.
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
activeWallets.length,
|
|
921
|
-
" wallet",
|
|
922
|
-
activeWallets.length !== 1 ? "s" : ""
|
|
923
|
-
]
|
|
924
|
-
}
|
|
925
|
-
)
|
|
926
|
-
] })
|
|
1588
|
+
balance && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1589
|
+
"div",
|
|
1590
|
+
{
|
|
1591
|
+
style: {
|
|
1592
|
+
fontSize: "0.75rem",
|
|
1593
|
+
color: tokens.textMuted,
|
|
1594
|
+
marginTop: "2px"
|
|
1595
|
+
},
|
|
1596
|
+
children: balance
|
|
1597
|
+
}
|
|
1598
|
+
)
|
|
927
1599
|
] }),
|
|
928
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1600
|
+
isAcctSelected && !selectedWalletId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
929
1601
|
"svg",
|
|
930
1602
|
{
|
|
931
1603
|
width: "14",
|
|
932
1604
|
height: "14",
|
|
933
1605
|
viewBox: "0 0 24 24",
|
|
934
1606
|
fill: "none",
|
|
935
|
-
style: {
|
|
936
|
-
transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)",
|
|
937
|
-
transition: "transform 0.2s ease",
|
|
938
|
-
flexShrink: 0
|
|
939
|
-
},
|
|
1607
|
+
style: { flexShrink: 0, marginLeft: "8px" },
|
|
940
1608
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
941
1609
|
"path",
|
|
942
1610
|
{
|
|
943
|
-
d: "
|
|
944
|
-
|
|
945
|
-
strokeWidth: "2",
|
|
946
|
-
strokeLinecap: "round",
|
|
947
|
-
strokeLinejoin: "round"
|
|
1611
|
+
d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
|
|
1612
|
+
fill: tokens.accent
|
|
948
1613
|
}
|
|
949
1614
|
)
|
|
950
1615
|
}
|
|
@@ -952,128 +1617,383 @@ function AccountWalletSelector({
|
|
|
952
1617
|
]
|
|
953
1618
|
}
|
|
954
1619
|
),
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
{
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1620
|
+
showWallets && walletsWithBalance.map((wallet, wIdx) => {
|
|
1621
|
+
const isWalletSelected = isAcctSelected && wallet.id === selectedWalletId;
|
|
1622
|
+
const walletBal = wallet.balance.available.amount > 0 ? `$${wallet.balance.available.amount.toFixed(2)}` : "";
|
|
1623
|
+
const isLastWallet = wIdx === walletsWithBalance.length - 1;
|
|
1624
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1625
|
+
"button",
|
|
1626
|
+
{
|
|
1627
|
+
onClick: () => {
|
|
1628
|
+
onWalletSelect(account.id, wallet.id);
|
|
1629
|
+
setOpen(false);
|
|
1630
|
+
},
|
|
1631
|
+
style: {
|
|
1632
|
+
display: "flex",
|
|
1633
|
+
alignItems: "center",
|
|
1634
|
+
justifyContent: "space-between",
|
|
1635
|
+
width: "100%",
|
|
1636
|
+
padding: "8px 14px 8px 28px",
|
|
1637
|
+
background: isWalletSelected ? tokens.accent + "12" : "transparent",
|
|
1638
|
+
border: "none",
|
|
1639
|
+
borderBottom: isLastWallet ? `1px solid ${tokens.border}` : "none",
|
|
1640
|
+
cursor: "pointer",
|
|
1641
|
+
color: tokens.text,
|
|
1642
|
+
fontFamily: "inherit",
|
|
1643
|
+
fontSize: "0.8rem",
|
|
1644
|
+
textAlign: "left",
|
|
1645
|
+
outline: "none",
|
|
1646
|
+
transition: "background 0.1s ease"
|
|
1647
|
+
},
|
|
1648
|
+
children: [
|
|
1649
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1650
|
+
"div",
|
|
1651
|
+
{
|
|
1652
|
+
style: {
|
|
1653
|
+
display: "flex",
|
|
1654
|
+
alignItems: "center",
|
|
1655
|
+
gap: "6px",
|
|
1656
|
+
minWidth: 0,
|
|
1657
|
+
flex: 1
|
|
1658
|
+
},
|
|
1659
|
+
children: [
|
|
1660
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1661
|
+
"span",
|
|
989
1662
|
{
|
|
990
1663
|
style: {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
gap: "6px"
|
|
1664
|
+
fontWeight: 500,
|
|
1665
|
+
fontSize: "0.8rem"
|
|
994
1666
|
},
|
|
995
|
-
children:
|
|
996
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: wallet.name }),
|
|
997
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
998
|
-
"span",
|
|
999
|
-
{
|
|
1000
|
-
style: {
|
|
1001
|
-
fontSize: "0.7rem",
|
|
1002
|
-
color: tokens.textMuted,
|
|
1003
|
-
background: tokens.bgHover,
|
|
1004
|
-
padding: "1px 6px",
|
|
1005
|
-
borderRadius: "4px"
|
|
1006
|
-
},
|
|
1007
|
-
children: wallet.chain.name
|
|
1008
|
-
}
|
|
1009
|
-
)
|
|
1010
|
-
]
|
|
1667
|
+
children: wallet.chain.name
|
|
1011
1668
|
}
|
|
1012
1669
|
),
|
|
1013
1670
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1014
|
-
"
|
|
1671
|
+
"span",
|
|
1672
|
+
{
|
|
1673
|
+
style: {
|
|
1674
|
+
fontSize: "0.7rem",
|
|
1675
|
+
color: tokens.textMuted,
|
|
1676
|
+
fontFamily: '"SF Mono", "Fira Code", monospace'
|
|
1677
|
+
},
|
|
1678
|
+
children: wallet.name
|
|
1679
|
+
}
|
|
1680
|
+
),
|
|
1681
|
+
walletBal && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1682
|
+
"span",
|
|
1015
1683
|
{
|
|
1016
1684
|
style: {
|
|
1017
|
-
fontSize: "0.
|
|
1018
|
-
color: tokens.
|
|
1019
|
-
|
|
1685
|
+
fontSize: "0.7rem",
|
|
1686
|
+
color: tokens.textMuted,
|
|
1687
|
+
marginLeft: "auto"
|
|
1020
1688
|
},
|
|
1021
|
-
children:
|
|
1689
|
+
children: walletBal
|
|
1022
1690
|
}
|
|
1023
1691
|
)
|
|
1024
|
-
]
|
|
1025
|
-
|
|
1026
|
-
|
|
1692
|
+
]
|
|
1693
|
+
}
|
|
1694
|
+
),
|
|
1695
|
+
isWalletSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1696
|
+
"svg",
|
|
1697
|
+
{
|
|
1698
|
+
width: "12",
|
|
1699
|
+
height: "12",
|
|
1700
|
+
viewBox: "0 0 24 24",
|
|
1701
|
+
fill: "none",
|
|
1702
|
+
style: {
|
|
1703
|
+
flexShrink: 0,
|
|
1704
|
+
marginLeft: "8px"
|
|
1705
|
+
},
|
|
1706
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1707
|
+
"path",
|
|
1027
1708
|
{
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
viewBox: "0 0 24 24",
|
|
1031
|
-
fill: "none",
|
|
1032
|
-
style: { flexShrink: 0, marginLeft: "8px" },
|
|
1033
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1034
|
-
"path",
|
|
1035
|
-
{
|
|
1036
|
-
d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
|
|
1037
|
-
fill: tokens.accent
|
|
1038
|
-
}
|
|
1039
|
-
)
|
|
1709
|
+
d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
|
|
1710
|
+
fill: tokens.accent
|
|
1040
1711
|
}
|
|
1041
1712
|
)
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
)
|
|
1049
|
-
]
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1713
|
+
}
|
|
1714
|
+
)
|
|
1715
|
+
]
|
|
1716
|
+
},
|
|
1717
|
+
wallet.id
|
|
1718
|
+
);
|
|
1719
|
+
})
|
|
1720
|
+
] }, account.id);
|
|
1721
|
+
})
|
|
1722
|
+
}
|
|
1723
|
+
)
|
|
1724
|
+
] });
|
|
1725
|
+
}
|
|
1726
|
+
var ASSETS = ["USDC", "USDT"];
|
|
1727
|
+
function AdvancedSettings({
|
|
1728
|
+
settings,
|
|
1729
|
+
onChange,
|
|
1730
|
+
chains,
|
|
1731
|
+
providers,
|
|
1732
|
+
onConnectNewAccount,
|
|
1733
|
+
connectingNewAccount
|
|
1734
|
+
}) {
|
|
1735
|
+
const { tokens } = useSwypeConfig();
|
|
1736
|
+
const [open, setOpen] = react.useState(false);
|
|
1737
|
+
const [showProviders, setShowProviders] = react.useState(false);
|
|
1738
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "12px" }, children: [
|
|
1739
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1740
|
+
"button",
|
|
1056
1741
|
{
|
|
1742
|
+
onClick: () => setOpen(!open),
|
|
1057
1743
|
style: {
|
|
1058
|
-
marginTop: "8px",
|
|
1059
|
-
fontSize: "0.8rem",
|
|
1060
|
-
color: tokens.accent,
|
|
1061
1744
|
display: "flex",
|
|
1062
1745
|
alignItems: "center",
|
|
1063
|
-
gap: "6px"
|
|
1746
|
+
gap: "6px",
|
|
1747
|
+
background: "transparent",
|
|
1748
|
+
border: "none",
|
|
1749
|
+
cursor: "pointer",
|
|
1750
|
+
padding: "4px 0",
|
|
1751
|
+
color: tokens.textMuted,
|
|
1752
|
+
fontFamily: "inherit",
|
|
1753
|
+
fontSize: "0.8rem",
|
|
1754
|
+
fontWeight: 500,
|
|
1755
|
+
outline: "none",
|
|
1756
|
+
letterSpacing: "0.02em"
|
|
1064
1757
|
},
|
|
1065
1758
|
children: [
|
|
1066
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1067
|
-
"
|
|
1759
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1760
|
+
"svg",
|
|
1068
1761
|
{
|
|
1069
|
-
|
|
1070
|
-
|
|
1762
|
+
width: "10",
|
|
1763
|
+
height: "10",
|
|
1764
|
+
viewBox: "0 0 24 24",
|
|
1765
|
+
fill: "none",
|
|
1766
|
+
style: {
|
|
1767
|
+
transform: open ? "rotate(180deg)" : "rotate(0deg)",
|
|
1768
|
+
transition: "transform 0.15s ease"
|
|
1769
|
+
},
|
|
1770
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1771
|
+
"path",
|
|
1772
|
+
{
|
|
1773
|
+
d: "M7 10l5 5 5-5",
|
|
1774
|
+
stroke: tokens.textMuted,
|
|
1775
|
+
strokeWidth: "2.5",
|
|
1776
|
+
strokeLinecap: "round",
|
|
1777
|
+
strokeLinejoin: "round"
|
|
1778
|
+
}
|
|
1779
|
+
)
|
|
1780
|
+
}
|
|
1781
|
+
),
|
|
1782
|
+
"Advanced options"
|
|
1783
|
+
]
|
|
1784
|
+
}
|
|
1785
|
+
),
|
|
1786
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1787
|
+
"div",
|
|
1788
|
+
{
|
|
1789
|
+
style: {
|
|
1790
|
+
marginTop: "10px",
|
|
1791
|
+
padding: "14px",
|
|
1792
|
+
background: tokens.bgInput,
|
|
1793
|
+
borderRadius: tokens.radius,
|
|
1794
|
+
border: `1px solid ${tokens.border}`
|
|
1795
|
+
},
|
|
1796
|
+
children: [
|
|
1797
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "14px" }, children: [
|
|
1798
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1799
|
+
"label",
|
|
1800
|
+
{
|
|
1801
|
+
style: {
|
|
1802
|
+
display: "block",
|
|
1803
|
+
fontSize: "0.7rem",
|
|
1804
|
+
fontWeight: 600,
|
|
1805
|
+
color: tokens.textMuted,
|
|
1806
|
+
textTransform: "uppercase",
|
|
1807
|
+
letterSpacing: "0.05em",
|
|
1808
|
+
marginBottom: "6px"
|
|
1809
|
+
},
|
|
1810
|
+
children: "Asset"
|
|
1811
|
+
}
|
|
1812
|
+
),
|
|
1813
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: "6px" }, children: ASSETS.map((asset) => {
|
|
1814
|
+
const isSelected = settings.asset === asset;
|
|
1815
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1816
|
+
"button",
|
|
1817
|
+
{
|
|
1818
|
+
onClick: () => onChange({
|
|
1819
|
+
...settings,
|
|
1820
|
+
asset: isSelected ? null : asset
|
|
1821
|
+
}),
|
|
1822
|
+
style: {
|
|
1823
|
+
padding: "6px 14px",
|
|
1824
|
+
fontSize: "0.8rem",
|
|
1825
|
+
fontWeight: 600,
|
|
1826
|
+
fontFamily: "inherit",
|
|
1827
|
+
borderRadius: "6px",
|
|
1828
|
+
border: `1.5px solid ${isSelected ? tokens.accent : tokens.border}`,
|
|
1829
|
+
background: isSelected ? tokens.accent + "18" : "transparent",
|
|
1830
|
+
color: isSelected ? tokens.accent : tokens.text,
|
|
1831
|
+
cursor: "pointer",
|
|
1832
|
+
outline: "none",
|
|
1833
|
+
transition: "all 0.12s ease"
|
|
1834
|
+
},
|
|
1835
|
+
children: asset
|
|
1836
|
+
},
|
|
1837
|
+
asset
|
|
1838
|
+
);
|
|
1839
|
+
}) })
|
|
1840
|
+
] }),
|
|
1841
|
+
chains.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "14px" }, children: [
|
|
1842
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1843
|
+
"label",
|
|
1844
|
+
{
|
|
1845
|
+
style: {
|
|
1846
|
+
display: "block",
|
|
1847
|
+
fontSize: "0.7rem",
|
|
1848
|
+
fontWeight: 600,
|
|
1849
|
+
color: tokens.textMuted,
|
|
1850
|
+
textTransform: "uppercase",
|
|
1851
|
+
letterSpacing: "0.05em",
|
|
1852
|
+
marginBottom: "6px"
|
|
1853
|
+
},
|
|
1854
|
+
children: "Chain"
|
|
1855
|
+
}
|
|
1856
|
+
),
|
|
1857
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: chains.map((chain) => {
|
|
1858
|
+
const isSelected = settings.chain === chain.name;
|
|
1859
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1860
|
+
"button",
|
|
1861
|
+
{
|
|
1862
|
+
onClick: () => onChange({
|
|
1863
|
+
...settings,
|
|
1864
|
+
chain: isSelected ? null : chain.name
|
|
1865
|
+
}),
|
|
1866
|
+
style: {
|
|
1867
|
+
padding: "6px 14px",
|
|
1868
|
+
fontSize: "0.8rem",
|
|
1869
|
+
fontWeight: 600,
|
|
1870
|
+
fontFamily: "inherit",
|
|
1871
|
+
borderRadius: "6px",
|
|
1872
|
+
border: `1.5px solid ${isSelected ? tokens.accent : tokens.border}`,
|
|
1873
|
+
background: isSelected ? tokens.accent + "18" : "transparent",
|
|
1874
|
+
color: isSelected ? tokens.accent : tokens.text,
|
|
1875
|
+
cursor: "pointer",
|
|
1876
|
+
outline: "none",
|
|
1877
|
+
transition: "all 0.12s ease"
|
|
1878
|
+
},
|
|
1879
|
+
children: chain.name
|
|
1880
|
+
},
|
|
1881
|
+
chain.id
|
|
1882
|
+
);
|
|
1883
|
+
}) })
|
|
1884
|
+
] }),
|
|
1885
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: !showProviders ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1886
|
+
"button",
|
|
1887
|
+
{
|
|
1888
|
+
onClick: () => setShowProviders(true),
|
|
1889
|
+
disabled: connectingNewAccount,
|
|
1890
|
+
style: {
|
|
1891
|
+
display: "flex",
|
|
1892
|
+
alignItems: "center",
|
|
1893
|
+
gap: "6px",
|
|
1894
|
+
background: "transparent",
|
|
1895
|
+
border: `1px dashed ${tokens.border}`,
|
|
1896
|
+
borderRadius: tokens.radius,
|
|
1897
|
+
padding: "10px 14px",
|
|
1898
|
+
width: "100%",
|
|
1899
|
+
cursor: connectingNewAccount ? "not-allowed" : "pointer",
|
|
1900
|
+
color: tokens.textSecondary,
|
|
1901
|
+
fontFamily: "inherit",
|
|
1902
|
+
fontSize: "0.825rem",
|
|
1903
|
+
fontWeight: 500,
|
|
1904
|
+
outline: "none",
|
|
1905
|
+
opacity: connectingNewAccount ? 0.5 : 1,
|
|
1906
|
+
transition: "opacity 0.1s ease"
|
|
1907
|
+
},
|
|
1908
|
+
children: [
|
|
1909
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1910
|
+
"svg",
|
|
1911
|
+
{
|
|
1912
|
+
width: "14",
|
|
1913
|
+
height: "14",
|
|
1914
|
+
viewBox: "0 0 24 24",
|
|
1915
|
+
fill: "none",
|
|
1916
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1917
|
+
"path",
|
|
1918
|
+
{
|
|
1919
|
+
d: "M12 5v14M5 12h14",
|
|
1920
|
+
stroke: tokens.textMuted,
|
|
1921
|
+
strokeWidth: "2",
|
|
1922
|
+
strokeLinecap: "round"
|
|
1923
|
+
}
|
|
1924
|
+
)
|
|
1925
|
+
}
|
|
1926
|
+
),
|
|
1927
|
+
"Connect new account"
|
|
1928
|
+
]
|
|
1071
1929
|
}
|
|
1072
|
-
)
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1930
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1931
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1932
|
+
"div",
|
|
1933
|
+
{
|
|
1934
|
+
style: {
|
|
1935
|
+
display: "flex",
|
|
1936
|
+
alignItems: "center",
|
|
1937
|
+
justifyContent: "space-between",
|
|
1938
|
+
marginBottom: "8px"
|
|
1939
|
+
},
|
|
1940
|
+
children: [
|
|
1941
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1942
|
+
"label",
|
|
1943
|
+
{
|
|
1944
|
+
style: {
|
|
1945
|
+
fontSize: "0.7rem",
|
|
1946
|
+
fontWeight: 600,
|
|
1947
|
+
color: tokens.textMuted,
|
|
1948
|
+
textTransform: "uppercase",
|
|
1949
|
+
letterSpacing: "0.05em"
|
|
1950
|
+
},
|
|
1951
|
+
children: "Select provider"
|
|
1952
|
+
}
|
|
1953
|
+
),
|
|
1954
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1955
|
+
"button",
|
|
1956
|
+
{
|
|
1957
|
+
onClick: () => setShowProviders(false),
|
|
1958
|
+
style: {
|
|
1959
|
+
background: "transparent",
|
|
1960
|
+
border: "none",
|
|
1961
|
+
cursor: "pointer",
|
|
1962
|
+
color: tokens.textMuted,
|
|
1963
|
+
fontSize: "0.75rem",
|
|
1964
|
+
fontFamily: "inherit",
|
|
1965
|
+
outline: "none",
|
|
1966
|
+
padding: "2px 4px"
|
|
1967
|
+
},
|
|
1968
|
+
children: "Cancel"
|
|
1969
|
+
}
|
|
1970
|
+
)
|
|
1971
|
+
]
|
|
1972
|
+
}
|
|
1973
|
+
),
|
|
1974
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1975
|
+
"div",
|
|
1976
|
+
{
|
|
1977
|
+
style: {
|
|
1978
|
+
display: "flex",
|
|
1979
|
+
flexDirection: "column",
|
|
1980
|
+
gap: "6px"
|
|
1981
|
+
},
|
|
1982
|
+
children: providers.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1983
|
+
ProviderCard,
|
|
1984
|
+
{
|
|
1985
|
+
provider: p,
|
|
1986
|
+
selected: false,
|
|
1987
|
+
onClick: () => {
|
|
1988
|
+
onConnectNewAccount(p.id);
|
|
1989
|
+
setShowProviders(false);
|
|
1990
|
+
}
|
|
1991
|
+
},
|
|
1992
|
+
p.id
|
|
1993
|
+
))
|
|
1994
|
+
}
|
|
1995
|
+
)
|
|
1996
|
+
] }) })
|
|
1077
1997
|
]
|
|
1078
1998
|
}
|
|
1079
1999
|
)
|
|
@@ -1085,69 +2005,135 @@ function isMobile() {
|
|
|
1085
2005
|
navigator.userAgent
|
|
1086
2006
|
);
|
|
1087
2007
|
}
|
|
2008
|
+
function computeSmartDefaults(accts, transferAmount) {
|
|
2009
|
+
if (accts.length === 0) return null;
|
|
2010
|
+
for (const acct of accts) {
|
|
2011
|
+
for (const wallet of acct.wallets) {
|
|
2012
|
+
if (wallet.status === "ACTIVE") {
|
|
2013
|
+
const bestSource = wallet.sources.find(
|
|
2014
|
+
(s) => s.balance.available.amount >= transferAmount
|
|
2015
|
+
);
|
|
2016
|
+
if (bestSource) {
|
|
2017
|
+
return { accountId: acct.id, walletId: wallet.id };
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
let bestAccount = null;
|
|
2023
|
+
let bestWallet = null;
|
|
2024
|
+
let bestBalance = -1;
|
|
2025
|
+
for (const acct of accts) {
|
|
2026
|
+
for (const wallet of acct.wallets) {
|
|
2027
|
+
const walletBal = wallet.balance.available.amount;
|
|
2028
|
+
if (walletBal > bestBalance) {
|
|
2029
|
+
bestBalance = walletBal;
|
|
2030
|
+
bestAccount = acct;
|
|
2031
|
+
bestWallet = wallet;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
if (bestAccount) {
|
|
2036
|
+
return {
|
|
2037
|
+
accountId: bestAccount.id,
|
|
2038
|
+
walletId: bestWallet?.id ?? null
|
|
2039
|
+
};
|
|
2040
|
+
}
|
|
2041
|
+
return { accountId: accts[0].id, walletId: null };
|
|
2042
|
+
}
|
|
1088
2043
|
function SwypePayment({
|
|
1089
2044
|
destination,
|
|
1090
2045
|
onComplete,
|
|
1091
2046
|
onError
|
|
1092
2047
|
}) {
|
|
1093
|
-
const { apiBaseUrl, tokens } = useSwypeConfig();
|
|
2048
|
+
const { apiBaseUrl, tokens, depositAmount } = useSwypeConfig();
|
|
1094
2049
|
const { ready, authenticated, login, getAccessToken } = reactAuth.usePrivy();
|
|
1095
2050
|
const [step, setStep] = react.useState("login");
|
|
1096
2051
|
const [error, setError] = react.useState(null);
|
|
1097
2052
|
const [providers, setProviders] = react.useState([]);
|
|
1098
2053
|
const [accounts, setAccounts] = react.useState([]);
|
|
2054
|
+
const [chains, setChains] = react.useState([]);
|
|
1099
2055
|
const [loadingData, setLoadingData] = react.useState(false);
|
|
1100
|
-
const [
|
|
1101
|
-
|
|
2056
|
+
const [selectedAccountId, setSelectedAccountId] = react.useState(null);
|
|
2057
|
+
const [selectedWalletId, setSelectedWalletId] = react.useState(null);
|
|
2058
|
+
const [selectedProviderId, setSelectedProviderId] = react.useState(null);
|
|
2059
|
+
const [connectingNewAccount, setConnectingNewAccount] = react.useState(false);
|
|
2060
|
+
const [amount, setAmount] = react.useState(
|
|
2061
|
+
depositAmount != null ? depositAmount.toString() : ""
|
|
1102
2062
|
);
|
|
1103
|
-
const [
|
|
1104
|
-
|
|
1105
|
-
|
|
2063
|
+
const [advancedSettings, setAdvancedSettings] = react.useState({
|
|
2064
|
+
asset: null,
|
|
2065
|
+
chain: null
|
|
2066
|
+
});
|
|
1106
2067
|
const [transfer, setTransfer] = react.useState(null);
|
|
1107
2068
|
const [creatingTransfer, setCreatingTransfer] = react.useState(false);
|
|
1108
2069
|
const [mobileFlow, setMobileFlow] = react.useState(false);
|
|
1109
2070
|
const pollingTransferIdRef = react.useRef(null);
|
|
1110
2071
|
const authExecutor = useAuthorizationExecutor();
|
|
1111
2072
|
const polling = useTransferPolling();
|
|
1112
|
-
const
|
|
1113
|
-
const
|
|
2073
|
+
const transferSigning = useTransferSigning();
|
|
2074
|
+
const sourceType = connectingNewAccount ? "providerId" : selectedWalletId ? "walletId" : selectedAccountId ? "accountId" : "providerId";
|
|
2075
|
+
const sourceId = connectingNewAccount ? selectedProviderId ?? "" : selectedWalletId ? selectedWalletId : selectedAccountId ? selectedAccountId : selectedProviderId ?? "";
|
|
2076
|
+
react.useEffect(() => {
|
|
2077
|
+
if (depositAmount != null) {
|
|
2078
|
+
setAmount(depositAmount.toString());
|
|
2079
|
+
}
|
|
2080
|
+
}, [depositAmount]);
|
|
1114
2081
|
react.useEffect(() => {
|
|
1115
2082
|
if (ready && authenticated && step === "login") {
|
|
1116
|
-
|
|
2083
|
+
if (depositAmount != null && depositAmount > 0) {
|
|
2084
|
+
setStep("ready");
|
|
2085
|
+
} else {
|
|
2086
|
+
setStep("enter-amount");
|
|
2087
|
+
}
|
|
1117
2088
|
}
|
|
1118
|
-
}, [ready, authenticated, step]);
|
|
2089
|
+
}, [ready, authenticated, step, depositAmount]);
|
|
2090
|
+
const loadingDataRef = react.useRef(false);
|
|
1119
2091
|
react.useEffect(() => {
|
|
1120
|
-
if (
|
|
1121
|
-
if (
|
|
2092
|
+
if (!authenticated) return;
|
|
2093
|
+
if (accounts.length > 0 || loadingDataRef.current) return;
|
|
1122
2094
|
let cancelled = false;
|
|
2095
|
+
loadingDataRef.current = true;
|
|
1123
2096
|
const load = async () => {
|
|
1124
2097
|
setLoadingData(true);
|
|
1125
2098
|
setError(null);
|
|
1126
2099
|
try {
|
|
1127
2100
|
const token = await getAccessToken();
|
|
1128
2101
|
if (!token) throw new Error("Not authenticated");
|
|
1129
|
-
const [prov, accts] = await Promise.all([
|
|
2102
|
+
const [prov, accts, chn] = await Promise.all([
|
|
1130
2103
|
fetchProviders(apiBaseUrl, token),
|
|
1131
|
-
fetchAccounts(apiBaseUrl, token)
|
|
2104
|
+
fetchAccounts(apiBaseUrl, token),
|
|
2105
|
+
fetchChains(apiBaseUrl, token)
|
|
1132
2106
|
]);
|
|
1133
2107
|
if (cancelled) return;
|
|
1134
2108
|
setProviders(prov);
|
|
1135
2109
|
setAccounts(accts);
|
|
1136
|
-
|
|
2110
|
+
setChains(chn);
|
|
2111
|
+
const parsedAmt = depositAmount != null ? depositAmount : 0;
|
|
2112
|
+
const defaults = computeSmartDefaults(accts, parsedAmt);
|
|
2113
|
+
if (defaults) {
|
|
2114
|
+
setSelectedAccountId(defaults.accountId);
|
|
2115
|
+
setSelectedWalletId(defaults.walletId);
|
|
2116
|
+
} else if (prov.length > 0) {
|
|
2117
|
+
setSelectedProviderId(prov[0].id);
|
|
2118
|
+
}
|
|
1137
2119
|
} catch (err) {
|
|
1138
2120
|
if (!cancelled) {
|
|
1139
2121
|
const msg = err instanceof Error ? err.message : "Failed to load data";
|
|
1140
2122
|
setError(msg);
|
|
1141
2123
|
}
|
|
1142
2124
|
} finally {
|
|
1143
|
-
if (!cancelled)
|
|
2125
|
+
if (!cancelled) {
|
|
2126
|
+
setLoadingData(false);
|
|
2127
|
+
loadingDataRef.current = false;
|
|
2128
|
+
}
|
|
1144
2129
|
}
|
|
1145
2130
|
};
|
|
1146
2131
|
load();
|
|
1147
2132
|
return () => {
|
|
1148
2133
|
cancelled = true;
|
|
2134
|
+
loadingDataRef.current = false;
|
|
1149
2135
|
};
|
|
1150
|
-
}, [
|
|
2136
|
+
}, [authenticated, accounts.length, apiBaseUrl, getAccessToken]);
|
|
1151
2137
|
react.useEffect(() => {
|
|
1152
2138
|
if (!polling.transfer) return;
|
|
1153
2139
|
if (polling.transfer.status === "COMPLETED") {
|
|
@@ -1174,6 +2160,61 @@ function SwypePayment({
|
|
|
1174
2160
|
document.removeEventListener("visibilitychange", handleVisibility);
|
|
1175
2161
|
};
|
|
1176
2162
|
}, [mobileFlow, polling]);
|
|
2163
|
+
react.useEffect(() => {
|
|
2164
|
+
if (!authExecutor.pendingSelectSource) return;
|
|
2165
|
+
const action = authExecutor.pendingSelectSource;
|
|
2166
|
+
const hasAdvancedOverride = advancedSettings.asset !== null || advancedSettings.chain !== null;
|
|
2167
|
+
if (hasAdvancedOverride) {
|
|
2168
|
+
const options = action.metadata?.options ?? [];
|
|
2169
|
+
const recommended = action.metadata?.recommended;
|
|
2170
|
+
const match = options.find(
|
|
2171
|
+
(opt) => (advancedSettings.chain === null || opt.chainName === advancedSettings.chain) && (advancedSettings.asset === null || opt.tokenSymbol === advancedSettings.asset)
|
|
2172
|
+
);
|
|
2173
|
+
if (match) {
|
|
2174
|
+
authExecutor.resolveSelectSource({
|
|
2175
|
+
chainName: match.chainName,
|
|
2176
|
+
tokenSymbol: match.tokenSymbol
|
|
2177
|
+
});
|
|
2178
|
+
} else if (recommended) {
|
|
2179
|
+
authExecutor.resolveSelectSource({
|
|
2180
|
+
chainName: recommended.chainName,
|
|
2181
|
+
tokenSymbol: recommended.tokenSymbol
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
} else {
|
|
2185
|
+
const options = action.metadata?.options ?? [];
|
|
2186
|
+
const recommended = action.metadata?.recommended;
|
|
2187
|
+
const selWallet = selectedWalletId ? accounts.find((a) => a.id === selectedAccountId)?.wallets.find((w) => w.id === selectedWalletId) : null;
|
|
2188
|
+
if (selWallet) {
|
|
2189
|
+
const walletMatch = options.find(
|
|
2190
|
+
(opt) => opt.chainName === selWallet.chain.name
|
|
2191
|
+
);
|
|
2192
|
+
if (walletMatch) {
|
|
2193
|
+
authExecutor.resolveSelectSource({
|
|
2194
|
+
chainName: walletMatch.chainName,
|
|
2195
|
+
tokenSymbol: walletMatch.tokenSymbol
|
|
2196
|
+
});
|
|
2197
|
+
return;
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
if (recommended) {
|
|
2201
|
+
authExecutor.resolveSelectSource({
|
|
2202
|
+
chainName: recommended.chainName,
|
|
2203
|
+
tokenSymbol: recommended.tokenSymbol
|
|
2204
|
+
});
|
|
2205
|
+
} else if (options.length > 0) {
|
|
2206
|
+
authExecutor.resolveSelectSource({
|
|
2207
|
+
chainName: options[0].chainName,
|
|
2208
|
+
tokenSymbol: options[0].tokenSymbol
|
|
2209
|
+
});
|
|
2210
|
+
} else {
|
|
2211
|
+
authExecutor.resolveSelectSource({
|
|
2212
|
+
chainName: "Base",
|
|
2213
|
+
tokenSymbol: "USDC"
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
}, [authExecutor, authExecutor.pendingSelectSource, advancedSettings, selectedWalletId, selectedAccountId, accounts]);
|
|
1177
2218
|
const handlePay = react.useCallback(async () => {
|
|
1178
2219
|
const parsedAmount = parseFloat(amount);
|
|
1179
2220
|
if (isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
@@ -1181,7 +2222,7 @@ function SwypePayment({
|
|
|
1181
2222
|
return;
|
|
1182
2223
|
}
|
|
1183
2224
|
if (!sourceId) {
|
|
1184
|
-
setError("
|
|
2225
|
+
setError("No account or provider selected.");
|
|
1185
2226
|
return;
|
|
1186
2227
|
}
|
|
1187
2228
|
setStep("processing");
|
|
@@ -1191,12 +2232,6 @@ function SwypePayment({
|
|
|
1191
2232
|
try {
|
|
1192
2233
|
const token = await getAccessToken();
|
|
1193
2234
|
if (!token) throw new Error("Not authenticated");
|
|
1194
|
-
const parsedTopUp = parseFloat(topUpBalance);
|
|
1195
|
-
if (!isNaN(parsedTopUp) && parsedTopUp > 0) {
|
|
1196
|
-
await updateUserConfig(apiBaseUrl, token, {
|
|
1197
|
-
defaultAllowance: parsedTopUp
|
|
1198
|
-
});
|
|
1199
|
-
}
|
|
1200
2235
|
const t = await createTransfer(apiBaseUrl, token, {
|
|
1201
2236
|
sourceType,
|
|
1202
2237
|
sourceId,
|
|
@@ -1215,12 +2250,14 @@ function SwypePayment({
|
|
|
1215
2250
|
await authExecutor.executeSession(t);
|
|
1216
2251
|
}
|
|
1217
2252
|
}
|
|
2253
|
+
const signedTransfer = await transferSigning.signTransfer(t.id);
|
|
2254
|
+
setTransfer(signedTransfer);
|
|
1218
2255
|
polling.startPolling(t.id);
|
|
1219
2256
|
} catch (err) {
|
|
1220
|
-
const msg = err instanceof Error ? err.message : "Transfer
|
|
2257
|
+
const msg = err instanceof Error ? err.message : "Transfer failed";
|
|
1221
2258
|
setError(msg);
|
|
1222
2259
|
onError?.(msg);
|
|
1223
|
-
setStep("
|
|
2260
|
+
setStep("ready");
|
|
1224
2261
|
} finally {
|
|
1225
2262
|
setCreatingTransfer(false);
|
|
1226
2263
|
}
|
|
@@ -1232,20 +2269,26 @@ function SwypePayment({
|
|
|
1232
2269
|
apiBaseUrl,
|
|
1233
2270
|
getAccessToken,
|
|
1234
2271
|
authExecutor,
|
|
2272
|
+
transferSigning,
|
|
1235
2273
|
polling,
|
|
1236
|
-
onError
|
|
1237
|
-
topUpBalance
|
|
2274
|
+
onError
|
|
1238
2275
|
]);
|
|
1239
2276
|
const handleNewPayment = () => {
|
|
1240
|
-
setStep("
|
|
2277
|
+
setStep("ready");
|
|
1241
2278
|
setTransfer(null);
|
|
1242
2279
|
setError(null);
|
|
1243
|
-
setAmount(
|
|
1244
|
-
setTopUpBalance("");
|
|
2280
|
+
setAmount(depositAmount != null ? depositAmount.toString() : "");
|
|
1245
2281
|
setMobileFlow(false);
|
|
1246
2282
|
pollingTransferIdRef.current = null;
|
|
1247
|
-
|
|
1248
|
-
|
|
2283
|
+
setConnectingNewAccount(false);
|
|
2284
|
+
setSelectedWalletId(null);
|
|
2285
|
+
setAdvancedSettings({ asset: null, chain: null });
|
|
2286
|
+
if (accounts.length > 0) setSelectedAccountId(accounts[0].id);
|
|
2287
|
+
};
|
|
2288
|
+
const handleConnectNewAccount = (providerId) => {
|
|
2289
|
+
setSelectedProviderId(providerId);
|
|
2290
|
+
setSelectedAccountId(null);
|
|
2291
|
+
setConnectingNewAccount(true);
|
|
1249
2292
|
};
|
|
1250
2293
|
const cardStyle = {
|
|
1251
2294
|
background: tokens.bgCard,
|
|
@@ -1283,15 +2326,10 @@ function SwypePayment({
|
|
|
1283
2326
|
opacity: 0.5,
|
|
1284
2327
|
cursor: "not-allowed"
|
|
1285
2328
|
};
|
|
1286
|
-
|
|
2329
|
+
({
|
|
1287
2330
|
...btnPrimary,
|
|
1288
|
-
background: "transparent",
|
|
1289
2331
|
color: tokens.textSecondary,
|
|
1290
|
-
border: `1px solid ${tokens.border}
|
|
1291
|
-
width: "auto",
|
|
1292
|
-
flex: "0 0 auto",
|
|
1293
|
-
padding: "14px 20px"
|
|
1294
|
-
};
|
|
2332
|
+
border: `1px solid ${tokens.border}`});
|
|
1295
2333
|
const errorStyle = {
|
|
1296
2334
|
background: tokens.errorBg,
|
|
1297
2335
|
border: `1px solid ${tokens.error}`,
|
|
@@ -1382,62 +2420,20 @@ function SwypePayment({
|
|
|
1382
2420
|
/* @__PURE__ */ jsxRuntime.jsx("button", { style: btnPrimary, onClick: login, children: "Connect to Swype" })
|
|
1383
2421
|
] }) });
|
|
1384
2422
|
}
|
|
1385
|
-
if (step === "select-source") {
|
|
1386
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
1387
|
-
stepBadge("Select payment source"),
|
|
1388
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle, children: "Choose a provider" }),
|
|
1389
|
-
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorStyle, children: error }),
|
|
1390
|
-
loadingData ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "24px 0", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { label: "Loading providers..." }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1391
|
-
accounts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1392
|
-
AccountWalletSelector,
|
|
1393
|
-
{
|
|
1394
|
-
accounts,
|
|
1395
|
-
selection: walletSelection,
|
|
1396
|
-
onSelect: (sel) => {
|
|
1397
|
-
setWalletSelection(sel);
|
|
1398
|
-
if (sel) setSelectedProviderId(null);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
) }),
|
|
1402
|
-
!walletSelection && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1403
|
-
"div",
|
|
1404
|
-
{
|
|
1405
|
-
style: {
|
|
1406
|
-
display: "flex",
|
|
1407
|
-
flexDirection: "column",
|
|
1408
|
-
gap: "8px",
|
|
1409
|
-
marginBottom: "20px"
|
|
1410
|
-
},
|
|
1411
|
-
children: providers.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1412
|
-
ProviderCard,
|
|
1413
|
-
{
|
|
1414
|
-
provider: p,
|
|
1415
|
-
selected: selectedProviderId === p.id,
|
|
1416
|
-
onClick: () => {
|
|
1417
|
-
setSelectedProviderId(p.id);
|
|
1418
|
-
setWalletSelection(null);
|
|
1419
|
-
}
|
|
1420
|
-
},
|
|
1421
|
-
p.id
|
|
1422
|
-
))
|
|
1423
|
-
}
|
|
1424
|
-
),
|
|
1425
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1426
|
-
"button",
|
|
1427
|
-
{
|
|
1428
|
-
style: sourceId ? btnPrimary : btnDisabled,
|
|
1429
|
-
disabled: !sourceId,
|
|
1430
|
-
onClick: () => {
|
|
1431
|
-
setError(null);
|
|
1432
|
-
setStep("enter-amount");
|
|
1433
|
-
},
|
|
1434
|
-
children: "Continue"
|
|
1435
|
-
}
|
|
1436
|
-
)
|
|
1437
|
-
] })
|
|
1438
|
-
] });
|
|
1439
|
-
}
|
|
1440
2423
|
if (step === "enter-amount") {
|
|
2424
|
+
const parsedAmount = parseFloat(amount);
|
|
2425
|
+
const canContinue = !isNaN(parsedAmount) && parsedAmount > 0;
|
|
2426
|
+
let maxSourceBalance = null;
|
|
2427
|
+
for (const acct of accounts) {
|
|
2428
|
+
for (const wallet of acct.wallets) {
|
|
2429
|
+
for (const source of wallet.sources) {
|
|
2430
|
+
const bal = source.balance.available.amount;
|
|
2431
|
+
if (maxSourceBalance === null || bal > maxSourceBalance) {
|
|
2432
|
+
maxSourceBalance = bal;
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
1441
2437
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
1442
2438
|
stepBadge("Enter amount"),
|
|
1443
2439
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle, children: "How much?" }),
|
|
@@ -1453,7 +2449,7 @@ function SwypePayment({
|
|
|
1453
2449
|
border: `1px solid ${tokens.border}`,
|
|
1454
2450
|
borderRadius: tokens.radius,
|
|
1455
2451
|
padding: "4px 14px 4px 4px",
|
|
1456
|
-
marginBottom: "
|
|
2452
|
+
marginBottom: "8px"
|
|
1457
2453
|
},
|
|
1458
2454
|
children: [
|
|
1459
2455
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1477,6 +2473,7 @@ function SwypePayment({
|
|
|
1477
2473
|
step: "0.01",
|
|
1478
2474
|
value: amount,
|
|
1479
2475
|
onChange: (e) => setAmount(e.target.value),
|
|
2476
|
+
placeholder: "0.00",
|
|
1480
2477
|
style: {
|
|
1481
2478
|
flex: 1,
|
|
1482
2479
|
background: "transparent",
|
|
@@ -1508,156 +2505,301 @@ function SwypePayment({
|
|
|
1508
2505
|
]
|
|
1509
2506
|
}
|
|
1510
2507
|
),
|
|
1511
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2508
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1512
2509
|
"div",
|
|
1513
2510
|
{
|
|
1514
2511
|
style: {
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
border: `1px solid ${tokens.border}`,
|
|
1520
|
-
borderRadius: tokens.radius,
|
|
1521
|
-
padding: "4px 14px 4px 4px",
|
|
1522
|
-
marginBottom: "20px"
|
|
2512
|
+
fontSize: "0.8rem",
|
|
2513
|
+
color: tokens.textMuted,
|
|
2514
|
+
marginBottom: "20px",
|
|
2515
|
+
paddingLeft: "2px"
|
|
1523
2516
|
},
|
|
1524
|
-
children: [
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
color: tokens.textMuted,
|
|
1532
|
-
paddingLeft: "10px",
|
|
1533
|
-
userSelect: "none"
|
|
1534
|
-
},
|
|
1535
|
-
children: "$"
|
|
1536
|
-
}
|
|
1537
|
-
),
|
|
1538
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1539
|
-
"input",
|
|
1540
|
-
{
|
|
1541
|
-
type: "number",
|
|
1542
|
-
min: "0",
|
|
1543
|
-
step: "1",
|
|
1544
|
-
placeholder: "Top up balance (optional)",
|
|
1545
|
-
value: topUpBalance,
|
|
1546
|
-
onChange: (e) => setTopUpBalance(e.target.value),
|
|
1547
|
-
style: {
|
|
1548
|
-
flex: 1,
|
|
1549
|
-
background: "transparent",
|
|
1550
|
-
border: "none",
|
|
1551
|
-
outline: "none",
|
|
1552
|
-
color: tokens.text,
|
|
1553
|
-
fontSize: "1rem",
|
|
1554
|
-
fontWeight: 600,
|
|
1555
|
-
fontFamily: "inherit",
|
|
1556
|
-
padding: "10px 0"
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1559
|
-
),
|
|
1560
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1561
|
-
"span",
|
|
1562
|
-
{
|
|
1563
|
-
style: {
|
|
1564
|
-
fontSize: "0.75rem",
|
|
1565
|
-
fontWeight: 600,
|
|
1566
|
-
color: tokens.textMuted,
|
|
1567
|
-
background: tokens.bgHover,
|
|
1568
|
-
padding: "4px 10px",
|
|
1569
|
-
borderRadius: "6px",
|
|
1570
|
-
whiteSpace: "nowrap"
|
|
1571
|
-
},
|
|
1572
|
-
children: "USD"
|
|
1573
|
-
}
|
|
1574
|
-
)
|
|
1575
|
-
]
|
|
2517
|
+
children: loadingData ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading balance..." }) : maxSourceBalance !== null && maxSourceBalance > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2518
|
+
"Available: ",
|
|
2519
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: tokens.textSecondary }, children: [
|
|
2520
|
+
"$",
|
|
2521
|
+
maxSourceBalance.toFixed(2)
|
|
2522
|
+
] })
|
|
2523
|
+
] }) : null
|
|
1576
2524
|
}
|
|
1577
2525
|
),
|
|
1578
2526
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1579
|
-
"
|
|
2527
|
+
"button",
|
|
1580
2528
|
{
|
|
1581
|
-
style:
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
2529
|
+
style: canContinue ? btnPrimary : btnDisabled,
|
|
2530
|
+
disabled: !canContinue,
|
|
2531
|
+
onClick: () => {
|
|
2532
|
+
setError(null);
|
|
2533
|
+
setStep("ready");
|
|
1586
2534
|
},
|
|
1587
|
-
children: "
|
|
2535
|
+
children: "Continue"
|
|
1588
2536
|
}
|
|
1589
|
-
)
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
2537
|
+
)
|
|
2538
|
+
] });
|
|
2539
|
+
}
|
|
2540
|
+
if (step === "ready") {
|
|
2541
|
+
const parsedAmount = parseFloat(amount);
|
|
2542
|
+
const canPay = !isNaN(parsedAmount) && parsedAmount > 0 && !!sourceId && !loadingData;
|
|
2543
|
+
const noAccounts = !loadingData && accounts.length === 0;
|
|
2544
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardStyle, children: [
|
|
2545
|
+
stepBadge("Review & pay"),
|
|
2546
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorStyle, children: error }),
|
|
2547
|
+
loadingData ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "24px 0", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { label: "Loading..." }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2548
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2549
|
+
"div",
|
|
2550
|
+
{
|
|
2551
|
+
style: {
|
|
2552
|
+
textAlign: "center",
|
|
2553
|
+
marginBottom: "20px"
|
|
2554
|
+
},
|
|
2555
|
+
children: [
|
|
1605
2556
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1606
|
-
"
|
|
2557
|
+
"div",
|
|
1607
2558
|
{
|
|
1608
2559
|
style: {
|
|
1609
|
-
|
|
1610
|
-
|
|
2560
|
+
fontSize: "2rem",
|
|
2561
|
+
fontWeight: 700,
|
|
2562
|
+
color: tokens.text,
|
|
2563
|
+
lineHeight: 1.2
|
|
1611
2564
|
},
|
|
1612
2565
|
children: [
|
|
1613
|
-
|
|
1614
|
-
"
|
|
1615
|
-
destination.address.slice(-4)
|
|
2566
|
+
"$",
|
|
2567
|
+
parsedAmount > 0 ? parsedAmount.toFixed(2) : "0.00"
|
|
1616
2568
|
]
|
|
1617
2569
|
}
|
|
2570
|
+
),
|
|
2571
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2572
|
+
"button",
|
|
2573
|
+
{
|
|
2574
|
+
onClick: () => setStep("enter-amount"),
|
|
2575
|
+
style: {
|
|
2576
|
+
background: "transparent",
|
|
2577
|
+
border: "none",
|
|
2578
|
+
cursor: "pointer",
|
|
2579
|
+
color: tokens.textMuted,
|
|
2580
|
+
fontSize: "0.75rem",
|
|
2581
|
+
fontFamily: "inherit",
|
|
2582
|
+
outline: "none",
|
|
2583
|
+
padding: "4px 8px",
|
|
2584
|
+
marginTop: "4px"
|
|
2585
|
+
},
|
|
2586
|
+
children: "Change amount"
|
|
2587
|
+
}
|
|
1618
2588
|
)
|
|
1619
|
-
]
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
1625
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Source" }),
|
|
1626
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600 }, children: walletSelection ? `${walletSelection.walletName} (${walletSelection.chainName})` : providers.find((p) => p.id === selectedProviderId)?.name ?? "Provider" })
|
|
1627
|
-
] })
|
|
1628
|
-
]
|
|
1629
|
-
}
|
|
1630
|
-
),
|
|
1631
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "10px" }, children: [
|
|
1632
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1633
|
-
"button",
|
|
2589
|
+
]
|
|
2590
|
+
}
|
|
2591
|
+
),
|
|
2592
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2593
|
+
"div",
|
|
1634
2594
|
{
|
|
1635
|
-
style:
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
2595
|
+
style: {
|
|
2596
|
+
fontSize: "0.825rem",
|
|
2597
|
+
color: tokens.textSecondary,
|
|
2598
|
+
marginBottom: "16px",
|
|
2599
|
+
padding: "12px 14px",
|
|
2600
|
+
background: tokens.bgInput,
|
|
2601
|
+
borderRadius: tokens.radius,
|
|
2602
|
+
lineHeight: 1.7
|
|
1639
2603
|
},
|
|
1640
|
-
children:
|
|
2604
|
+
children: [
|
|
2605
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2606
|
+
"div",
|
|
2607
|
+
{
|
|
2608
|
+
style: { display: "flex", justifyContent: "space-between" },
|
|
2609
|
+
children: [
|
|
2610
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "To" }),
|
|
2611
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2612
|
+
"span",
|
|
2613
|
+
{
|
|
2614
|
+
style: {
|
|
2615
|
+
fontFamily: '"SF Mono", "Fira Code", monospace',
|
|
2616
|
+
fontSize: "0.8rem"
|
|
2617
|
+
},
|
|
2618
|
+
children: [
|
|
2619
|
+
destination.address.slice(0, 6),
|
|
2620
|
+
"...",
|
|
2621
|
+
destination.address.slice(-4)
|
|
2622
|
+
]
|
|
2623
|
+
}
|
|
2624
|
+
)
|
|
2625
|
+
]
|
|
2626
|
+
}
|
|
2627
|
+
),
|
|
2628
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2629
|
+
"div",
|
|
2630
|
+
{
|
|
2631
|
+
style: { display: "flex", justifyContent: "space-between" },
|
|
2632
|
+
children: [
|
|
2633
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Token" }),
|
|
2634
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600 }, children: destination.token.symbol })
|
|
2635
|
+
]
|
|
2636
|
+
}
|
|
2637
|
+
),
|
|
2638
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2639
|
+
"div",
|
|
2640
|
+
{
|
|
2641
|
+
style: {
|
|
2642
|
+
display: "flex",
|
|
2643
|
+
justifyContent: "space-between",
|
|
2644
|
+
alignItems: "center"
|
|
2645
|
+
},
|
|
2646
|
+
children: [
|
|
2647
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "From" }),
|
|
2648
|
+
noAccounts ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500, color: tokens.textMuted }, children: "New account" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2649
|
+
AccountDropdown,
|
|
2650
|
+
{
|
|
2651
|
+
accounts,
|
|
2652
|
+
selectedAccountId,
|
|
2653
|
+
selectedWalletId,
|
|
2654
|
+
onSelect: (id) => {
|
|
2655
|
+
setSelectedAccountId(id);
|
|
2656
|
+
setSelectedWalletId(null);
|
|
2657
|
+
setConnectingNewAccount(false);
|
|
2658
|
+
setSelectedProviderId(null);
|
|
2659
|
+
},
|
|
2660
|
+
onWalletSelect: (accountId, walletId) => {
|
|
2661
|
+
setSelectedAccountId(accountId);
|
|
2662
|
+
setSelectedWalletId(walletId);
|
|
2663
|
+
setConnectingNewAccount(false);
|
|
2664
|
+
setSelectedProviderId(null);
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
)
|
|
2668
|
+
]
|
|
2669
|
+
}
|
|
2670
|
+
)
|
|
2671
|
+
]
|
|
1641
2672
|
}
|
|
1642
2673
|
),
|
|
2674
|
+
noAccounts && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "16px" }, children: [
|
|
2675
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2676
|
+
"label",
|
|
2677
|
+
{
|
|
2678
|
+
style: {
|
|
2679
|
+
display: "block",
|
|
2680
|
+
fontSize: "0.8rem",
|
|
2681
|
+
color: tokens.textMuted,
|
|
2682
|
+
marginBottom: "8px",
|
|
2683
|
+
fontWeight: 500,
|
|
2684
|
+
textTransform: "uppercase",
|
|
2685
|
+
letterSpacing: "0.05em"
|
|
2686
|
+
},
|
|
2687
|
+
children: "Connect a wallet"
|
|
2688
|
+
}
|
|
2689
|
+
),
|
|
2690
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2691
|
+
"div",
|
|
2692
|
+
{
|
|
2693
|
+
style: {
|
|
2694
|
+
display: "flex",
|
|
2695
|
+
flexDirection: "column",
|
|
2696
|
+
gap: "8px"
|
|
2697
|
+
},
|
|
2698
|
+
children: providers.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2699
|
+
ProviderCard,
|
|
2700
|
+
{
|
|
2701
|
+
provider: p,
|
|
2702
|
+
selected: selectedProviderId === p.id,
|
|
2703
|
+
onClick: () => {
|
|
2704
|
+
setSelectedProviderId(p.id);
|
|
2705
|
+
setSelectedAccountId(null);
|
|
2706
|
+
setConnectingNewAccount(false);
|
|
2707
|
+
}
|
|
2708
|
+
},
|
|
2709
|
+
p.id
|
|
2710
|
+
))
|
|
2711
|
+
}
|
|
2712
|
+
)
|
|
2713
|
+
] }),
|
|
1643
2714
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1644
2715
|
"button",
|
|
1645
2716
|
{
|
|
1646
|
-
style:
|
|
1647
|
-
disabled: !
|
|
2717
|
+
style: canPay ? btnPrimary : btnDisabled,
|
|
2718
|
+
disabled: !canPay,
|
|
1648
2719
|
onClick: handlePay,
|
|
1649
2720
|
children: [
|
|
1650
2721
|
"Pay $",
|
|
1651
|
-
|
|
2722
|
+
parsedAmount > 0 ? parsedAmount.toFixed(2) : "0.00"
|
|
1652
2723
|
]
|
|
1653
2724
|
}
|
|
2725
|
+
),
|
|
2726
|
+
!noAccounts && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2727
|
+
AdvancedSettings,
|
|
2728
|
+
{
|
|
2729
|
+
settings: advancedSettings,
|
|
2730
|
+
onChange: setAdvancedSettings,
|
|
2731
|
+
chains,
|
|
2732
|
+
providers,
|
|
2733
|
+
onConnectNewAccount: handleConnectNewAccount,
|
|
2734
|
+
connectingNewAccount
|
|
2735
|
+
}
|
|
1654
2736
|
)
|
|
1655
2737
|
] })
|
|
1656
2738
|
] });
|
|
1657
2739
|
}
|
|
1658
2740
|
if (step === "processing") {
|
|
1659
|
-
|
|
1660
|
-
|
|
2741
|
+
if (transferSigning.signing && transferSigning.signPayload) {
|
|
2742
|
+
const payload = transferSigning.signPayload;
|
|
2743
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "16px 0" }, children: [
|
|
2744
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "48", height: "48", viewBox: "0 0 48 48", fill: "none", style: { margin: "0 auto 16px" }, children: [
|
|
2745
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "48", height: "48", rx: "12", fill: tokens.accent + "20" }),
|
|
2746
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M24 14v8M20 18h8M24 26v2M24 32v2", stroke: tokens.accent, strokeWidth: "2", strokeLinecap: "round" })
|
|
2747
|
+
] }),
|
|
2748
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Authorize Transfer" }),
|
|
2749
|
+
/* @__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." }),
|
|
2750
|
+
/* @__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: [
|
|
2751
|
+
payload.amount && payload.tokenSymbol && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
2752
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Amount" }),
|
|
2753
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 600, color: tokens.text }, children: [
|
|
2754
|
+
payload.amount,
|
|
2755
|
+
" ",
|
|
2756
|
+
payload.tokenSymbol
|
|
2757
|
+
] })
|
|
2758
|
+
] }),
|
|
2759
|
+
payload.bridgeRelayAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
2760
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Bridge relay" }),
|
|
2761
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontFamily: '"SF Mono", "Fira Code", monospace', fontSize: "0.75rem" }, children: [
|
|
2762
|
+
payload.bridgeRelayAddress.slice(0, 6),
|
|
2763
|
+
"...",
|
|
2764
|
+
payload.bridgeRelayAddress.slice(-4)
|
|
2765
|
+
] })
|
|
2766
|
+
] }),
|
|
2767
|
+
payload.estimatedFeeUsd && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
2768
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Est. fee" }),
|
|
2769
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 600 }, children: [
|
|
2770
|
+
"$",
|
|
2771
|
+
payload.estimatedFeeUsd
|
|
2772
|
+
] })
|
|
2773
|
+
] })
|
|
2774
|
+
] }),
|
|
2775
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spinner, { label: "Waiting for passkey..." })
|
|
2776
|
+
] }) });
|
|
2777
|
+
}
|
|
2778
|
+
const currentActionType = authExecutor.currentAction?.type;
|
|
2779
|
+
const getRegistrationMessage = () => {
|
|
2780
|
+
switch (currentActionType) {
|
|
2781
|
+
case "REGISTER_PASSKEY":
|
|
2782
|
+
return {
|
|
2783
|
+
label: "Creating your passkey...",
|
|
2784
|
+
description: "Set up a passkey for secure, one-touch payments."
|
|
2785
|
+
};
|
|
2786
|
+
case "UPGRADE_SMART_ACCOUNT":
|
|
2787
|
+
return {
|
|
2788
|
+
label: "Upgrading your account...",
|
|
2789
|
+
description: "Approve the prompts in MetaMask to upgrade your account to a smart account and register your passkey. You may see two prompts."
|
|
2790
|
+
};
|
|
2791
|
+
case "GRANT_PERMISSIONS":
|
|
2792
|
+
return {
|
|
2793
|
+
label: "Setting up permissions...",
|
|
2794
|
+
description: "Signing delegation permissions. Transfer routing and gas sponsorship are handled by Swype backend."
|
|
2795
|
+
};
|
|
2796
|
+
default:
|
|
2797
|
+
return { label: "", description: "" };
|
|
2798
|
+
}
|
|
2799
|
+
};
|
|
2800
|
+
const regMsg = getRegistrationMessage();
|
|
2801
|
+
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...";
|
|
2802
|
+
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...";
|
|
1661
2803
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "16px 0" }, children: [
|
|
1662
2804
|
/* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: 48 }),
|
|
1663
2805
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1701,11 +2843,11 @@ function SwypePayment({
|
|
|
1701
2843
|
},
|
|
1702
2844
|
r.actionId
|
|
1703
2845
|
)) }),
|
|
1704
|
-
(error || authExecutor.error || polling.error) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2846
|
+
(error || authExecutor.error || transferSigning.error || polling.error) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1705
2847
|
"div",
|
|
1706
2848
|
{
|
|
1707
2849
|
style: { ...errorStyle, marginTop: "16px", textAlign: "left" },
|
|
1708
|
-
children: error || authExecutor.error || polling.error
|
|
2850
|
+
children: error || authExecutor.error || transferSigning.error || polling.error
|
|
1709
2851
|
}
|
|
1710
2852
|
)
|
|
1711
2853
|
] }) });
|
|
@@ -1840,6 +2982,7 @@ exports.lightTheme = lightTheme;
|
|
|
1840
2982
|
exports.swypeApi = api_exports;
|
|
1841
2983
|
exports.useAuthorizationExecutor = useAuthorizationExecutor;
|
|
1842
2984
|
exports.useSwypeConfig = useSwypeConfig;
|
|
2985
|
+
exports.useSwypeDepositAmount = useSwypeDepositAmount;
|
|
1843
2986
|
exports.useTransferPolling = useTransferPolling;
|
|
1844
2987
|
//# sourceMappingURL=index.cjs.map
|
|
1845
2988
|
//# sourceMappingURL=index.cjs.map
|