@rhinestone/1auth 0.1.1 → 0.1.2
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/README.md +130 -0
- package/dist/{chunk-U7KZ4XMQ.mjs → chunk-TACK3LJN.mjs} +162 -22
- package/dist/chunk-TACK3LJN.mjs.map +1 -0
- package/dist/{client-B-HGKKaJ.d.mts → client-DyYGKWj3.d.mts} +302 -22
- package/dist/{client-B-HGKKaJ.d.ts → client-DyYGKWj3.d.ts} +302 -22
- package/dist/index.d.mts +20 -11
- package/dist/index.d.ts +20 -11
- package/dist/index.js +966 -221
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +805 -200
- package/dist/index.mjs.map +1 -1
- package/dist/provider-CNTZPPFz.d.ts +33 -0
- package/dist/provider-Ctr7HQHR.d.mts +33 -0
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js.map +1 -1
- package/dist/react.mjs.map +1 -1
- package/dist/wagmi.d.mts +3 -3
- package/dist/wagmi.d.ts +3 -3
- package/dist/wagmi.js +153 -23
- package/dist/wagmi.js.map +1 -1
- package/dist/wagmi.mjs +1 -1
- package/package.json +19 -6
- package/dist/chunk-U7KZ4XMQ.mjs.map +0 -1
- package/dist/provider-CDIRlA4y.d.mts +0 -25
- package/dist/provider-Cy1StrOe.d.ts +0 -25
package/dist/index.js
CHANGED
|
@@ -32,9 +32,11 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
BatchQueueProvider: () => BatchQueueProvider,
|
|
34
34
|
BatchQueueWidget: () => BatchQueueWidget,
|
|
35
|
+
ETHEREUM_MESSAGE_PREFIX: () => ETHEREUM_MESSAGE_PREFIX,
|
|
35
36
|
OneAuthClient: () => OneAuthClient,
|
|
36
37
|
PASSKEY_MESSAGE_PREFIX: () => PASSKEY_MESSAGE_PREFIX,
|
|
37
38
|
PasskeyProviderClient: () => OneAuthClient,
|
|
39
|
+
createOneAuthProvider: () => createOneAuthProvider,
|
|
38
40
|
createPasskeyAccount: () => createPasskeyAccount,
|
|
39
41
|
createPasskeyProvider: () => createPasskeyProvider,
|
|
40
42
|
createPasskeyWalletClient: () => createPasskeyWalletClient,
|
|
@@ -156,7 +158,13 @@ function resolveTokenAddress(token, chainId) {
|
|
|
156
158
|
if ((0, import_viem.isAddress)(token)) {
|
|
157
159
|
return token;
|
|
158
160
|
}
|
|
159
|
-
|
|
161
|
+
const match = getSupportedTokens(chainId).find(
|
|
162
|
+
(t) => t.symbol.toUpperCase() === token.toUpperCase()
|
|
163
|
+
);
|
|
164
|
+
if (!match) {
|
|
165
|
+
return (0, import_sdk.getTokenAddress)(token, chainId);
|
|
166
|
+
}
|
|
167
|
+
return match.address;
|
|
160
168
|
}
|
|
161
169
|
function isTestnet(chainId) {
|
|
162
170
|
try {
|
|
@@ -258,9 +266,7 @@ var OneAuthClient = class {
|
|
|
258
266
|
const response = await fetch(
|
|
259
267
|
`${this.config.providerUrl}/api/intent/status/${intentId}`,
|
|
260
268
|
{
|
|
261
|
-
headers: {
|
|
262
|
-
"x-client-id": this.config.clientId
|
|
263
|
-
}
|
|
269
|
+
headers: this.config.clientId ? { "x-client-id": this.config.clientId } : {}
|
|
264
270
|
}
|
|
265
271
|
);
|
|
266
272
|
if (response.ok) {
|
|
@@ -284,9 +290,11 @@ var OneAuthClient = class {
|
|
|
284
290
|
async authWithModal(options) {
|
|
285
291
|
const dialogUrl = this.getDialogUrl();
|
|
286
292
|
const params = new URLSearchParams({
|
|
287
|
-
clientId: this.config.clientId,
|
|
288
293
|
mode: "iframe"
|
|
289
294
|
});
|
|
295
|
+
if (this.config.clientId) {
|
|
296
|
+
params.set("clientId", this.config.clientId);
|
|
297
|
+
}
|
|
290
298
|
if (options?.username) {
|
|
291
299
|
params.set("username", options.username);
|
|
292
300
|
}
|
|
@@ -302,6 +310,55 @@ var OneAuthClient = class {
|
|
|
302
310
|
const { dialog, iframe, cleanup } = this.createModalDialog(url);
|
|
303
311
|
return this.waitForModalAuthResponse(dialog, iframe, cleanup);
|
|
304
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Open the connect dialog (lightweight connection without passkey auth).
|
|
315
|
+
*
|
|
316
|
+
* This method shows a simple connection confirmation dialog that doesn't
|
|
317
|
+
* require a passkey signature. Users can optionally enable "auto-connect"
|
|
318
|
+
* to skip this dialog in the future.
|
|
319
|
+
*
|
|
320
|
+
* If the user has never connected before, this will return action: "switch"
|
|
321
|
+
* to indicate that the full auth modal should be opened instead.
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```typescript
|
|
325
|
+
* const result = await client.connectWithModal();
|
|
326
|
+
*
|
|
327
|
+
* if (result.success) {
|
|
328
|
+
* console.log('Connected as:', result.username);
|
|
329
|
+
* } else if (result.action === 'switch') {
|
|
330
|
+
* // User needs to sign in first
|
|
331
|
+
* const authResult = await client.authWithModal();
|
|
332
|
+
* }
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
async connectWithModal(options) {
|
|
336
|
+
const dialogUrl = this.getDialogUrl();
|
|
337
|
+
const params = new URLSearchParams({
|
|
338
|
+
mode: "iframe"
|
|
339
|
+
});
|
|
340
|
+
if (this.config.clientId) {
|
|
341
|
+
params.set("clientId", this.config.clientId);
|
|
342
|
+
}
|
|
343
|
+
const themeParams = this.getThemeParams(options?.theme);
|
|
344
|
+
if (themeParams) {
|
|
345
|
+
const themeParsed = new URLSearchParams(themeParams);
|
|
346
|
+
themeParsed.forEach((value, key) => params.set(key, value));
|
|
347
|
+
}
|
|
348
|
+
const url = `${dialogUrl}/dialog/connect?${params.toString()}`;
|
|
349
|
+
const { dialog, iframe, cleanup } = this.createModalDialog(url);
|
|
350
|
+
const ready = await this.waitForDialogReady(dialog, iframe, cleanup, {
|
|
351
|
+
mode: "iframe"
|
|
352
|
+
});
|
|
353
|
+
if (!ready) {
|
|
354
|
+
return {
|
|
355
|
+
success: false,
|
|
356
|
+
action: "cancel",
|
|
357
|
+
error: { code: "USER_CANCELLED", message: "Connection was cancelled" }
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
return this.waitForConnectResponse(dialog, iframe, cleanup);
|
|
361
|
+
}
|
|
305
362
|
/**
|
|
306
363
|
* Authenticate a user with an optional challenge to sign.
|
|
307
364
|
*
|
|
@@ -337,9 +394,11 @@ var OneAuthClient = class {
|
|
|
337
394
|
async authenticate(options) {
|
|
338
395
|
const dialogUrl = this.getDialogUrl();
|
|
339
396
|
const params = new URLSearchParams({
|
|
340
|
-
clientId: this.config.clientId,
|
|
341
397
|
mode: "iframe"
|
|
342
398
|
});
|
|
399
|
+
if (this.config.clientId) {
|
|
400
|
+
params.set("clientId", this.config.clientId);
|
|
401
|
+
}
|
|
343
402
|
if (options?.challenge) {
|
|
344
403
|
params.set("challenge", options.challenge);
|
|
345
404
|
}
|
|
@@ -353,28 +412,30 @@ var OneAuthClient = class {
|
|
|
353
412
|
return this.waitForAuthenticateResponse(dialog, iframe, cleanup);
|
|
354
413
|
}
|
|
355
414
|
/**
|
|
356
|
-
* Show signing in a modal overlay (
|
|
415
|
+
* Show signing in a modal overlay (iframe dialog)
|
|
357
416
|
*/
|
|
358
417
|
async signWithModal(options) {
|
|
359
418
|
const dialogUrl = this.getDialogUrl();
|
|
360
419
|
const themeParams = this.getThemeParams(options?.theme);
|
|
361
420
|
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
362
421
|
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
username: options.username,
|
|
371
|
-
description: options.description,
|
|
372
|
-
transaction: options.transaction,
|
|
373
|
-
metadata: options.metadata
|
|
374
|
-
}, dialogOrigin);
|
|
375
|
-
resolve();
|
|
376
|
-
};
|
|
422
|
+
const ready = await this.waitForDialogReady(dialog, iframe, cleanup, {
|
|
423
|
+
mode: "iframe",
|
|
424
|
+
challenge: options.challenge,
|
|
425
|
+
username: options.username,
|
|
426
|
+
description: options.description,
|
|
427
|
+
transaction: options.transaction,
|
|
428
|
+
metadata: options.metadata
|
|
377
429
|
});
|
|
430
|
+
if (!ready) {
|
|
431
|
+
return {
|
|
432
|
+
success: false,
|
|
433
|
+
error: {
|
|
434
|
+
code: "USER_REJECTED",
|
|
435
|
+
message: "User closed the dialog"
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
378
439
|
return this.waitForSigningResponse(dialog, iframe, cleanup);
|
|
379
440
|
}
|
|
380
441
|
/**
|
|
@@ -447,16 +508,21 @@ var OneAuthClient = class {
|
|
|
447
508
|
}
|
|
448
509
|
};
|
|
449
510
|
}
|
|
511
|
+
const serializedTokenRequests = options.tokenRequests?.map((r) => ({
|
|
512
|
+
token: r.token,
|
|
513
|
+
amount: r.amount.toString()
|
|
514
|
+
}));
|
|
450
515
|
let prepareResponse;
|
|
516
|
+
const requestBody = signedIntent || {
|
|
517
|
+
username: options.username,
|
|
518
|
+
targetChain: options.targetChain,
|
|
519
|
+
calls: options.calls,
|
|
520
|
+
tokenRequests: serializedTokenRequests,
|
|
521
|
+
sourceAssets: options.sourceAssets,
|
|
522
|
+
sourceChainId: options.sourceChainId,
|
|
523
|
+
...this.config.clientId && { clientId: this.config.clientId }
|
|
524
|
+
};
|
|
451
525
|
try {
|
|
452
|
-
const requestBody = signedIntent || {
|
|
453
|
-
username: options.username,
|
|
454
|
-
targetChain: options.targetChain,
|
|
455
|
-
calls: options.calls,
|
|
456
|
-
tokenRequests: options.tokenRequests,
|
|
457
|
-
sourceAssets: options.sourceAssets,
|
|
458
|
-
clientId: this.config.clientId
|
|
459
|
-
};
|
|
460
526
|
const response = await fetch(`${this.config.providerUrl}/api/intent/prepare`, {
|
|
461
527
|
method: "POST",
|
|
462
528
|
headers: {
|
|
@@ -493,112 +559,190 @@ var OneAuthClient = class {
|
|
|
493
559
|
};
|
|
494
560
|
}
|
|
495
561
|
const dialogUrl = this.getDialogUrl();
|
|
496
|
-
const
|
|
562
|
+
const themeParams = this.getThemeParams();
|
|
563
|
+
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
497
564
|
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
498
565
|
const dialogOrigin = this.getDialogOrigin();
|
|
499
|
-
await
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
accountAddress: prepareResponse.accountAddress,
|
|
513
|
-
intentId: prepareResponse.intentId
|
|
514
|
-
}, dialogOrigin);
|
|
515
|
-
resolve();
|
|
516
|
-
}
|
|
517
|
-
};
|
|
518
|
-
window.addEventListener("message", handleReady);
|
|
566
|
+
const ready = await this.waitForDialogReady(dialog, iframe, cleanup, {
|
|
567
|
+
mode: "iframe",
|
|
568
|
+
calls,
|
|
569
|
+
chainId: targetChain,
|
|
570
|
+
transaction: prepareResponse.transaction,
|
|
571
|
+
challenge: prepareResponse.challenge,
|
|
572
|
+
username,
|
|
573
|
+
accountAddress: prepareResponse.accountAddress,
|
|
574
|
+
originMessages: prepareResponse.originMessages,
|
|
575
|
+
tokenRequests: serializedTokenRequests,
|
|
576
|
+
expiresAt: prepareResponse.expiresAt,
|
|
577
|
+
userId: prepareResponse.userId,
|
|
578
|
+
intentOp: prepareResponse.intentOp
|
|
519
579
|
});
|
|
520
|
-
|
|
580
|
+
if (!ready) {
|
|
581
|
+
return {
|
|
582
|
+
success: false,
|
|
583
|
+
intentId: "",
|
|
584
|
+
status: "failed",
|
|
585
|
+
error: { code: "USER_CANCELLED", message: "User closed the dialog" }
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
const signingResult = await this.waitForSigningWithRefresh(
|
|
589
|
+
dialog,
|
|
590
|
+
iframe,
|
|
591
|
+
cleanup,
|
|
592
|
+
dialogOrigin,
|
|
593
|
+
// Refresh callback - called when dialog requests a quote refresh
|
|
594
|
+
async () => {
|
|
595
|
+
console.log("[SDK] Dialog requested quote refresh, re-preparing intent");
|
|
596
|
+
try {
|
|
597
|
+
const refreshResponse = await fetch(`${this.config.providerUrl}/api/intent/prepare`, {
|
|
598
|
+
method: "POST",
|
|
599
|
+
headers: { "Content-Type": "application/json" },
|
|
600
|
+
body: JSON.stringify(requestBody),
|
|
601
|
+
credentials: "include"
|
|
602
|
+
});
|
|
603
|
+
if (!refreshResponse.ok) {
|
|
604
|
+
console.error("[SDK] Quote refresh failed:", await refreshResponse.text());
|
|
605
|
+
return null;
|
|
606
|
+
}
|
|
607
|
+
const refreshedData = await refreshResponse.json();
|
|
608
|
+
prepareResponse = refreshedData;
|
|
609
|
+
return {
|
|
610
|
+
intentOp: refreshedData.intentOp,
|
|
611
|
+
expiresAt: refreshedData.expiresAt,
|
|
612
|
+
challenge: refreshedData.challenge,
|
|
613
|
+
originMessages: refreshedData.originMessages,
|
|
614
|
+
transaction: refreshedData.transaction
|
|
615
|
+
};
|
|
616
|
+
} catch (error) {
|
|
617
|
+
console.error("[SDK] Quote refresh error:", error);
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
);
|
|
521
622
|
if (!signingResult.success) {
|
|
522
623
|
return {
|
|
523
624
|
success: false,
|
|
524
|
-
intentId:
|
|
625
|
+
intentId: "",
|
|
626
|
+
// No intentId yet - signing was cancelled before execute
|
|
525
627
|
status: "failed",
|
|
526
628
|
error: signingResult.error
|
|
527
629
|
};
|
|
528
630
|
}
|
|
631
|
+
const dialogExecutedIntent = "intentId" in signingResult && signingResult.intentId;
|
|
529
632
|
let executeResponse;
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
633
|
+
if (dialogExecutedIntent) {
|
|
634
|
+
executeResponse = {
|
|
635
|
+
success: true,
|
|
636
|
+
intentId: signingResult.intentId,
|
|
637
|
+
status: "pending"
|
|
638
|
+
};
|
|
639
|
+
} else {
|
|
640
|
+
try {
|
|
641
|
+
const response = await fetch(`${this.config.providerUrl}/api/intent/execute`, {
|
|
642
|
+
method: "POST",
|
|
643
|
+
headers: {
|
|
644
|
+
"Content-Type": "application/json"
|
|
645
|
+
},
|
|
646
|
+
body: JSON.stringify({
|
|
647
|
+
// Data from prepare response (no intentId yet - created on execute)
|
|
648
|
+
intentOp: prepareResponse.intentOp,
|
|
649
|
+
userId: prepareResponse.userId,
|
|
650
|
+
targetChain: prepareResponse.targetChain,
|
|
651
|
+
calls: prepareResponse.calls,
|
|
652
|
+
expiresAt: prepareResponse.expiresAt,
|
|
653
|
+
// Signature from dialog
|
|
654
|
+
signature: signingResult.signature,
|
|
655
|
+
passkey: signingResult.passkey
|
|
656
|
+
// Include passkey info for signature encoding
|
|
657
|
+
})
|
|
658
|
+
});
|
|
659
|
+
if (!response.ok) {
|
|
660
|
+
const errorData = await response.json().catch(() => ({}));
|
|
661
|
+
this.sendTransactionStatus(iframe, "failed");
|
|
662
|
+
await this.waitForDialogClose(dialog, cleanup);
|
|
663
|
+
return {
|
|
664
|
+
success: false,
|
|
665
|
+
intentId: "",
|
|
666
|
+
// No intentId - execute failed before creation
|
|
667
|
+
status: "failed",
|
|
668
|
+
error: {
|
|
669
|
+
code: "EXECUTE_FAILED",
|
|
670
|
+
message: errorData.error || "Failed to execute intent"
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
executeResponse = await response.json();
|
|
675
|
+
} catch (error) {
|
|
545
676
|
this.sendTransactionStatus(iframe, "failed");
|
|
546
677
|
await this.waitForDialogClose(dialog, cleanup);
|
|
547
678
|
return {
|
|
548
679
|
success: false,
|
|
549
|
-
intentId:
|
|
680
|
+
intentId: "",
|
|
681
|
+
// No intentId - network error before creation
|
|
550
682
|
status: "failed",
|
|
551
683
|
error: {
|
|
552
|
-
code: "
|
|
553
|
-
message:
|
|
684
|
+
code: "NETWORK_ERROR",
|
|
685
|
+
message: error instanceof Error ? error.message : "Network error"
|
|
554
686
|
}
|
|
555
687
|
};
|
|
556
688
|
}
|
|
557
|
-
executeResponse = await response.json();
|
|
558
|
-
} catch (error) {
|
|
559
|
-
this.sendTransactionStatus(iframe, "failed");
|
|
560
|
-
await this.waitForDialogClose(dialog, cleanup);
|
|
561
|
-
return {
|
|
562
|
-
success: false,
|
|
563
|
-
intentId: prepareResponse.intentId,
|
|
564
|
-
status: "failed",
|
|
565
|
-
error: {
|
|
566
|
-
code: "NETWORK_ERROR",
|
|
567
|
-
message: error instanceof Error ? error.message : "Network error"
|
|
568
|
-
}
|
|
569
|
-
};
|
|
570
689
|
}
|
|
571
|
-
const closeOn = options.closeOn || "preconfirmed";
|
|
572
|
-
const acceptPreconfirmations = closeOn !== "completed";
|
|
573
690
|
let finalStatus = executeResponse.status;
|
|
574
691
|
let finalTxHash = executeResponse.transactionHash;
|
|
575
692
|
if (finalStatus === "pending") {
|
|
576
|
-
this.sendTransactionStatus(iframe, "
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
693
|
+
this.sendTransactionStatus(iframe, "pending");
|
|
694
|
+
const maxAttempts = 120;
|
|
695
|
+
const pollIntervalMs = 1500;
|
|
696
|
+
let lastStatus = "pending";
|
|
697
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
698
|
+
try {
|
|
699
|
+
const statusResponse = await fetch(
|
|
700
|
+
`${this.config.providerUrl}/api/intent/status/${executeResponse.intentId}`,
|
|
701
|
+
{
|
|
702
|
+
method: "GET",
|
|
703
|
+
headers: this.config.clientId ? { "x-client-id": this.config.clientId } : {}
|
|
704
|
+
}
|
|
705
|
+
);
|
|
706
|
+
if (statusResponse.ok) {
|
|
707
|
+
const statusResult = await statusResponse.json();
|
|
708
|
+
finalStatus = statusResult.status;
|
|
709
|
+
finalTxHash = statusResult.transactionHash;
|
|
710
|
+
if (finalStatus !== lastStatus) {
|
|
711
|
+
this.sendTransactionStatus(iframe, finalStatus, finalTxHash);
|
|
712
|
+
lastStatus = finalStatus;
|
|
713
|
+
}
|
|
714
|
+
const closeOn2 = options.closeOn || "preconfirmed";
|
|
715
|
+
const successStatuses2 = {
|
|
716
|
+
claimed: ["claimed", "preconfirmed", "filled", "completed"],
|
|
717
|
+
preconfirmed: ["preconfirmed", "filled", "completed"],
|
|
718
|
+
filled: ["filled", "completed"],
|
|
719
|
+
completed: ["completed"]
|
|
720
|
+
};
|
|
721
|
+
const isTerminal = finalStatus === "failed" || finalStatus === "expired";
|
|
722
|
+
const isSuccess = successStatuses2[closeOn2]?.includes(finalStatus) ?? false;
|
|
723
|
+
if (isTerminal || isSuccess) {
|
|
724
|
+
break;
|
|
583
725
|
}
|
|
584
726
|
}
|
|
585
|
-
)
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
finalTxHash = waitResult.transactionHash;
|
|
590
|
-
} else {
|
|
591
|
-
console.error("Wait endpoint failed:", await waitResponse.text());
|
|
592
|
-
}
|
|
593
|
-
} catch (waitError) {
|
|
594
|
-
console.error("Failed to wait for intent:", waitError);
|
|
727
|
+
} catch (pollError) {
|
|
728
|
+
console.error("Failed to poll intent status:", pollError);
|
|
729
|
+
}
|
|
730
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
595
731
|
}
|
|
596
732
|
}
|
|
597
|
-
const
|
|
733
|
+
const closeOn = options.closeOn || "preconfirmed";
|
|
734
|
+
const successStatuses = {
|
|
735
|
+
claimed: ["claimed", "preconfirmed", "filled", "completed"],
|
|
736
|
+
preconfirmed: ["preconfirmed", "filled", "completed"],
|
|
737
|
+
filled: ["filled", "completed"],
|
|
738
|
+
completed: ["completed"]
|
|
739
|
+
};
|
|
740
|
+
const isSuccessStatus = successStatuses[closeOn]?.includes(finalStatus) ?? false;
|
|
741
|
+
const displayStatus = isSuccessStatus ? "confirmed" : finalStatus;
|
|
598
742
|
this.sendTransactionStatus(iframe, displayStatus, finalTxHash);
|
|
599
743
|
await this.waitForDialogClose(dialog, cleanup);
|
|
600
744
|
if (options.waitForHash && !finalTxHash) {
|
|
601
|
-
const hash = await this.waitForTransactionHash(
|
|
745
|
+
const hash = await this.waitForTransactionHash(executeResponse.intentId, {
|
|
602
746
|
timeoutMs: options.hashTimeoutMs,
|
|
603
747
|
intervalMs: options.hashIntervalMs
|
|
604
748
|
});
|
|
@@ -609,7 +753,7 @@ var OneAuthClient = class {
|
|
|
609
753
|
finalStatus = "failed";
|
|
610
754
|
return {
|
|
611
755
|
success: false,
|
|
612
|
-
intentId:
|
|
756
|
+
intentId: executeResponse.intentId,
|
|
613
757
|
status: finalStatus,
|
|
614
758
|
transactionHash: finalTxHash,
|
|
615
759
|
operationId: executeResponse.operationId,
|
|
@@ -621,14 +765,204 @@ var OneAuthClient = class {
|
|
|
621
765
|
}
|
|
622
766
|
}
|
|
623
767
|
return {
|
|
624
|
-
success:
|
|
625
|
-
intentId:
|
|
768
|
+
success: isSuccessStatus,
|
|
769
|
+
intentId: executeResponse.intentId,
|
|
626
770
|
status: finalStatus,
|
|
627
771
|
transactionHash: finalTxHash,
|
|
628
772
|
operationId: executeResponse.operationId,
|
|
629
773
|
error: executeResponse.error
|
|
630
774
|
};
|
|
631
775
|
}
|
|
776
|
+
/**
|
|
777
|
+
* Send a batch of intents for multi-chain execution with a single passkey tap.
|
|
778
|
+
*
|
|
779
|
+
* This method prepares multiple intents, shows a paginated review,
|
|
780
|
+
* and signs all intents with a single passkey tap via a shared merkle tree.
|
|
781
|
+
*
|
|
782
|
+
* @example
|
|
783
|
+
* ```typescript
|
|
784
|
+
* const result = await client.sendBatchIntent({
|
|
785
|
+
* username: 'alice',
|
|
786
|
+
* intents: [
|
|
787
|
+
* {
|
|
788
|
+
* targetChain: 8453, // Base
|
|
789
|
+
* calls: [{ to: '0x...', data: '0x...', label: 'Swap on Base' }],
|
|
790
|
+
* },
|
|
791
|
+
* {
|
|
792
|
+
* targetChain: 42161, // Arbitrum
|
|
793
|
+
* calls: [{ to: '0x...', data: '0x...', label: 'Mint on Arbitrum' }],
|
|
794
|
+
* },
|
|
795
|
+
* ],
|
|
796
|
+
* });
|
|
797
|
+
*
|
|
798
|
+
* if (result.success) {
|
|
799
|
+
* console.log(`${result.successCount} intents submitted`);
|
|
800
|
+
* }
|
|
801
|
+
* ```
|
|
802
|
+
*/
|
|
803
|
+
async sendBatchIntent(options) {
|
|
804
|
+
if (!options.username) {
|
|
805
|
+
return {
|
|
806
|
+
success: false,
|
|
807
|
+
results: [],
|
|
808
|
+
successCount: 0,
|
|
809
|
+
failureCount: 0
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
if (!options.intents?.length) {
|
|
813
|
+
return {
|
|
814
|
+
success: false,
|
|
815
|
+
results: [],
|
|
816
|
+
successCount: 0,
|
|
817
|
+
failureCount: 0
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
const serializedIntents = options.intents.map((intent) => ({
|
|
821
|
+
targetChain: intent.targetChain,
|
|
822
|
+
calls: intent.calls,
|
|
823
|
+
tokenRequests: intent.tokenRequests?.map((r) => ({
|
|
824
|
+
token: r.token,
|
|
825
|
+
amount: r.amount.toString()
|
|
826
|
+
})),
|
|
827
|
+
sourceAssets: intent.sourceAssets,
|
|
828
|
+
sourceChainId: intent.sourceChainId
|
|
829
|
+
}));
|
|
830
|
+
const requestBody = {
|
|
831
|
+
username: options.username,
|
|
832
|
+
intents: serializedIntents,
|
|
833
|
+
...this.config.clientId && { clientId: this.config.clientId }
|
|
834
|
+
};
|
|
835
|
+
let prepareResponse;
|
|
836
|
+
try {
|
|
837
|
+
const response = await fetch(`${this.config.providerUrl}/api/intent/batch-prepare`, {
|
|
838
|
+
method: "POST",
|
|
839
|
+
headers: { "Content-Type": "application/json" },
|
|
840
|
+
body: JSON.stringify(requestBody)
|
|
841
|
+
});
|
|
842
|
+
if (!response.ok) {
|
|
843
|
+
const errorData = await response.json().catch(() => ({}));
|
|
844
|
+
const errorMessage = errorData.error || "Failed to prepare batch intent";
|
|
845
|
+
if (errorMessage.includes("User not found")) {
|
|
846
|
+
localStorage.removeItem("1auth-user");
|
|
847
|
+
}
|
|
848
|
+
return {
|
|
849
|
+
success: false,
|
|
850
|
+
results: [],
|
|
851
|
+
successCount: 0,
|
|
852
|
+
failureCount: 0
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
prepareResponse = await response.json();
|
|
856
|
+
} catch {
|
|
857
|
+
return {
|
|
858
|
+
success: false,
|
|
859
|
+
results: [],
|
|
860
|
+
successCount: 0,
|
|
861
|
+
failureCount: 0
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
const dialogUrl = this.getDialogUrl();
|
|
865
|
+
const themeParams = this.getThemeParams();
|
|
866
|
+
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
867
|
+
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
868
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
869
|
+
const ready = await this.waitForDialogReady(dialog, iframe, cleanup, {
|
|
870
|
+
mode: "iframe",
|
|
871
|
+
batchMode: true,
|
|
872
|
+
batchIntents: prepareResponse.intents,
|
|
873
|
+
challenge: prepareResponse.challenge,
|
|
874
|
+
username: options.username,
|
|
875
|
+
accountAddress: prepareResponse.accountAddress,
|
|
876
|
+
userId: prepareResponse.userId,
|
|
877
|
+
expiresAt: prepareResponse.expiresAt
|
|
878
|
+
});
|
|
879
|
+
if (!ready) {
|
|
880
|
+
return {
|
|
881
|
+
success: false,
|
|
882
|
+
results: [],
|
|
883
|
+
successCount: 0,
|
|
884
|
+
failureCount: 0
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
const batchResult = await new Promise((resolve) => {
|
|
888
|
+
const handleMessage = async (event) => {
|
|
889
|
+
if (event.origin !== dialogOrigin) return;
|
|
890
|
+
const message = event.data;
|
|
891
|
+
if (message?.type === "PASSKEY_REFRESH_QUOTE") {
|
|
892
|
+
console.log("[SDK] Batch dialog requested quote refresh, re-preparing all intents");
|
|
893
|
+
try {
|
|
894
|
+
const refreshResponse = await fetch(`${this.config.providerUrl}/api/intent/batch-prepare`, {
|
|
895
|
+
method: "POST",
|
|
896
|
+
headers: { "Content-Type": "application/json" },
|
|
897
|
+
body: JSON.stringify(requestBody)
|
|
898
|
+
});
|
|
899
|
+
if (refreshResponse.ok) {
|
|
900
|
+
const refreshed = await refreshResponse.json();
|
|
901
|
+
prepareResponse = refreshed;
|
|
902
|
+
iframe.contentWindow?.postMessage({
|
|
903
|
+
type: "PASSKEY_REFRESH_COMPLETE",
|
|
904
|
+
batchIntents: refreshed.intents,
|
|
905
|
+
challenge: refreshed.challenge,
|
|
906
|
+
expiresAt: refreshed.expiresAt
|
|
907
|
+
}, dialogOrigin);
|
|
908
|
+
} else {
|
|
909
|
+
iframe.contentWindow?.postMessage({
|
|
910
|
+
type: "PASSKEY_REFRESH_ERROR",
|
|
911
|
+
error: "Failed to refresh batch quotes"
|
|
912
|
+
}, dialogOrigin);
|
|
913
|
+
}
|
|
914
|
+
} catch {
|
|
915
|
+
iframe.contentWindow?.postMessage({
|
|
916
|
+
type: "PASSKEY_REFRESH_ERROR",
|
|
917
|
+
error: "Failed to refresh batch quotes"
|
|
918
|
+
}, dialogOrigin);
|
|
919
|
+
}
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
if (message?.type === "PASSKEY_SIGNING_RESULT") {
|
|
923
|
+
window.removeEventListener("message", handleMessage);
|
|
924
|
+
if (message.success && message.data?.batchResults) {
|
|
925
|
+
const rawResults = message.data.batchResults;
|
|
926
|
+
const results = rawResults.map((r) => ({
|
|
927
|
+
index: r.index,
|
|
928
|
+
success: r.success ?? r.status !== "FAILED",
|
|
929
|
+
intentId: r.intentId || r.operationId || "",
|
|
930
|
+
status: r.status === "FAILED" ? "failed" : "pending",
|
|
931
|
+
error: r.error ? { code: "EXECUTE_FAILED", message: r.error } : void 0
|
|
932
|
+
}));
|
|
933
|
+
const successCount = results.filter((r) => r.success).length;
|
|
934
|
+
await this.waitForDialogClose(dialog, cleanup);
|
|
935
|
+
resolve({
|
|
936
|
+
success: successCount === results.length,
|
|
937
|
+
results,
|
|
938
|
+
successCount,
|
|
939
|
+
failureCount: results.length - successCount
|
|
940
|
+
});
|
|
941
|
+
} else {
|
|
942
|
+
cleanup();
|
|
943
|
+
resolve({
|
|
944
|
+
success: false,
|
|
945
|
+
results: [],
|
|
946
|
+
successCount: 0,
|
|
947
|
+
failureCount: 0
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
if (message?.type === "PASSKEY_CLOSE") {
|
|
952
|
+
window.removeEventListener("message", handleMessage);
|
|
953
|
+
cleanup();
|
|
954
|
+
resolve({
|
|
955
|
+
success: false,
|
|
956
|
+
results: [],
|
|
957
|
+
successCount: 0,
|
|
958
|
+
failureCount: 0
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
window.addEventListener("message", handleMessage);
|
|
963
|
+
});
|
|
964
|
+
return batchResult;
|
|
965
|
+
}
|
|
632
966
|
/**
|
|
633
967
|
* Send transaction status to the dialog iframe
|
|
634
968
|
*/
|
|
@@ -705,7 +1039,77 @@ var OneAuthClient = class {
|
|
|
705
1039
|
const payload = message?.data;
|
|
706
1040
|
if (message?.type === "PASSKEY_SIGNING_RESULT") {
|
|
707
1041
|
window.removeEventListener("message", handleMessage);
|
|
708
|
-
if (message.success && payload?.
|
|
1042
|
+
if (message.success && payload?.intentId) {
|
|
1043
|
+
resolve({
|
|
1044
|
+
success: true,
|
|
1045
|
+
intentId: payload.intentId
|
|
1046
|
+
});
|
|
1047
|
+
} else if (message.success && payload?.signature) {
|
|
1048
|
+
resolve({
|
|
1049
|
+
success: true,
|
|
1050
|
+
signature: payload.signature,
|
|
1051
|
+
passkey: payload.passkey,
|
|
1052
|
+
signedHash: payload.signedHash
|
|
1053
|
+
});
|
|
1054
|
+
} else {
|
|
1055
|
+
resolve({
|
|
1056
|
+
success: false,
|
|
1057
|
+
error: message.error || {
|
|
1058
|
+
code: "SIGNING_FAILED",
|
|
1059
|
+
message: "Signing failed"
|
|
1060
|
+
}
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
} else if (message?.type === "PASSKEY_CLOSE") {
|
|
1064
|
+
window.removeEventListener("message", handleMessage);
|
|
1065
|
+
cleanup();
|
|
1066
|
+
resolve({
|
|
1067
|
+
success: false,
|
|
1068
|
+
error: {
|
|
1069
|
+
code: "USER_REJECTED",
|
|
1070
|
+
message: "User closed the dialog"
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
window.addEventListener("message", handleMessage);
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Wait for signing result with auto-refresh support
|
|
1080
|
+
* This method handles both signing results and quote refresh requests from the dialog
|
|
1081
|
+
*/
|
|
1082
|
+
waitForSigningWithRefresh(dialog, iframe, cleanup, dialogOrigin, onRefresh) {
|
|
1083
|
+
console.log("[SDK] waitForSigningWithRefresh, expecting origin:", dialogOrigin);
|
|
1084
|
+
return new Promise((resolve) => {
|
|
1085
|
+
const handleMessage = async (event) => {
|
|
1086
|
+
if (event.origin !== dialogOrigin) return;
|
|
1087
|
+
const message = event.data;
|
|
1088
|
+
if (message?.type === "PASSKEY_REFRESH_QUOTE") {
|
|
1089
|
+
console.log("[SDK] Received quote refresh request from dialog");
|
|
1090
|
+
const refreshedData = await onRefresh();
|
|
1091
|
+
if (refreshedData) {
|
|
1092
|
+
iframe.contentWindow?.postMessage({
|
|
1093
|
+
type: "PASSKEY_REFRESH_COMPLETE",
|
|
1094
|
+
...refreshedData
|
|
1095
|
+
}, dialogOrigin);
|
|
1096
|
+
} else {
|
|
1097
|
+
iframe.contentWindow?.postMessage({
|
|
1098
|
+
type: "PASSKEY_REFRESH_ERROR",
|
|
1099
|
+
error: "Failed to refresh quote"
|
|
1100
|
+
}, dialogOrigin);
|
|
1101
|
+
}
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
const payload = message?.data;
|
|
1105
|
+
if (message?.type === "PASSKEY_SIGNING_RESULT") {
|
|
1106
|
+
window.removeEventListener("message", handleMessage);
|
|
1107
|
+
if (message.success && payload?.intentId) {
|
|
1108
|
+
resolve({
|
|
1109
|
+
success: true,
|
|
1110
|
+
intentId: payload.intentId
|
|
1111
|
+
});
|
|
1112
|
+
} else if (message.success && payload?.signature) {
|
|
709
1113
|
resolve({
|
|
710
1114
|
success: true,
|
|
711
1115
|
signature: payload.signature,
|
|
@@ -771,9 +1175,7 @@ var OneAuthClient = class {
|
|
|
771
1175
|
const response = await fetch(
|
|
772
1176
|
`${this.config.providerUrl}/api/intent/status/${intentId}`,
|
|
773
1177
|
{
|
|
774
|
-
headers: {
|
|
775
|
-
"x-client-id": this.config.clientId
|
|
776
|
-
}
|
|
1178
|
+
headers: this.config.clientId ? { "x-client-id": this.config.clientId } : {}
|
|
777
1179
|
}
|
|
778
1180
|
);
|
|
779
1181
|
if (!response.ok) {
|
|
@@ -808,6 +1210,43 @@ var OneAuthClient = class {
|
|
|
808
1210
|
};
|
|
809
1211
|
}
|
|
810
1212
|
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Get the history of intents for the authenticated user.
|
|
1215
|
+
*
|
|
1216
|
+
* Requires an active session (user must be logged in).
|
|
1217
|
+
*
|
|
1218
|
+
* @example
|
|
1219
|
+
* ```typescript
|
|
1220
|
+
* // Get recent intents
|
|
1221
|
+
* const history = await client.getIntentHistory({ limit: 10 });
|
|
1222
|
+
*
|
|
1223
|
+
* // Filter by status
|
|
1224
|
+
* const pending = await client.getIntentHistory({ status: 'pending' });
|
|
1225
|
+
*
|
|
1226
|
+
* // Filter by date range
|
|
1227
|
+
* const lastWeek = await client.getIntentHistory({
|
|
1228
|
+
* from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
1229
|
+
* });
|
|
1230
|
+
* ```
|
|
1231
|
+
*/
|
|
1232
|
+
async getIntentHistory(options) {
|
|
1233
|
+
const queryParams = new URLSearchParams();
|
|
1234
|
+
if (options?.limit) queryParams.set("limit", String(options.limit));
|
|
1235
|
+
if (options?.offset) queryParams.set("offset", String(options.offset));
|
|
1236
|
+
if (options?.status) queryParams.set("status", options.status);
|
|
1237
|
+
if (options?.from) queryParams.set("from", options.from);
|
|
1238
|
+
if (options?.to) queryParams.set("to", options.to);
|
|
1239
|
+
const url = `${this.config.providerUrl}/api/intent/history${queryParams.toString() ? `?${queryParams}` : ""}`;
|
|
1240
|
+
const response = await fetch(url, {
|
|
1241
|
+
headers: this.config.clientId ? { "x-client-id": this.config.clientId } : {},
|
|
1242
|
+
credentials: "include"
|
|
1243
|
+
});
|
|
1244
|
+
if (!response.ok) {
|
|
1245
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1246
|
+
throw new Error(errorData.error || "Failed to get intent history");
|
|
1247
|
+
}
|
|
1248
|
+
return response.json();
|
|
1249
|
+
}
|
|
811
1250
|
/**
|
|
812
1251
|
* Send a swap intent through the Rhinestone orchestrator
|
|
813
1252
|
*
|
|
@@ -870,17 +1309,21 @@ var OneAuthClient = class {
|
|
|
870
1309
|
};
|
|
871
1310
|
}
|
|
872
1311
|
};
|
|
873
|
-
|
|
874
|
-
if (
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1312
|
+
let fromTokenAddress;
|
|
1313
|
+
if (options.fromToken) {
|
|
1314
|
+
const fromTokenResult = resolveToken(options.fromToken, "fromToken");
|
|
1315
|
+
if (!fromTokenResult.address) {
|
|
1316
|
+
return {
|
|
1317
|
+
success: false,
|
|
1318
|
+
intentId: "",
|
|
1319
|
+
status: "failed",
|
|
1320
|
+
error: {
|
|
1321
|
+
code: "INVALID_TOKEN",
|
|
1322
|
+
message: fromTokenResult.error || `Unknown fromToken: ${options.fromToken}`
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
fromTokenAddress = fromTokenResult.address;
|
|
884
1327
|
}
|
|
885
1328
|
const toTokenResult = resolveToken(options.toToken, "toToken");
|
|
886
1329
|
if (!toTokenResult.address) {
|
|
@@ -894,18 +1337,17 @@ var OneAuthClient = class {
|
|
|
894
1337
|
}
|
|
895
1338
|
};
|
|
896
1339
|
}
|
|
897
|
-
const fromTokenAddress = fromTokenResult.address;
|
|
898
1340
|
const toTokenAddress = toTokenResult.address;
|
|
899
1341
|
console.log("[SDK sendSwap] Token resolution:", {
|
|
900
|
-
fromToken: options.fromToken,
|
|
901
|
-
fromTokenAddress,
|
|
1342
|
+
fromToken: options.fromToken ?? "Any",
|
|
1343
|
+
fromTokenAddress: fromTokenAddress ?? "orchestrator picks",
|
|
902
1344
|
toToken: options.toToken,
|
|
903
1345
|
toTokenAddress,
|
|
904
1346
|
targetChain: options.targetChain
|
|
905
1347
|
});
|
|
906
1348
|
const formatTokenLabel = (token, fallback) => {
|
|
907
1349
|
if (!token.startsWith("0x")) {
|
|
908
|
-
return token
|
|
1350
|
+
return token;
|
|
909
1351
|
}
|
|
910
1352
|
try {
|
|
911
1353
|
return getTokenSymbol(token, options.targetChain);
|
|
@@ -913,15 +1355,11 @@ var OneAuthClient = class {
|
|
|
913
1355
|
return fallback;
|
|
914
1356
|
}
|
|
915
1357
|
};
|
|
916
|
-
const fromSymbol = formatTokenLabel(
|
|
917
|
-
options.fromToken,
|
|
918
|
-
`${options.fromToken.slice(0, 6)}...${options.fromToken.slice(-4)}`
|
|
919
|
-
);
|
|
920
1358
|
const toSymbol = formatTokenLabel(
|
|
921
1359
|
options.toToken,
|
|
922
1360
|
`${options.toToken.slice(0, 6)}...${options.toToken.slice(-4)}`
|
|
923
1361
|
);
|
|
924
|
-
const isFromNativeEth = fromTokenAddress === "0x0000000000000000000000000000000000000000";
|
|
1362
|
+
const isFromNativeEth = fromTokenAddress ? fromTokenAddress === "0x0000000000000000000000000000000000000000" : false;
|
|
925
1363
|
const isToNativeEth = toTokenAddress === "0x0000000000000000000000000000000000000000";
|
|
926
1364
|
const KNOWN_DECIMALS = {
|
|
927
1365
|
ETH: 18,
|
|
@@ -931,31 +1369,33 @@ var OneAuthClient = class {
|
|
|
931
1369
|
USDT0: 6
|
|
932
1370
|
};
|
|
933
1371
|
const getDecimals = (symbol, chainId) => {
|
|
934
|
-
const upperSymbol = symbol.toUpperCase();
|
|
935
1372
|
try {
|
|
936
|
-
const
|
|
937
|
-
|
|
1373
|
+
const match = getSupportedTokens(chainId).find(
|
|
1374
|
+
(t) => t.symbol.toUpperCase() === symbol.toUpperCase()
|
|
1375
|
+
);
|
|
1376
|
+
if (match) {
|
|
1377
|
+
console.log(`[SDK] getTokenDecimals(${match.symbol}, ${chainId}) = ${match.decimals}`);
|
|
1378
|
+
return match.decimals;
|
|
1379
|
+
}
|
|
1380
|
+
const decimals = (0, import_sdk.getTokenDecimals)(symbol, chainId);
|
|
1381
|
+
console.log(`[SDK] getTokenDecimals(${symbol}, ${chainId}) = ${decimals}`);
|
|
938
1382
|
return decimals;
|
|
939
1383
|
} catch (e) {
|
|
940
|
-
|
|
1384
|
+
const upperSymbol = symbol.toUpperCase();
|
|
1385
|
+
console.warn(`[SDK] getTokenDecimals failed for ${symbol}, using fallback`, e);
|
|
941
1386
|
return KNOWN_DECIMALS[upperSymbol] ?? 18;
|
|
942
1387
|
}
|
|
943
1388
|
};
|
|
944
|
-
const fromDecimals = getDecimals(options.fromToken, options.targetChain);
|
|
945
1389
|
const toDecimals = getDecimals(options.toToken, options.targetChain);
|
|
946
|
-
const isBridge = options.fromToken.toUpperCase() === options.toToken.toUpperCase();
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
amount: (0, import_viem2.parseUnits)(options.amount, toDecimals).toString()
|
|
952
|
-
}];
|
|
953
|
-
}
|
|
1390
|
+
const isBridge = options.fromToken ? options.fromToken.toUpperCase() === options.toToken.toUpperCase() : false;
|
|
1391
|
+
const tokenRequests = [{
|
|
1392
|
+
token: toTokenAddress,
|
|
1393
|
+
amount: (0, import_viem2.parseUnits)(options.amount, toDecimals)
|
|
1394
|
+
}];
|
|
954
1395
|
console.log("[SDK sendSwap] Building intent:", {
|
|
955
1396
|
isBridge,
|
|
956
1397
|
isFromNativeEth,
|
|
957
1398
|
isToNativeEth,
|
|
958
|
-
fromDecimals,
|
|
959
1399
|
toDecimals,
|
|
960
1400
|
tokenRequests
|
|
961
1401
|
});
|
|
@@ -966,15 +1406,20 @@ var OneAuthClient = class {
|
|
|
966
1406
|
{
|
|
967
1407
|
// Minimal call - just signals to orchestrator we want the tokenRequests delivered
|
|
968
1408
|
to: toTokenAddress,
|
|
969
|
-
value: "0"
|
|
1409
|
+
value: "0",
|
|
1410
|
+
// SDK provides labels so dialog shows "Buy ETH" not "Send ETH / To: 0x000..."
|
|
1411
|
+
label: `Buy ${toSymbol}`,
|
|
1412
|
+
sublabel: `${options.amount} ${toSymbol}`
|
|
970
1413
|
}
|
|
971
1414
|
],
|
|
972
1415
|
// Request specific output tokens - this is what actually matters for swaps
|
|
973
1416
|
tokenRequests,
|
|
974
1417
|
// Constrain orchestrator to use only the fromToken as input
|
|
975
1418
|
// This ensures the swap uses the correct source token
|
|
976
|
-
//
|
|
977
|
-
sourceAssets: options.sourceAssets || [options.fromToken
|
|
1419
|
+
// Use canonical symbol casing from registry (e.g. "MockUSD" not "MOCKUSD")
|
|
1420
|
+
sourceAssets: options.sourceAssets || (options.fromToken ? [options.fromToken] : void 0),
|
|
1421
|
+
// Pass source chain ID so orchestrator knows which chain to look for tokens on
|
|
1422
|
+
sourceChainId: options.sourceChainId,
|
|
978
1423
|
closeOn: options.closeOn || "preconfirmed",
|
|
979
1424
|
waitForHash: options.waitForHash,
|
|
980
1425
|
hashTimeoutMs: options.hashTimeoutMs,
|
|
@@ -983,7 +1428,7 @@ var OneAuthClient = class {
|
|
|
983
1428
|
return {
|
|
984
1429
|
...result,
|
|
985
1430
|
quote: result.success ? {
|
|
986
|
-
fromToken: fromTokenAddress,
|
|
1431
|
+
fromToken: fromTokenAddress ?? options.fromToken,
|
|
987
1432
|
toToken: toTokenAddress,
|
|
988
1433
|
amountIn: options.amount,
|
|
989
1434
|
amountOut: "",
|
|
@@ -1025,26 +1470,23 @@ var OneAuthClient = class {
|
|
|
1025
1470
|
const themeParams = this.getThemeParams(options?.theme);
|
|
1026
1471
|
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
1027
1472
|
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
1028
|
-
const
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
}, dialogOrigin);
|
|
1043
|
-
resolve();
|
|
1473
|
+
const ready = await this.waitForDialogReady(dialog, iframe, cleanup, {
|
|
1474
|
+
mode: "iframe",
|
|
1475
|
+
message: options.message,
|
|
1476
|
+
challenge: options.challenge || options.message,
|
|
1477
|
+
username: options.username,
|
|
1478
|
+
description: options.description,
|
|
1479
|
+
metadata: options.metadata
|
|
1480
|
+
});
|
|
1481
|
+
if (!ready) {
|
|
1482
|
+
return {
|
|
1483
|
+
success: false,
|
|
1484
|
+
error: {
|
|
1485
|
+
code: "USER_REJECTED",
|
|
1486
|
+
message: "User closed the dialog"
|
|
1044
1487
|
}
|
|
1045
1488
|
};
|
|
1046
|
-
|
|
1047
|
-
});
|
|
1489
|
+
}
|
|
1048
1490
|
const signingResult = await this.waitForSigningResponse(dialog, iframe, cleanup);
|
|
1049
1491
|
cleanup();
|
|
1050
1492
|
if (signingResult.success) {
|
|
@@ -1113,31 +1555,28 @@ var OneAuthClient = class {
|
|
|
1113
1555
|
const themeParams = this.getThemeParams(options?.theme);
|
|
1114
1556
|
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
1115
1557
|
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
1116
|
-
const
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
}, dialogOrigin);
|
|
1136
|
-
resolve();
|
|
1558
|
+
const ready = await this.waitForDialogReady(dialog, iframe, cleanup, {
|
|
1559
|
+
mode: "iframe",
|
|
1560
|
+
signingMode: "typedData",
|
|
1561
|
+
typedData: {
|
|
1562
|
+
domain: options.domain,
|
|
1563
|
+
types: options.types,
|
|
1564
|
+
primaryType: options.primaryType,
|
|
1565
|
+
message: options.message
|
|
1566
|
+
},
|
|
1567
|
+
challenge: signedHash,
|
|
1568
|
+
username: options.username,
|
|
1569
|
+
description: options.description
|
|
1570
|
+
});
|
|
1571
|
+
if (!ready) {
|
|
1572
|
+
return {
|
|
1573
|
+
success: false,
|
|
1574
|
+
error: {
|
|
1575
|
+
code: "USER_REJECTED",
|
|
1576
|
+
message: "User closed the dialog"
|
|
1137
1577
|
}
|
|
1138
1578
|
};
|
|
1139
|
-
|
|
1140
|
-
});
|
|
1579
|
+
}
|
|
1141
1580
|
const signingResult = await this.waitForSigningResponse(dialog, iframe, cleanup);
|
|
1142
1581
|
cleanup();
|
|
1143
1582
|
if (signingResult.success) {
|
|
@@ -1291,9 +1730,7 @@ var OneAuthClient = class {
|
|
|
1291
1730
|
const response = await fetch(
|
|
1292
1731
|
`${this.config.providerUrl}/api/users/${encodeURIComponent(username)}/passkeys`,
|
|
1293
1732
|
{
|
|
1294
|
-
headers: {
|
|
1295
|
-
"x-client-id": this.config.clientId
|
|
1296
|
-
}
|
|
1733
|
+
headers: this.config.clientId ? { "x-client-id": this.config.clientId } : {}
|
|
1297
1734
|
}
|
|
1298
1735
|
);
|
|
1299
1736
|
if (!response.ok) {
|
|
@@ -1312,7 +1749,7 @@ var OneAuthClient = class {
|
|
|
1312
1749
|
"Content-Type": "application/json"
|
|
1313
1750
|
},
|
|
1314
1751
|
body: JSON.stringify({
|
|
1315
|
-
clientId: this.config.clientId,
|
|
1752
|
+
...this.config.clientId && { clientId: this.config.clientId },
|
|
1316
1753
|
username: options.username,
|
|
1317
1754
|
challenge: options.challenge,
|
|
1318
1755
|
description: options.description,
|
|
@@ -1338,6 +1775,44 @@ var OneAuthClient = class {
|
|
|
1338
1775
|
`width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},popup=true`
|
|
1339
1776
|
);
|
|
1340
1777
|
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Wait for the dialog iframe to signal ready, then send init data.
|
|
1780
|
+
* Also handles early close (X button, escape, backdrop) during the ready phase.
|
|
1781
|
+
* Returns true if dialog is ready, false if it was closed before becoming ready.
|
|
1782
|
+
*/
|
|
1783
|
+
waitForDialogReady(dialog, iframe, cleanup, initMessage) {
|
|
1784
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
1785
|
+
return new Promise((resolve) => {
|
|
1786
|
+
let settled = false;
|
|
1787
|
+
const teardown = () => {
|
|
1788
|
+
if (settled) return;
|
|
1789
|
+
settled = true;
|
|
1790
|
+
window.removeEventListener("message", handleMessage);
|
|
1791
|
+
dialog.removeEventListener("close", handleClose);
|
|
1792
|
+
};
|
|
1793
|
+
const handleMessage = (event) => {
|
|
1794
|
+
if (event.origin !== dialogOrigin) return;
|
|
1795
|
+
if (event.data?.type === "PASSKEY_READY") {
|
|
1796
|
+
teardown();
|
|
1797
|
+
iframe.contentWindow?.postMessage({
|
|
1798
|
+
type: "PASSKEY_INIT",
|
|
1799
|
+
...initMessage
|
|
1800
|
+
}, dialogOrigin);
|
|
1801
|
+
resolve(true);
|
|
1802
|
+
} else if (event.data?.type === "PASSKEY_CLOSE") {
|
|
1803
|
+
teardown();
|
|
1804
|
+
cleanup();
|
|
1805
|
+
resolve(false);
|
|
1806
|
+
}
|
|
1807
|
+
};
|
|
1808
|
+
const handleClose = () => {
|
|
1809
|
+
teardown();
|
|
1810
|
+
resolve(false);
|
|
1811
|
+
};
|
|
1812
|
+
window.addEventListener("message", handleMessage);
|
|
1813
|
+
dialog.addEventListener("close", handleClose);
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1341
1816
|
/**
|
|
1342
1817
|
* Create a modal dialog with an iframe inside.
|
|
1343
1818
|
*/
|
|
@@ -1482,12 +1957,24 @@ var OneAuthClient = class {
|
|
|
1482
1957
|
};
|
|
1483
1958
|
return { dialog, iframe, cleanup };
|
|
1484
1959
|
}
|
|
1485
|
-
waitForModalAuthResponse(_dialog,
|
|
1960
|
+
waitForModalAuthResponse(_dialog, iframe, cleanup) {
|
|
1486
1961
|
const dialogOrigin = this.getDialogOrigin();
|
|
1487
1962
|
return new Promise((resolve) => {
|
|
1963
|
+
let dialogReady = false;
|
|
1488
1964
|
const handleMessage = (event) => {
|
|
1489
1965
|
if (event.origin !== dialogOrigin) return;
|
|
1490
1966
|
const data = event.data;
|
|
1967
|
+
if (data?.type === "PASSKEY_READY") {
|
|
1968
|
+
dialogReady = true;
|
|
1969
|
+
iframe.contentWindow?.postMessage({
|
|
1970
|
+
type: "PASSKEY_INIT",
|
|
1971
|
+
mode: "iframe"
|
|
1972
|
+
}, dialogOrigin);
|
|
1973
|
+
return;
|
|
1974
|
+
}
|
|
1975
|
+
if (!dialogReady && data?.type === "PASSKEY_CLOSE") {
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1491
1978
|
if (data?.type === "PASSKEY_LOGIN_RESULT") {
|
|
1492
1979
|
window.removeEventListener("message", handleMessage);
|
|
1493
1980
|
cleanup();
|
|
@@ -1517,6 +2004,11 @@ var OneAuthClient = class {
|
|
|
1517
2004
|
error: data.error
|
|
1518
2005
|
});
|
|
1519
2006
|
}
|
|
2007
|
+
} else if (data?.type === "PASSKEY_RETRY_POPUP") {
|
|
2008
|
+
window.removeEventListener("message", handleMessage);
|
|
2009
|
+
cleanup();
|
|
2010
|
+
const popupUrl = data.data?.url?.replace("mode=iframe", "mode=popup") || `${this.getDialogUrl()}/dialog/auth?mode=popup${this.config.clientId ? `&clientId=${this.config.clientId}` : ""}`;
|
|
2011
|
+
this.waitForPopupAuthResponse(popupUrl).then(resolve);
|
|
1520
2012
|
} else if (data?.type === "PASSKEY_CLOSE") {
|
|
1521
2013
|
window.removeEventListener("message", handleMessage);
|
|
1522
2014
|
cleanup();
|
|
@@ -1532,6 +2024,77 @@ var OneAuthClient = class {
|
|
|
1532
2024
|
window.addEventListener("message", handleMessage);
|
|
1533
2025
|
});
|
|
1534
2026
|
}
|
|
2027
|
+
/**
|
|
2028
|
+
* Open a popup for auth and wait for the result.
|
|
2029
|
+
* Used when iframe mode fails (e.g., due to password manager interference).
|
|
2030
|
+
*/
|
|
2031
|
+
waitForPopupAuthResponse(url) {
|
|
2032
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
2033
|
+
const popup = this.openPopup(url);
|
|
2034
|
+
return new Promise((resolve) => {
|
|
2035
|
+
const pollTimer = setInterval(() => {
|
|
2036
|
+
if (popup?.closed) {
|
|
2037
|
+
clearInterval(pollTimer);
|
|
2038
|
+
window.removeEventListener("message", handleMessage);
|
|
2039
|
+
resolve({
|
|
2040
|
+
success: false,
|
|
2041
|
+
error: {
|
|
2042
|
+
code: "USER_CANCELLED",
|
|
2043
|
+
message: "Authentication was cancelled"
|
|
2044
|
+
}
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
2047
|
+
}, 500);
|
|
2048
|
+
const handleMessage = (event) => {
|
|
2049
|
+
if (event.origin !== dialogOrigin) return;
|
|
2050
|
+
const data = event.data;
|
|
2051
|
+
if (data?.type === "PASSKEY_LOGIN_RESULT") {
|
|
2052
|
+
clearInterval(pollTimer);
|
|
2053
|
+
window.removeEventListener("message", handleMessage);
|
|
2054
|
+
popup?.close();
|
|
2055
|
+
if (data.success) {
|
|
2056
|
+
resolve({
|
|
2057
|
+
success: true,
|
|
2058
|
+
username: data.data?.username,
|
|
2059
|
+
user: data.data?.user
|
|
2060
|
+
});
|
|
2061
|
+
} else {
|
|
2062
|
+
resolve({
|
|
2063
|
+
success: false,
|
|
2064
|
+
error: data.error
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
} else if (data?.type === "PASSKEY_REGISTER_RESULT") {
|
|
2068
|
+
clearInterval(pollTimer);
|
|
2069
|
+
window.removeEventListener("message", handleMessage);
|
|
2070
|
+
popup?.close();
|
|
2071
|
+
if (data.success) {
|
|
2072
|
+
resolve({
|
|
2073
|
+
success: true,
|
|
2074
|
+
username: data.data?.username
|
|
2075
|
+
});
|
|
2076
|
+
} else {
|
|
2077
|
+
resolve({
|
|
2078
|
+
success: false,
|
|
2079
|
+
error: data.error
|
|
2080
|
+
});
|
|
2081
|
+
}
|
|
2082
|
+
} else if (data?.type === "PASSKEY_CLOSE") {
|
|
2083
|
+
clearInterval(pollTimer);
|
|
2084
|
+
window.removeEventListener("message", handleMessage);
|
|
2085
|
+
popup?.close();
|
|
2086
|
+
resolve({
|
|
2087
|
+
success: false,
|
|
2088
|
+
error: {
|
|
2089
|
+
code: "USER_CANCELLED",
|
|
2090
|
+
message: "Authentication was cancelled"
|
|
2091
|
+
}
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
};
|
|
2095
|
+
window.addEventListener("message", handleMessage);
|
|
2096
|
+
});
|
|
2097
|
+
}
|
|
1535
2098
|
waitForAuthenticateResponse(_dialog, _iframe, cleanup) {
|
|
1536
2099
|
const dialogOrigin = this.getDialogOrigin();
|
|
1537
2100
|
return new Promise((resolve) => {
|
|
@@ -1571,6 +2134,44 @@ var OneAuthClient = class {
|
|
|
1571
2134
|
window.addEventListener("message", handleMessage);
|
|
1572
2135
|
});
|
|
1573
2136
|
}
|
|
2137
|
+
waitForConnectResponse(_dialog, _iframe, cleanup) {
|
|
2138
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
2139
|
+
return new Promise((resolve) => {
|
|
2140
|
+
const handleMessage = (event) => {
|
|
2141
|
+
if (event.origin !== dialogOrigin) return;
|
|
2142
|
+
const data = event.data;
|
|
2143
|
+
if (data?.type === "PASSKEY_CONNECT_RESULT") {
|
|
2144
|
+
window.removeEventListener("message", handleMessage);
|
|
2145
|
+
cleanup();
|
|
2146
|
+
if (data.success) {
|
|
2147
|
+
resolve({
|
|
2148
|
+
success: true,
|
|
2149
|
+
username: data.data?.username,
|
|
2150
|
+
autoConnected: data.data?.autoConnected
|
|
2151
|
+
});
|
|
2152
|
+
} else {
|
|
2153
|
+
resolve({
|
|
2154
|
+
success: false,
|
|
2155
|
+
action: data.data?.action,
|
|
2156
|
+
error: data.error
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
} else if (data?.type === "PASSKEY_CLOSE") {
|
|
2160
|
+
window.removeEventListener("message", handleMessage);
|
|
2161
|
+
cleanup();
|
|
2162
|
+
resolve({
|
|
2163
|
+
success: false,
|
|
2164
|
+
action: "cancel",
|
|
2165
|
+
error: {
|
|
2166
|
+
code: "USER_CANCELLED",
|
|
2167
|
+
message: "Connection was cancelled"
|
|
2168
|
+
}
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
};
|
|
2172
|
+
window.addEventListener("message", handleMessage);
|
|
2173
|
+
});
|
|
2174
|
+
}
|
|
1574
2175
|
waitForModalSigningResponse(requestId, _dialog, _iframe, cleanup) {
|
|
1575
2176
|
const dialogOrigin = this.getDialogOrigin();
|
|
1576
2177
|
return new Promise((resolve) => {
|
|
@@ -1659,9 +2260,7 @@ var OneAuthClient = class {
|
|
|
1659
2260
|
const response = await fetch(
|
|
1660
2261
|
`${this.config.providerUrl}/api/sign/request/${requestId}`,
|
|
1661
2262
|
{
|
|
1662
|
-
headers: {
|
|
1663
|
-
"x-client-id": this.config.clientId
|
|
1664
|
-
}
|
|
2263
|
+
headers: this.config.clientId ? { "x-client-id": this.config.clientId } : {}
|
|
1665
2264
|
}
|
|
1666
2265
|
);
|
|
1667
2266
|
if (!response.ok) {
|
|
@@ -1765,7 +2364,7 @@ function buildTransactionReview(calls) {
|
|
|
1765
2364
|
|
|
1766
2365
|
// src/provider.ts
|
|
1767
2366
|
var DEFAULT_STORAGE_KEY = "1auth-user";
|
|
1768
|
-
function
|
|
2367
|
+
function createOneAuthProvider(options) {
|
|
1769
2368
|
const { client } = options;
|
|
1770
2369
|
let chainId = options.chainId;
|
|
1771
2370
|
const storageKey = options.storageKey || DEFAULT_STORAGE_KEY;
|
|
@@ -1796,12 +2395,11 @@ function createPasskeyProvider(options) {
|
|
|
1796
2395
|
localStorage.removeItem(storageKey);
|
|
1797
2396
|
};
|
|
1798
2397
|
const resolveAccountAddress = async (username) => {
|
|
2398
|
+
const clientId = client.getClientId();
|
|
1799
2399
|
const response = await fetch(
|
|
1800
2400
|
`${client.getProviderUrl()}/api/users/${encodeURIComponent(username)}/account`,
|
|
1801
2401
|
{
|
|
1802
|
-
headers: {
|
|
1803
|
-
"x-client-id": client.getClientId()
|
|
1804
|
-
}
|
|
2402
|
+
headers: clientId ? { "x-client-id": clientId } : {}
|
|
1805
2403
|
}
|
|
1806
2404
|
);
|
|
1807
2405
|
if (!response.ok) {
|
|
@@ -1816,12 +2414,21 @@ function createPasskeyProvider(options) {
|
|
|
1816
2414
|
if (stored) {
|
|
1817
2415
|
return [stored.address];
|
|
1818
2416
|
}
|
|
1819
|
-
const
|
|
1820
|
-
|
|
1821
|
-
|
|
2417
|
+
const connectResult = await client.connectWithModal();
|
|
2418
|
+
let username;
|
|
2419
|
+
if (connectResult.success && connectResult.username) {
|
|
2420
|
+
username = connectResult.username;
|
|
2421
|
+
} else if (connectResult.action === "switch") {
|
|
2422
|
+
const authResult = await client.authWithModal();
|
|
2423
|
+
if (!authResult.success || !authResult.username) {
|
|
2424
|
+
throw new Error(authResult.error?.message || "Authentication failed");
|
|
2425
|
+
}
|
|
2426
|
+
username = authResult.username;
|
|
2427
|
+
} else {
|
|
2428
|
+
throw new Error(connectResult.error?.message || "Connection cancelled");
|
|
1822
2429
|
}
|
|
1823
|
-
const address = await resolveAccountAddress(
|
|
1824
|
-
setStoredUser({ username
|
|
2430
|
+
const address = await resolveAccountAddress(username);
|
|
2431
|
+
setStoredUser({ username, address });
|
|
1825
2432
|
emit("accountsChanged", [address]);
|
|
1826
2433
|
emit("connect", { chainId: (0, import_viem4.numberToHex)(chainId) });
|
|
1827
2434
|
return [address];
|
|
@@ -1878,6 +2485,16 @@ function createPasskeyProvider(options) {
|
|
|
1878
2485
|
};
|
|
1879
2486
|
});
|
|
1880
2487
|
};
|
|
2488
|
+
const normalizeTokenRequests = (requests) => {
|
|
2489
|
+
if (!Array.isArray(requests)) return void 0;
|
|
2490
|
+
return requests.map((r) => {
|
|
2491
|
+
const req = r;
|
|
2492
|
+
return {
|
|
2493
|
+
token: req.token,
|
|
2494
|
+
amount: typeof req.amount === "bigint" ? req.amount : BigInt(String(req.amount || "0"))
|
|
2495
|
+
};
|
|
2496
|
+
});
|
|
2497
|
+
};
|
|
1881
2498
|
const decodeMessage = (value) => {
|
|
1882
2499
|
if (!(0, import_viem4.isHex)(value)) return value;
|
|
1883
2500
|
try {
|
|
@@ -1917,31 +2534,35 @@ function createPasskeyProvider(options) {
|
|
|
1917
2534
|
return {
|
|
1918
2535
|
username: payload.username,
|
|
1919
2536
|
targetChain: payload.targetChain,
|
|
1920
|
-
calls: payload.calls
|
|
2537
|
+
calls: payload.calls,
|
|
2538
|
+
tokenRequests: payload.tokenRequests
|
|
1921
2539
|
};
|
|
1922
2540
|
}
|
|
1923
2541
|
const signedIntent = await options.signIntent({
|
|
1924
2542
|
username: payload.username,
|
|
1925
2543
|
accountAddress: payload.accountAddress,
|
|
1926
2544
|
targetChain: payload.targetChain,
|
|
1927
|
-
calls: payload.calls
|
|
2545
|
+
calls: payload.calls,
|
|
2546
|
+
tokenRequests: payload.tokenRequests
|
|
1928
2547
|
});
|
|
1929
2548
|
return { signedIntent };
|
|
1930
2549
|
};
|
|
1931
2550
|
const sendIntent = async (payload) => {
|
|
1932
|
-
const closeOn = options.waitForHash ?? true ? "completed" : "preconfirmed";
|
|
2551
|
+
const closeOn = options.closeOn ?? (options.waitForHash ?? true ? "completed" : "preconfirmed");
|
|
1933
2552
|
const intentPayload = await resolveIntentPayload(payload);
|
|
1934
2553
|
const result = await client.sendIntent({
|
|
1935
2554
|
...intentPayload,
|
|
2555
|
+
tokenRequests: payload.tokenRequests,
|
|
2556
|
+
sourceChainId: payload.sourceChainId,
|
|
1936
2557
|
closeOn,
|
|
1937
2558
|
waitForHash: options.waitForHash ?? true,
|
|
1938
2559
|
hashTimeoutMs: options.hashTimeoutMs,
|
|
1939
2560
|
hashIntervalMs: options.hashIntervalMs
|
|
1940
2561
|
});
|
|
1941
|
-
if (!result.success
|
|
2562
|
+
if (!result.success) {
|
|
1942
2563
|
throw new Error(result.error?.message || "Transaction failed");
|
|
1943
2564
|
}
|
|
1944
|
-
return result.
|
|
2565
|
+
return result.intentId;
|
|
1945
2566
|
};
|
|
1946
2567
|
const request = async ({ method, params }) => {
|
|
1947
2568
|
switch (method) {
|
|
@@ -1994,11 +2615,15 @@ function createPasskeyProvider(options) {
|
|
|
1994
2615
|
const user = await ensureUser();
|
|
1995
2616
|
const targetChain = parseChainId(tx.chainId) ?? chainId;
|
|
1996
2617
|
const calls = normalizeCalls([tx]);
|
|
2618
|
+
const tokenRequests = normalizeTokenRequests(tx.tokenRequests);
|
|
2619
|
+
const txSourceChainId = parseChainId(tx.sourceChainId);
|
|
1997
2620
|
return sendIntent({
|
|
1998
2621
|
username: user.username,
|
|
1999
2622
|
accountAddress: user.address,
|
|
2000
2623
|
targetChain,
|
|
2001
|
-
calls
|
|
2624
|
+
calls,
|
|
2625
|
+
tokenRequests,
|
|
2626
|
+
sourceChainId: txSourceChainId
|
|
2002
2627
|
});
|
|
2003
2628
|
}
|
|
2004
2629
|
case "wallet_sendCalls": {
|
|
@@ -2007,22 +2632,128 @@ function createPasskeyProvider(options) {
|
|
|
2007
2632
|
const user = await ensureUser();
|
|
2008
2633
|
const targetChain = parseChainId(payload.chainId) ?? chainId;
|
|
2009
2634
|
const calls = normalizeCalls(payload.calls || []);
|
|
2635
|
+
const tokenRequests = normalizeTokenRequests(payload.tokenRequests);
|
|
2636
|
+
const sourceChainId = parseChainId(payload.sourceChainId);
|
|
2010
2637
|
if (!calls.length) throw new Error("No calls provided");
|
|
2011
2638
|
return sendIntent({
|
|
2012
2639
|
username: user.username,
|
|
2013
2640
|
accountAddress: user.address,
|
|
2014
2641
|
targetChain,
|
|
2015
|
-
calls
|
|
2642
|
+
calls,
|
|
2643
|
+
tokenRequests,
|
|
2644
|
+
sourceChainId
|
|
2016
2645
|
});
|
|
2017
2646
|
}
|
|
2018
2647
|
case "wallet_getCapabilities": {
|
|
2648
|
+
const paramList = Array.isArray(params) ? params : [];
|
|
2649
|
+
const requestedChains = paramList[1];
|
|
2019
2650
|
const chainIds = getSupportedChainIds();
|
|
2020
|
-
const
|
|
2021
|
-
|
|
2651
|
+
const capabilities = {};
|
|
2652
|
+
for (const chainId2 of chainIds) {
|
|
2653
|
+
const hexChainId = `0x${chainId2.toString(16)}`;
|
|
2654
|
+
if (requestedChains && !requestedChains.includes(hexChainId)) {
|
|
2655
|
+
continue;
|
|
2656
|
+
}
|
|
2657
|
+
capabilities[hexChainId] = {
|
|
2658
|
+
atomic: { status: "supported" },
|
|
2659
|
+
paymasterService: { supported: true },
|
|
2660
|
+
auxiliaryFunds: { supported: true }
|
|
2661
|
+
};
|
|
2662
|
+
}
|
|
2663
|
+
return capabilities;
|
|
2664
|
+
}
|
|
2665
|
+
case "wallet_getAssets": {
|
|
2666
|
+
const { username } = await ensureUser();
|
|
2667
|
+
const clientId = client.getClientId();
|
|
2668
|
+
const response = await fetch(
|
|
2669
|
+
`${client.getProviderUrl()}/api/users/${encodeURIComponent(username)}/portfolio`,
|
|
2670
|
+
{
|
|
2671
|
+
headers: clientId ? { "x-client-id": clientId } : {}
|
|
2672
|
+
}
|
|
2673
|
+
);
|
|
2674
|
+
if (!response.ok) {
|
|
2675
|
+
const data = await response.json().catch(() => ({}));
|
|
2676
|
+
throw new Error(data.error || "Failed to get assets");
|
|
2677
|
+
}
|
|
2678
|
+
return response.json();
|
|
2679
|
+
}
|
|
2680
|
+
case "wallet_getCallsStatus": {
|
|
2681
|
+
const paramList = Array.isArray(params) ? params : [];
|
|
2682
|
+
const callsId = paramList[0];
|
|
2683
|
+
if (!callsId) {
|
|
2684
|
+
throw new Error("callsId is required");
|
|
2685
|
+
}
|
|
2686
|
+
const statusClientId = client.getClientId();
|
|
2687
|
+
const response = await fetch(
|
|
2688
|
+
`${client.getProviderUrl()}/api/intent/status/${encodeURIComponent(callsId)}`,
|
|
2689
|
+
{
|
|
2690
|
+
headers: statusClientId ? { "x-client-id": statusClientId } : {}
|
|
2691
|
+
}
|
|
2022
2692
|
);
|
|
2693
|
+
if (!response.ok) {
|
|
2694
|
+
const data2 = await response.json().catch(() => ({}));
|
|
2695
|
+
throw new Error(data2.error || "Failed to get calls status");
|
|
2696
|
+
}
|
|
2697
|
+
const data = await response.json();
|
|
2698
|
+
const statusMap = {
|
|
2699
|
+
pending: "PENDING",
|
|
2700
|
+
preconfirmed: "PENDING",
|
|
2701
|
+
completed: "CONFIRMED",
|
|
2702
|
+
failed: "CONFIRMED",
|
|
2703
|
+
expired: "CONFIRMED"
|
|
2704
|
+
};
|
|
2023
2705
|
return {
|
|
2024
|
-
|
|
2025
|
-
|
|
2706
|
+
status: statusMap[data.status] || "PENDING",
|
|
2707
|
+
receipts: data.transactionHash ? [
|
|
2708
|
+
{
|
|
2709
|
+
logs: [],
|
|
2710
|
+
status: data.status === "completed" ? "0x1" : "0x0",
|
|
2711
|
+
blockHash: data.blockHash,
|
|
2712
|
+
blockNumber: data.blockNumber,
|
|
2713
|
+
transactionHash: data.transactionHash
|
|
2714
|
+
}
|
|
2715
|
+
] : []
|
|
2716
|
+
};
|
|
2717
|
+
}
|
|
2718
|
+
case "wallet_getCallsHistory": {
|
|
2719
|
+
const paramList = Array.isArray(params) ? params : [];
|
|
2720
|
+
const options2 = paramList[0] || {};
|
|
2721
|
+
const queryParams = new URLSearchParams();
|
|
2722
|
+
if (options2.limit) queryParams.set("limit", String(options2.limit));
|
|
2723
|
+
if (options2.offset) queryParams.set("offset", String(options2.offset));
|
|
2724
|
+
if (options2.status) queryParams.set("status", options2.status);
|
|
2725
|
+
if (options2.from) queryParams.set("from", options2.from);
|
|
2726
|
+
if (options2.to) queryParams.set("to", options2.to);
|
|
2727
|
+
const url = `${client.getProviderUrl()}/api/intent/history${queryParams.toString() ? `?${queryParams}` : ""}`;
|
|
2728
|
+
const historyClientId = client.getClientId();
|
|
2729
|
+
const response = await fetch(url, {
|
|
2730
|
+
headers: historyClientId ? { "x-client-id": historyClientId } : {},
|
|
2731
|
+
credentials: "include"
|
|
2732
|
+
});
|
|
2733
|
+
if (!response.ok) {
|
|
2734
|
+
const data2 = await response.json().catch(() => ({}));
|
|
2735
|
+
throw new Error(data2.error || "Failed to get calls history");
|
|
2736
|
+
}
|
|
2737
|
+
const data = await response.json();
|
|
2738
|
+
const statusMap = {
|
|
2739
|
+
pending: "PENDING",
|
|
2740
|
+
preconfirmed: "PENDING",
|
|
2741
|
+
completed: "CONFIRMED",
|
|
2742
|
+
failed: "CONFIRMED",
|
|
2743
|
+
expired: "CONFIRMED"
|
|
2744
|
+
};
|
|
2745
|
+
return {
|
|
2746
|
+
calls: data.intents.map(
|
|
2747
|
+
(intent) => ({
|
|
2748
|
+
callsId: intent.intentId,
|
|
2749
|
+
// intentId is the orchestrator's ID
|
|
2750
|
+
status: statusMap[intent.status] || "PENDING",
|
|
2751
|
+
receipts: intent.transactionHash ? [{ transactionHash: intent.transactionHash }] : [],
|
|
2752
|
+
chainId: `0x${intent.targetChain.toString(16)}`
|
|
2753
|
+
})
|
|
2754
|
+
),
|
|
2755
|
+
total: data.total,
|
|
2756
|
+
hasMore: data.hasMore
|
|
2026
2757
|
};
|
|
2027
2758
|
}
|
|
2028
2759
|
default:
|
|
@@ -2045,6 +2776,7 @@ function createPasskeyProvider(options) {
|
|
|
2045
2776
|
disconnect
|
|
2046
2777
|
};
|
|
2047
2778
|
}
|
|
2779
|
+
var createPasskeyProvider = createOneAuthProvider;
|
|
2048
2780
|
|
|
2049
2781
|
// src/account.ts
|
|
2050
2782
|
var import_viem5 = require("viem");
|
|
@@ -2147,6 +2879,9 @@ function createPasskeyWalletClient(config) {
|
|
|
2147
2879
|
if (!result.success) {
|
|
2148
2880
|
throw new Error(result.error?.message || "Signing failed");
|
|
2149
2881
|
}
|
|
2882
|
+
if (!result.signature) {
|
|
2883
|
+
throw new Error("No signature received");
|
|
2884
|
+
}
|
|
2150
2885
|
return encodeWebAuthnSignature(result.signature);
|
|
2151
2886
|
};
|
|
2152
2887
|
const signTransactionImpl = async (transaction) => {
|
|
@@ -2167,6 +2902,9 @@ function createPasskeyWalletClient(config) {
|
|
|
2167
2902
|
if (!result.success) {
|
|
2168
2903
|
throw new Error(result.error?.message || "Signing failed");
|
|
2169
2904
|
}
|
|
2905
|
+
if (!result.signature) {
|
|
2906
|
+
throw new Error("No signature received");
|
|
2907
|
+
}
|
|
2170
2908
|
return encodeWebAuthnSignature(result.signature);
|
|
2171
2909
|
};
|
|
2172
2910
|
const signTypedDataImpl = async (typedData) => {
|
|
@@ -2188,6 +2926,9 @@ function createPasskeyWalletClient(config) {
|
|
|
2188
2926
|
if (!result.success) {
|
|
2189
2927
|
throw new Error(result.error?.message || "Signing failed");
|
|
2190
2928
|
}
|
|
2929
|
+
if (!result.signature) {
|
|
2930
|
+
throw new Error("No signature received");
|
|
2931
|
+
}
|
|
2191
2932
|
return encodeWebAuthnSignature(result.signature);
|
|
2192
2933
|
};
|
|
2193
2934
|
const buildIntentPayload = async (calls, targetChainOverride) => {
|
|
@@ -2256,11 +2997,12 @@ function createPasskeyWalletClient(config) {
|
|
|
2256
2997
|
* Send multiple calls as a single batched transaction
|
|
2257
2998
|
*/
|
|
2258
2999
|
async sendCalls(params) {
|
|
2259
|
-
const { calls, chainId: targetChain } = params;
|
|
3000
|
+
const { calls, chainId: targetChain, tokenRequests } = params;
|
|
2260
3001
|
const closeOn = config.waitForHash ?? true ? "completed" : "preconfirmed";
|
|
2261
3002
|
const intentPayload = await buildIntentPayload(calls, targetChain);
|
|
2262
3003
|
const result = await provider.sendIntent({
|
|
2263
3004
|
...intentPayload,
|
|
3005
|
+
tokenRequests,
|
|
2264
3006
|
closeOn,
|
|
2265
3007
|
waitForHash: config.waitForHash ?? true,
|
|
2266
3008
|
hashTimeoutMs: config.hashTimeoutMs,
|
|
@@ -2704,9 +3446,10 @@ function BatchQueueWidget({ onSignAll }) {
|
|
|
2704
3446
|
|
|
2705
3447
|
// src/verify.ts
|
|
2706
3448
|
var import_viem7 = require("viem");
|
|
2707
|
-
var
|
|
3449
|
+
var ETHEREUM_MESSAGE_PREFIX = "Ethereum Signed Message:\n";
|
|
3450
|
+
var PASSKEY_MESSAGE_PREFIX = ETHEREUM_MESSAGE_PREFIX;
|
|
2708
3451
|
function hashMessage2(message) {
|
|
2709
|
-
const prefixed =
|
|
3452
|
+
const prefixed = ETHEREUM_MESSAGE_PREFIX + message.length.toString() + message;
|
|
2710
3453
|
return (0, import_viem7.keccak256)((0, import_viem7.toBytes)(prefixed));
|
|
2711
3454
|
}
|
|
2712
3455
|
function verifyMessageHash(message, signedHash) {
|
|
@@ -2718,9 +3461,11 @@ function verifyMessageHash(message, signedHash) {
|
|
|
2718
3461
|
0 && (module.exports = {
|
|
2719
3462
|
BatchQueueProvider,
|
|
2720
3463
|
BatchQueueWidget,
|
|
3464
|
+
ETHEREUM_MESSAGE_PREFIX,
|
|
2721
3465
|
OneAuthClient,
|
|
2722
3466
|
PASSKEY_MESSAGE_PREFIX,
|
|
2723
3467
|
PasskeyProviderClient,
|
|
3468
|
+
createOneAuthProvider,
|
|
2724
3469
|
createPasskeyAccount,
|
|
2725
3470
|
createPasskeyProvider,
|
|
2726
3471
|
createPasskeyWalletClient,
|