@dynamic-labs-wallet/browser 0.0.47 → 0.0.49
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/index.cjs.js +467 -118
- package/index.esm.js +452 -102
- package/package.json +4 -3
- package/src/backup/encryption.d.ts.map +1 -1
- package/src/backup/providers/googleDrive.d.ts.map +1 -1
- package/src/client.d.ts +115 -18
- package/src/client.d.ts.map +1 -1
- package/src/constants.d.ts +0 -6
- package/src/constants.d.ts.map +1 -1
- package/src/services/iframeDisplay.d.ts +9 -0
- package/src/services/iframeDisplay.d.ts.map +1 -0
- package/src/services/iframeLocalStorage.d.ts +13 -0
- package/src/services/iframeLocalStorage.d.ts.map +1 -0
- package/src/services/messageTransportBridge.d.ts +3 -0
- package/src/services/messageTransportBridge.d.ts.map +1 -0
- package/src/types.d.ts +4 -52
- package/src/types.d.ts.map +1 -1
- package/src/utils.d.ts +1 -2
- package/src/utils.d.ts.map +1 -1
package/index.cjs.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var core = require('@dynamic-labs-wallet/core');
|
|
4
4
|
var web = require('./internal/web');
|
|
5
5
|
var logger$1 = require('@dynamic-labs/logger');
|
|
6
|
+
var messageTransport = require('@dynamic-labs/message-transport');
|
|
6
7
|
|
|
7
8
|
function _extends() {
|
|
8
9
|
_extends = Object.assign || function assign(target) {
|
|
@@ -184,7 +185,6 @@ const encryptData = async ({ data, password })=>{
|
|
|
184
185
|
cipher: bytesToBase64(new Uint8Array(encryptedData))
|
|
185
186
|
};
|
|
186
187
|
} catch (error) {
|
|
187
|
-
console.error('Error encrypting data:', error);
|
|
188
188
|
throw new Error('Error encrypting data');
|
|
189
189
|
}
|
|
190
190
|
};
|
|
@@ -208,7 +208,6 @@ const decryptData = async ({ data, password })=>{
|
|
|
208
208
|
}, key, cipherBytes);
|
|
209
209
|
return new TextDecoder().decode(decryptedData);
|
|
210
210
|
} catch (error) {
|
|
211
|
-
console.error('Decryption error details:', error);
|
|
212
211
|
throw new Error('Decryption failed');
|
|
213
212
|
}
|
|
214
213
|
};
|
|
@@ -305,7 +304,6 @@ const downloadFileFromGoogleDrive = async ({ accessToken, name })=>{
|
|
|
305
304
|
// The client will handle validation of the structure
|
|
306
305
|
return JSON.parse(fileRawData);
|
|
307
306
|
} catch (error) {
|
|
308
|
-
console.error('Error parsing backup file:', error);
|
|
309
307
|
return null;
|
|
310
308
|
}
|
|
311
309
|
};
|
|
@@ -379,17 +377,91 @@ const localStorageWriteTest = {
|
|
|
379
377
|
}
|
|
380
378
|
});
|
|
381
379
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
380
|
+
/**
|
|
381
|
+
* StorageRequestChannelAdapter.getItem() sends a message within host domain
|
|
382
|
+
* the bridge on host will capture this request and forwards it to the iframe via contentWindow.postMessage()
|
|
383
|
+
*/ class StorageRequestChannelAdapter {
|
|
384
|
+
async getItem(key) {
|
|
385
|
+
const item = await this.requestChannel.request('getItem', {
|
|
386
|
+
source: 'localStorage',
|
|
387
|
+
key
|
|
388
|
+
});
|
|
389
|
+
return item ? JSON.parse(item) : null;
|
|
390
|
+
}
|
|
391
|
+
async setItem(key, value) {
|
|
392
|
+
const stringifiedValue = typeof value === 'object' ? JSON.stringify(value) : value;
|
|
393
|
+
return this.requestChannel.request('setItem', {
|
|
394
|
+
source: 'localStorage',
|
|
395
|
+
key,
|
|
396
|
+
data: stringifiedValue
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
async removeItem(key) {
|
|
400
|
+
return this.requestChannel.request('deleteItem', {
|
|
401
|
+
source: 'localStorage',
|
|
402
|
+
key
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
constructor(messageTransport$1){
|
|
406
|
+
this.requestChannel = messageTransport.createRequestChannel(messageTransport$1);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const setupMessageTransportBridge = (messageTransport$1, iframe, iframeOrigin)=>{
|
|
411
|
+
if (!(iframe == null ? void 0 : iframe.contentWindow)) {
|
|
412
|
+
throw new Error('Iframe or contentWindow not available');
|
|
413
|
+
}
|
|
414
|
+
const logger = new logger$1.Logger('debug');
|
|
415
|
+
messageTransport$1.on((message)=>{
|
|
416
|
+
// Forward the message to webview via postMessage
|
|
417
|
+
if (message.origin === 'host') {
|
|
418
|
+
var _iframe_contentWindow;
|
|
419
|
+
logger.debug(`[host bridge] host --> bridge --> iframe`, message);
|
|
420
|
+
iframe == null ? void 0 : (_iframe_contentWindow = iframe.contentWindow) == null ? void 0 : _iframe_contentWindow.postMessage(message, iframeOrigin);
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
const handleIncomingMessage = (message)=>{
|
|
424
|
+
const { data } = message;
|
|
425
|
+
if (!data) return;
|
|
426
|
+
if ((data == null ? void 0 : data.origin) !== 'webview') {
|
|
427
|
+
logger.debug(`skipped message: ${JSON.stringify(data)}: origin is not host`);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (typeof data !== 'object') {
|
|
431
|
+
logger.debug(`skipped message: ${JSON.stringify(data)}: data is not an object`);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
try {
|
|
435
|
+
const message = messageTransport.parseMessageTransportData(data);
|
|
436
|
+
logger.debug(`[host bridge] iframe --> bridge --> host`, message);
|
|
437
|
+
messageTransport$1.emit(message);
|
|
438
|
+
} catch (error) {
|
|
439
|
+
if (!(error instanceof SyntaxError)) {
|
|
440
|
+
logger.error('Error handling incoming message:', error);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
/**
|
|
445
|
+
* Handle incoming message from android client
|
|
446
|
+
*/ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
447
|
+
// @ts-ignore
|
|
448
|
+
document.addEventListener('message', handleIncomingMessage);
|
|
449
|
+
/**
|
|
450
|
+
* Handle incoming message from iOS client
|
|
451
|
+
*/ window.addEventListener('message', handleIncomingMessage);
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
class IframeDisplayChannelAdapter {
|
|
455
|
+
async displayClientShares(accountAddress) {
|
|
456
|
+
await this.requestChannel.request('displayClientShares', accountAddress);
|
|
457
|
+
}
|
|
458
|
+
async displayPrivateKey(accountAddress, privateKey) {
|
|
459
|
+
await this.requestChannel.request('displayPrivateKey', accountAddress, privateKey);
|
|
460
|
+
}
|
|
461
|
+
constructor(messageTransport$1){
|
|
462
|
+
this.requestChannel = messageTransport.createRequestChannel(messageTransport$1);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
393
465
|
|
|
394
466
|
class DynamicWalletClient {
|
|
395
467
|
async initialize() {
|
|
@@ -403,11 +475,196 @@ class DynamicWalletClient {
|
|
|
403
475
|
return result;
|
|
404
476
|
}
|
|
405
477
|
/**
|
|
478
|
+
* Initializes the iframe display for a specific container.
|
|
479
|
+
*
|
|
480
|
+
* @param {HTMLElement} container - The container to which the iframe will be attached.
|
|
481
|
+
* @returns {Promise<{
|
|
482
|
+
* iframe: HTMLIFrameElement;
|
|
483
|
+
* iframeDisplay: IframeDisplayChannelAdapter;
|
|
484
|
+
* cleanup: () => void;
|
|
485
|
+
* }>} A promise that resolves when the iframe is loaded.
|
|
486
|
+
*/ async initializeIframeDisplayForContainer({ container }) {
|
|
487
|
+
try {
|
|
488
|
+
const iframe = await this.loadIframeForContainer(container);
|
|
489
|
+
const transport = messageTransport.applyDefaultMessageOrigin({
|
|
490
|
+
defaultOrigin: 'host',
|
|
491
|
+
messageTransport: messageTransport.createMessageTransport()
|
|
492
|
+
});
|
|
493
|
+
setupMessageTransportBridge(transport, iframe, this.iframeDomain);
|
|
494
|
+
const iframeDisplay = new IframeDisplayChannelAdapter(transport);
|
|
495
|
+
return {
|
|
496
|
+
iframe,
|
|
497
|
+
iframeDisplay,
|
|
498
|
+
cleanup: ()=>{
|
|
499
|
+
container.removeChild(iframe);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
} catch (error) {
|
|
503
|
+
this.logger.error('Error initializing iframe:', error);
|
|
504
|
+
throw error;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* this is called on class construction time
|
|
509
|
+
* @returns {Promise<void>} that resolves when the iframe is loaded and the message transport and iframe storage are initialized
|
|
510
|
+
*/ initializeIframeCommunication() {
|
|
511
|
+
if (!this.iframeLoadPromise) {
|
|
512
|
+
this.iframeLoadPromise = this.doInitializeIframeCommunication();
|
|
513
|
+
}
|
|
514
|
+
return this.iframeLoadPromise;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* initialize the iframe communication by awaiting the iframe load promise
|
|
518
|
+
* and initializing the message transport and iframe storage after iframe is successfully loaded
|
|
519
|
+
*/ async doInitializeIframeCommunication() {
|
|
520
|
+
try {
|
|
521
|
+
await this.loadIframe();
|
|
522
|
+
this.initializeMessageTransport();
|
|
523
|
+
this.initializeIframeStorage();
|
|
524
|
+
} catch (error) {
|
|
525
|
+
this.logger.error('Error initializing iframe:', error);
|
|
526
|
+
throw error;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* create a promise to load an iframe
|
|
531
|
+
* @returns {Promise<void>} that resolves when the iframe is loaded
|
|
532
|
+
*/ loadIframe() {
|
|
533
|
+
return new Promise((resolve, reject)=>{
|
|
534
|
+
const iframe = document.createElement('iframe');
|
|
535
|
+
const iframeTimeoutId = setTimeout(()=>{
|
|
536
|
+
reject(new Error('Iframe load timeout'));
|
|
537
|
+
}, 10000);
|
|
538
|
+
iframe.style.display = 'none';
|
|
539
|
+
iframe.setAttribute('title', 'Dynamic Wallet Iframe');
|
|
540
|
+
iframe.style.position = 'fixed';
|
|
541
|
+
iframe.style.top = '0';
|
|
542
|
+
iframe.style.left = '0';
|
|
543
|
+
iframe.style.width = '0';
|
|
544
|
+
iframe.style.height = '0';
|
|
545
|
+
iframe.style.border = 'none';
|
|
546
|
+
iframe.style.pointerEvents = 'none';
|
|
547
|
+
const params = new URLSearchParams({
|
|
548
|
+
instanceId: this.instanceId,
|
|
549
|
+
hostOrigin: window.location.origin
|
|
550
|
+
});
|
|
551
|
+
iframe.src = `${this.iframeDomain}/waas/${this.environmentId}?${params.toString()}`;
|
|
552
|
+
this.logger.debug('Creating iframe with src:', iframe.src);
|
|
553
|
+
document.body.appendChild(iframe);
|
|
554
|
+
iframe.onload = ()=>{
|
|
555
|
+
clearTimeout(iframeTimeoutId);
|
|
556
|
+
this.logger.debug('Iframe loaded successfully');
|
|
557
|
+
this.iframe = iframe;
|
|
558
|
+
resolve();
|
|
559
|
+
};
|
|
560
|
+
iframe.onerror = (error)=>{
|
|
561
|
+
clearTimeout(iframeTimeoutId);
|
|
562
|
+
this.logger.error('Iframe failed to load:', error);
|
|
563
|
+
reject(new Error('Failed to load iframe'));
|
|
564
|
+
};
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Load an iframe for a specific container
|
|
569
|
+
* @param {HTMLElement} container - The container to which the iframe will be attached
|
|
570
|
+
* @returns {Promise<HTMLIFrameElement>} that resolves when the iframe is loaded
|
|
571
|
+
*/ loadIframeForContainer(container) {
|
|
572
|
+
return new Promise((resolve, reject)=>{
|
|
573
|
+
const iframe = document.createElement('iframe');
|
|
574
|
+
const iframeTimeoutId = setTimeout(()=>{
|
|
575
|
+
reject(new Error('Iframe load timeout'));
|
|
576
|
+
}, 10000);
|
|
577
|
+
iframe.style.display = 'block';
|
|
578
|
+
iframe.style.width = '100%';
|
|
579
|
+
iframe.style.height = '100%';
|
|
580
|
+
iframe.setAttribute('title', 'Dynamic Wallet Storage');
|
|
581
|
+
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
582
|
+
const params = new URLSearchParams({
|
|
583
|
+
instanceId: this.instanceId,
|
|
584
|
+
hostOrigin: window.location.origin
|
|
585
|
+
});
|
|
586
|
+
iframe.src = `${this.iframeDomain}/waas/${this.environmentId}?${params.toString()}`;
|
|
587
|
+
this.logger.debug('Creating iframe with src:', iframe.src);
|
|
588
|
+
// Add iframe to the provided container
|
|
589
|
+
container.appendChild(iframe);
|
|
590
|
+
iframe.onload = ()=>{
|
|
591
|
+
clearTimeout(iframeTimeoutId);
|
|
592
|
+
this.logger.debug('Iframe loaded successfully');
|
|
593
|
+
this.iframe = iframe;
|
|
594
|
+
resolve(iframe);
|
|
595
|
+
};
|
|
596
|
+
iframe.onerror = (error)=>{
|
|
597
|
+
clearTimeout(iframeTimeoutId);
|
|
598
|
+
this.logger.error('Iframe failed to load:', error);
|
|
599
|
+
reject(new Error('Failed to load iframe'));
|
|
600
|
+
};
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* initialize the message transport after iframe is successfully loaded
|
|
605
|
+
*/ initializeMessageTransport() {
|
|
606
|
+
const transport = messageTransport.applyDefaultMessageOrigin({
|
|
607
|
+
defaultOrigin: 'host',
|
|
608
|
+
messageTransport: messageTransport.createMessageTransport()
|
|
609
|
+
});
|
|
610
|
+
this.messageTransport = transport;
|
|
611
|
+
if (!this.iframe) {
|
|
612
|
+
throw new Error('Iframe not available');
|
|
613
|
+
}
|
|
614
|
+
setupMessageTransportBridge(this.messageTransport, this.iframe, this.iframeDomain);
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* initialize the iframe storage after iframe is successfully loaded
|
|
618
|
+
*/ initializeIframeStorage() {
|
|
619
|
+
if (!this.messageTransport) {
|
|
620
|
+
throw new Error('Message transport not initialized');
|
|
621
|
+
}
|
|
622
|
+
this.iframeStorage = new StorageRequestChannelAdapter(this.messageTransport);
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Gets the initialized iframe instance. This method ensures the iframe is properly loaded and configured.
|
|
626
|
+
* The first call will initialize and await the iframe loading process.
|
|
627
|
+
* Subsequent calls will return the same iframe instance immediately.
|
|
628
|
+
*
|
|
629
|
+
* @throws {Error} If iframe initialization fails
|
|
630
|
+
* @throws {Error} If message transport initialization fails
|
|
631
|
+
* @throws {Error} If iframe storage initialization fails
|
|
632
|
+
* @returns {Promise<HTMLIFrameElement>} The initialized iframe element
|
|
633
|
+
*/ async getIframe() {
|
|
634
|
+
await this.initializeIframeCommunication();
|
|
635
|
+
if (!this.iframe) {
|
|
636
|
+
throw new Error('Failed to initialize iframe');
|
|
637
|
+
}
|
|
638
|
+
if (!this.messageTransport) {
|
|
639
|
+
throw new Error('Failed to initialize message transport');
|
|
640
|
+
}
|
|
641
|
+
if (!this.iframeStorage) {
|
|
642
|
+
throw new Error('Failed to initialize iframe storage');
|
|
643
|
+
}
|
|
644
|
+
return this.iframe;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Gets the initialized iframe storage instance. This method ensures the iframe storage is properly configured.
|
|
648
|
+
* The first call will initialize and await the iframe communication process.
|
|
649
|
+
* Subsequent calls will return the same storage instance immediately.
|
|
650
|
+
*
|
|
651
|
+
* @throws {Error} If iframe storage initialization fails
|
|
652
|
+
* @returns {Promise<SupportedStorage>} The initialized iframe storage instance
|
|
653
|
+
*/ async getIframeStorage() {
|
|
654
|
+
await this.initializeIframeCommunication();
|
|
655
|
+
if (!this.iframeStorage) {
|
|
656
|
+
throw new Error('Failed to initialize iframe storage');
|
|
657
|
+
}
|
|
658
|
+
return this.iframeStorage;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
406
661
|
* Client initialization logic
|
|
407
662
|
*/ async _initialize() {
|
|
408
663
|
try {
|
|
409
|
-
const initializePromises = [
|
|
410
|
-
|
|
664
|
+
const initializePromises = [
|
|
665
|
+
this.restoreWallets(),
|
|
666
|
+
this.useIframeStorage && this.initializeIframeCommunication()
|
|
667
|
+
];
|
|
411
668
|
await Promise.all(initializePromises);
|
|
412
669
|
return {
|
|
413
670
|
error: null
|
|
@@ -514,6 +771,52 @@ class DynamicWalletClient {
|
|
|
514
771
|
throw new Error('Error creating wallet account');
|
|
515
772
|
}
|
|
516
773
|
}
|
|
774
|
+
async importRawPrivateKey({ chainName, privateKey, thresholdSignatureScheme, onError, onCeremonyComplete }) {
|
|
775
|
+
const mpcSigner = getMPCSigner({
|
|
776
|
+
chainName,
|
|
777
|
+
baseRelayUrl: this.baseMPCRelayApiUrl
|
|
778
|
+
});
|
|
779
|
+
const clientKeygenInitResults = await this.clientInitializeKeyGen({
|
|
780
|
+
chainName,
|
|
781
|
+
thresholdSignatureScheme
|
|
782
|
+
});
|
|
783
|
+
const clientKeygenIds = clientKeygenInitResults.map((result)=>result.keygenId);
|
|
784
|
+
const { roomId, serverKeygenIds } = await this.apiClient.importPrivateKey({
|
|
785
|
+
chainName,
|
|
786
|
+
clientKeygenIds,
|
|
787
|
+
thresholdSignatureScheme,
|
|
788
|
+
onError,
|
|
789
|
+
onCeremonyComplete
|
|
790
|
+
});
|
|
791
|
+
const { threshold } = core.getTSSConfig(thresholdSignatureScheme);
|
|
792
|
+
const clientKeygenResults = await Promise.all(clientKeygenInitResults.map(async (currentInit, index)=>{
|
|
793
|
+
const otherClientKeygenIds = clientKeygenInitResults.filter((init)=>init.keygenId !== currentInit.keygenId).map((init)=>init.keygenId);
|
|
794
|
+
if (index === 0) {
|
|
795
|
+
const otherKeyGenIds = [
|
|
796
|
+
...serverKeygenIds,
|
|
797
|
+
...otherClientKeygenIds
|
|
798
|
+
];
|
|
799
|
+
const importerKeygenResult = await mpcSigner.importPrivateKeyImporter(roomId, threshold, privateKey, currentInit, otherKeyGenIds);
|
|
800
|
+
return importerKeygenResult;
|
|
801
|
+
} else {
|
|
802
|
+
const recipientKeygenResult = await mpcSigner.importPrivateKeyRecipient(roomId, threshold, currentInit, [
|
|
803
|
+
...serverKeygenIds,
|
|
804
|
+
...otherClientKeygenIds
|
|
805
|
+
]);
|
|
806
|
+
return recipientKeygenResult;
|
|
807
|
+
}
|
|
808
|
+
}));
|
|
809
|
+
const [clientKeygenResult] = clientKeygenResults;
|
|
810
|
+
const rawPublicKey = await this.derivePublicKey({
|
|
811
|
+
chainName,
|
|
812
|
+
keyShare: clientKeygenResult,
|
|
813
|
+
derivationPath: undefined
|
|
814
|
+
});
|
|
815
|
+
return {
|
|
816
|
+
rawPublicKey,
|
|
817
|
+
clientKeyShares: clientKeygenResults
|
|
818
|
+
};
|
|
819
|
+
}
|
|
517
820
|
async serverSign({ walletId, message }) {
|
|
518
821
|
// Create the room and sign the message
|
|
519
822
|
if (typeof message !== 'string') {
|
|
@@ -562,12 +865,12 @@ class DynamicWalletClient {
|
|
|
562
865
|
await this.verifyPassword({
|
|
563
866
|
accountAddress,
|
|
564
867
|
password,
|
|
565
|
-
walletOperation: WalletOperation.SIGN_MESSAGE
|
|
868
|
+
walletOperation: core.WalletOperation.SIGN_MESSAGE
|
|
566
869
|
});
|
|
567
870
|
const wallet = await this.getWallet({
|
|
568
871
|
accountAddress,
|
|
569
872
|
password,
|
|
570
|
-
walletOperation: WalletOperation.SIGN_MESSAGE
|
|
873
|
+
walletOperation: core.WalletOperation.SIGN_MESSAGE
|
|
571
874
|
});
|
|
572
875
|
// Perform the server sign
|
|
573
876
|
const data = await this.serverSign({
|
|
@@ -576,11 +879,14 @@ class DynamicWalletClient {
|
|
|
576
879
|
});
|
|
577
880
|
const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
|
|
578
881
|
// Perform the client sign and return the signature
|
|
882
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
883
|
+
accountAddress
|
|
884
|
+
});
|
|
579
885
|
const signature = await this.clientSign({
|
|
580
886
|
chainName,
|
|
581
887
|
message,
|
|
582
888
|
roomId: data.roomId,
|
|
583
|
-
keyShare:
|
|
889
|
+
keyShare: clientKeyShares[0],
|
|
584
890
|
derivationPath
|
|
585
891
|
});
|
|
586
892
|
return signature;
|
|
@@ -589,11 +895,11 @@ class DynamicWalletClient {
|
|
|
589
895
|
await this.verifyPassword({
|
|
590
896
|
accountAddress,
|
|
591
897
|
password,
|
|
592
|
-
walletOperation: WalletOperation.REFRESH
|
|
898
|
+
walletOperation: core.WalletOperation.REFRESH
|
|
593
899
|
});
|
|
594
900
|
const wallet = await this.getWallet({
|
|
595
901
|
accountAddress,
|
|
596
|
-
walletOperation: WalletOperation.
|
|
902
|
+
walletOperation: core.WalletOperation.NO_OPERATION,
|
|
597
903
|
password
|
|
598
904
|
});
|
|
599
905
|
const mpcSigner = getMPCSigner({
|
|
@@ -605,12 +911,18 @@ class DynamicWalletClient {
|
|
|
605
911
|
walletId: wallet.walletId
|
|
606
912
|
});
|
|
607
913
|
const roomId = data.roomId;
|
|
608
|
-
const
|
|
914
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
915
|
+
accountAddress
|
|
916
|
+
});
|
|
917
|
+
const refreshResults = await Promise.all(clientKeyShares.map((clientKeyShare)=>mpcSigner.refresh(roomId, clientKeyShare)));
|
|
609
918
|
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
610
|
-
clientKeyShares: refreshResults,
|
|
611
919
|
clientKeySharesBackupInfo: getClientKeyShareBackupInfo()
|
|
612
920
|
});
|
|
613
|
-
await this.
|
|
921
|
+
await this.setClientKeySharesToLocalStorage({
|
|
922
|
+
accountAddress,
|
|
923
|
+
clientKeyShares: refreshResults,
|
|
924
|
+
overwriteOrMerge: 'overwrite'
|
|
925
|
+
});
|
|
614
926
|
await this.storeEncryptedBackupByWallet({
|
|
615
927
|
accountAddress,
|
|
616
928
|
password: password != null ? password : this.environmentId
|
|
@@ -638,7 +950,7 @@ class DynamicWalletClient {
|
|
|
638
950
|
* existingClientKeyShares: ClientKeyShare[]
|
|
639
951
|
* }>} Object containing new and existing client keygen results, IDs and shares
|
|
640
952
|
* @todo Support higher to lower reshare strategies
|
|
641
|
-
*/ async reshareStrategy({ chainName, wallet, oldThresholdSignatureScheme, newThresholdSignatureScheme }) {
|
|
953
|
+
*/ async reshareStrategy({ chainName, wallet, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme }) {
|
|
642
954
|
const mpcSigner = getMPCSigner({
|
|
643
955
|
chainName,
|
|
644
956
|
baseRelayUrl: this.baseMPCRelayApiUrl
|
|
@@ -654,7 +966,9 @@ class DynamicWalletClient {
|
|
|
654
966
|
}, ()=>mpcSigner.initKeygen()));
|
|
655
967
|
const newClientKeygenIds = newClientInitKeygenResults.map((result)=>result.keygenId);
|
|
656
968
|
// Get existing client shares
|
|
657
|
-
const existingClientKeyShares =
|
|
969
|
+
const existingClientKeyShares = (await this.getClientKeySharesFromLocalStorage({
|
|
970
|
+
accountAddress
|
|
971
|
+
})).slice(0, existingClientShareCount);
|
|
658
972
|
const existingClientKeygenIds = await Promise.all(existingClientKeyShares.map(async (keyShare)=>await this.getExportId({
|
|
659
973
|
chainName,
|
|
660
974
|
clientKeyShare: keyShare
|
|
@@ -670,7 +984,7 @@ class DynamicWalletClient {
|
|
|
670
984
|
await this.verifyPassword({
|
|
671
985
|
accountAddress,
|
|
672
986
|
password,
|
|
673
|
-
walletOperation: WalletOperation.RESHARE
|
|
987
|
+
walletOperation: core.WalletOperation.RESHARE
|
|
674
988
|
});
|
|
675
989
|
const { existingClientShareCount } = core.getReshareConfig({
|
|
676
990
|
oldThresholdSignatureScheme,
|
|
@@ -678,12 +992,13 @@ class DynamicWalletClient {
|
|
|
678
992
|
});
|
|
679
993
|
const wallet = await this.getWallet({
|
|
680
994
|
accountAddress,
|
|
681
|
-
walletOperation: WalletOperation.
|
|
995
|
+
walletOperation: core.WalletOperation.NO_OPERATION,
|
|
682
996
|
shareCount: existingClientShareCount,
|
|
683
997
|
password
|
|
684
998
|
});
|
|
685
999
|
const { newClientInitKeygenResults, newClientKeygenIds, existingClientKeygenIds, existingClientKeyShares } = await this.reshareStrategy({
|
|
686
1000
|
chainName,
|
|
1001
|
+
accountAddress,
|
|
687
1002
|
wallet,
|
|
688
1003
|
oldThresholdSignatureScheme,
|
|
689
1004
|
newThresholdSignatureScheme
|
|
@@ -716,35 +1031,39 @@ class DynamicWalletClient {
|
|
|
716
1031
|
...newClientInitKeygenResults.map((keygenResult)=>mpcSigner.reshareNewParty(roomId, oldMpcConfig.threshold, newMpcConfig.threshold, keygenResult, allPartyKeygenIds)),
|
|
717
1032
|
...existingClientKeyShares.map((keyShare)=>mpcSigner.reshareRemainingParty(roomId, newMpcConfig.threshold, keyShare, allPartyKeygenIds))
|
|
718
1033
|
]);
|
|
719
|
-
this.
|
|
720
|
-
|
|
1034
|
+
await this.setClientKeySharesToLocalStorage({
|
|
1035
|
+
accountAddress,
|
|
1036
|
+
clientKeyShares: reshareResults,
|
|
1037
|
+
overwriteOrMerge: 'overwrite'
|
|
721
1038
|
});
|
|
722
|
-
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
723
1039
|
await this.storeEncryptedBackupByWallet({
|
|
724
1040
|
accountAddress,
|
|
725
1041
|
password
|
|
726
1042
|
});
|
|
727
1043
|
return reshareResults;
|
|
728
1044
|
}
|
|
729
|
-
async exportKey({ accountAddress, chainName, password = undefined }) {
|
|
1045
|
+
async exportKey({ accountAddress, displayContainer, chainName, password = undefined }) {
|
|
730
1046
|
const wallet = await this.getWallet({
|
|
731
1047
|
accountAddress,
|
|
732
1048
|
password,
|
|
733
|
-
walletOperation: WalletOperation.EXPORT_PRIVATE_KEY
|
|
1049
|
+
walletOperation: core.WalletOperation.EXPORT_PRIVATE_KEY
|
|
734
1050
|
});
|
|
735
1051
|
const mpcSigner = getMPCSigner({
|
|
736
1052
|
chainName,
|
|
737
1053
|
baseRelayUrl: this.baseMPCRelayApiUrl
|
|
738
1054
|
});
|
|
1055
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
1056
|
+
accountAddress
|
|
1057
|
+
});
|
|
739
1058
|
const exportId = await this.getExportId({
|
|
740
1059
|
chainName,
|
|
741
|
-
clientKeyShare:
|
|
1060
|
+
clientKeyShare: clientKeyShares[0]
|
|
742
1061
|
});
|
|
743
1062
|
const data = await this.apiClient.exportKey({
|
|
744
1063
|
walletId: wallet.walletId,
|
|
745
1064
|
exportId
|
|
746
1065
|
});
|
|
747
|
-
const keyExportRaw = await mpcSigner.exportFullPrivateKey(data.roomId,
|
|
1066
|
+
const keyExportRaw = await mpcSigner.exportFullPrivateKey(data.roomId, clientKeyShares[0], exportId);
|
|
748
1067
|
if (!keyExportRaw) {
|
|
749
1068
|
throw new Error('Error exporting private key');
|
|
750
1069
|
}
|
|
@@ -787,11 +1106,17 @@ class DynamicWalletClient {
|
|
|
787
1106
|
} else if (mpcSigner instanceof web.BIP340) {
|
|
788
1107
|
derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
|
|
789
1108
|
}
|
|
1109
|
+
const rawPublicKey = await this.derivePublicKey({
|
|
1110
|
+
chainName,
|
|
1111
|
+
keyShare: walletKeyShares[0],
|
|
1112
|
+
derivationPath: walletDerivationPath
|
|
1113
|
+
});
|
|
790
1114
|
return {
|
|
791
|
-
derivedPrivateKey
|
|
1115
|
+
derivedPrivateKey,
|
|
1116
|
+
rawPublicKey
|
|
792
1117
|
};
|
|
793
1118
|
} catch (error) {
|
|
794
|
-
|
|
1119
|
+
this.logger.error('Error in offlineExportKey:', error);
|
|
795
1120
|
throw error;
|
|
796
1121
|
}
|
|
797
1122
|
}
|
|
@@ -806,6 +1131,47 @@ class DynamicWalletClient {
|
|
|
806
1131
|
return serializedEncryptedKeyShare;
|
|
807
1132
|
}
|
|
808
1133
|
/**
|
|
1134
|
+
* temporary helper function to store encrypted backup by wallet based on `useIframeStorage` flag
|
|
1135
|
+
* TODO: revise this to only use iframe storage when iframe is deployed
|
|
1136
|
+
*/ async getClientKeySharesFromLocalStorage({ accountAddress }) {
|
|
1137
|
+
var _this_iframeStorage;
|
|
1138
|
+
if (!this.useIframeStorage) {
|
|
1139
|
+
return this.walletMap[accountAddress].clientKeyShares;
|
|
1140
|
+
}
|
|
1141
|
+
await this.initializeIframeCommunication();
|
|
1142
|
+
const walletObject = await ((_this_iframeStorage = this.iframeStorage) == null ? void 0 : _this_iframeStorage.getItem(accountAddress));
|
|
1143
|
+
if (!walletObject) {
|
|
1144
|
+
this.logger.debug(`No item found in iframe local storage for accountAddress: ${accountAddress}`);
|
|
1145
|
+
return [];
|
|
1146
|
+
}
|
|
1147
|
+
try {
|
|
1148
|
+
return (walletObject == null ? void 0 : walletObject.clientKeyShares) || [];
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
this.logger.error(`Error parsing clientKeyShares: ${error} for accountAddress: ${accountAddress}`);
|
|
1151
|
+
return [];
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* temporary helper function to store encrypted backup by wallet based on `useIframeStorage` flag
|
|
1156
|
+
* TODO: revise this to only use iframe storage when iframe is deployed
|
|
1157
|
+
*/ async setClientKeySharesToLocalStorage({ accountAddress, clientKeyShares, overwriteOrMerge = 'merge' }) {
|
|
1158
|
+
var _this_iframeStorage;
|
|
1159
|
+
if (!this.useIframeStorage) {
|
|
1160
|
+
var _this_walletMap_accountAddress;
|
|
1161
|
+
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
|
|
1162
|
+
clientKeyShares: overwriteOrMerge === 'overwrite' ? clientKeyShares : mergeUniqueKeyShares(((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.clientKeyShares) || [], clientKeyShares)
|
|
1163
|
+
});
|
|
1164
|
+
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
await this.initializeIframeCommunication();
|
|
1168
|
+
await ((_this_iframeStorage = this.iframeStorage) == null ? void 0 : _this_iframeStorage.setItem(accountAddress, {
|
|
1169
|
+
clientKeyShares: overwriteOrMerge === 'overwrite' ? clientKeyShares : mergeUniqueKeyShares(await this.getClientKeySharesFromLocalStorage({
|
|
1170
|
+
accountAddress
|
|
1171
|
+
}), clientKeyShares)
|
|
1172
|
+
}));
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
809
1175
|
* Encrypts and stores wallet key shares as backups.
|
|
810
1176
|
*
|
|
811
1177
|
* This method encrypts all client key shares for a specific wallet and stores them
|
|
@@ -823,7 +1189,9 @@ class DynamicWalletClient {
|
|
|
823
1189
|
* @param {string} params.accountAddress - The account address of the wallet to backup
|
|
824
1190
|
* @param {string} [params.password] - Optional password for encrypting the key shares
|
|
825
1191
|
*/ async storeEncryptedBackupByWallet({ accountAddress, clientKeyShares = undefined, password = undefined }) {
|
|
826
|
-
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : this.
|
|
1192
|
+
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
1193
|
+
accountAddress
|
|
1194
|
+
});
|
|
827
1195
|
const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
|
|
828
1196
|
keyShare,
|
|
829
1197
|
password
|
|
@@ -884,7 +1252,7 @@ class DynamicWalletClient {
|
|
|
884
1252
|
await this.getWallet({
|
|
885
1253
|
accountAddress,
|
|
886
1254
|
password: existingPassword,
|
|
887
|
-
walletOperation: WalletOperation.REACH_ALL_PARTIES
|
|
1255
|
+
walletOperation: core.WalletOperation.REACH_ALL_PARTIES
|
|
888
1256
|
});
|
|
889
1257
|
await this.storeEncryptedBackupByWallet({
|
|
890
1258
|
accountAddress,
|
|
@@ -914,7 +1282,7 @@ class DynamicWalletClient {
|
|
|
914
1282
|
*/ recoverStrategy({ clientKeyShareBackupInfo, thresholdSignatureScheme, walletOperation, shareCount = undefined }) {
|
|
915
1283
|
const { backups } = clientKeyShareBackupInfo;
|
|
916
1284
|
const { clientThreshold } = core.MPC_CONFIG[thresholdSignatureScheme];
|
|
917
|
-
let requiredShareCount = walletOperation === WalletOperation.REFRESH || walletOperation === WalletOperation.REACH_ALL_PARTIES || walletOperation === WalletOperation.RESHARE ? clientThreshold : 1;
|
|
1285
|
+
let requiredShareCount = walletOperation === core.WalletOperation.REFRESH || walletOperation === core.WalletOperation.REACH_ALL_PARTIES || walletOperation === core.WalletOperation.RESHARE ? clientThreshold : 1;
|
|
918
1286
|
// Override requiredShareCount if shareCount is provided
|
|
919
1287
|
if (shareCount !== undefined) {
|
|
920
1288
|
requiredShareCount = shareCount;
|
|
@@ -947,8 +1315,10 @@ class DynamicWalletClient {
|
|
|
947
1315
|
password: password != null ? password : this.environmentId
|
|
948
1316
|
})));
|
|
949
1317
|
if (storeRecoveredShares) {
|
|
950
|
-
this.
|
|
951
|
-
|
|
1318
|
+
await this.setClientKeySharesToLocalStorage({
|
|
1319
|
+
accountAddress,
|
|
1320
|
+
clientKeyShares: decryptedKeyShares,
|
|
1321
|
+
overwriteOrMerge: 'merge'
|
|
952
1322
|
});
|
|
953
1323
|
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
954
1324
|
}
|
|
@@ -964,10 +1334,12 @@ class DynamicWalletClient {
|
|
|
964
1334
|
async backupKeySharesToGoogleDrive({ accountAddress, fileName, oauthAccountId, password }) {
|
|
965
1335
|
await this.getWallet({
|
|
966
1336
|
accountAddress,
|
|
967
|
-
walletOperation: WalletOperation.REACH_ALL_PARTIES,
|
|
1337
|
+
walletOperation: core.WalletOperation.REACH_ALL_PARTIES,
|
|
968
1338
|
password
|
|
969
1339
|
});
|
|
970
|
-
const clientKeyShares = this.
|
|
1340
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
1341
|
+
accountAddress
|
|
1342
|
+
});
|
|
971
1343
|
if (clientKeyShares.length === 0) {
|
|
972
1344
|
throw new Error('No key shares found');
|
|
973
1345
|
}
|
|
@@ -1022,7 +1394,7 @@ class DynamicWalletClient {
|
|
|
1022
1394
|
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
1023
1395
|
return ids;
|
|
1024
1396
|
}
|
|
1025
|
-
async restoreBackupFromGoogleDrive({ accountAddress, oauthAccountId, name, password }) {
|
|
1397
|
+
async restoreBackupFromGoogleDrive({ accountAddress, oauthAccountId, name, displayContainer, password }) {
|
|
1026
1398
|
await this.getWallet({
|
|
1027
1399
|
accountAddress
|
|
1028
1400
|
});
|
|
@@ -1050,71 +1422,27 @@ class DynamicWalletClient {
|
|
|
1050
1422
|
keyShare,
|
|
1051
1423
|
password
|
|
1052
1424
|
})));
|
|
1053
|
-
this.
|
|
1054
|
-
|
|
1425
|
+
await this.setClientKeySharesToLocalStorage({
|
|
1426
|
+
accountAddress,
|
|
1427
|
+
clientKeyShares: decryptedKeyShares,
|
|
1428
|
+
overwriteOrMerge: 'merge'
|
|
1055
1429
|
});
|
|
1430
|
+
if (this.useIframeStorage) {
|
|
1431
|
+
const { iframeDisplay } = await this.initializeIframeDisplayForContainer({
|
|
1432
|
+
container: displayContainer
|
|
1433
|
+
});
|
|
1434
|
+
iframeDisplay.displayClientShares(accountAddress);
|
|
1435
|
+
}
|
|
1056
1436
|
return decryptedKeyShares;
|
|
1057
1437
|
}
|
|
1058
|
-
async importRawPrivateKey({ chainName, privateKey, thresholdSignatureScheme, onError, onCeremonyComplete }) {
|
|
1059
|
-
const mpcSigner = getMPCSigner({
|
|
1060
|
-
chainName,
|
|
1061
|
-
baseRelayUrl: this.baseMPCRelayApiUrl
|
|
1062
|
-
});
|
|
1063
|
-
const clientKeygenInitResults = await this.clientInitializeKeyGen({
|
|
1064
|
-
chainName,
|
|
1065
|
-
thresholdSignatureScheme
|
|
1066
|
-
});
|
|
1067
|
-
const clientKeygenIds = clientKeygenInitResults.map((result)=>result.keygenId);
|
|
1068
|
-
const { roomId, serverKeygenIds } = await this.apiClient.importPrivateKey({
|
|
1069
|
-
chainName,
|
|
1070
|
-
clientKeygenIds,
|
|
1071
|
-
thresholdSignatureScheme,
|
|
1072
|
-
onError,
|
|
1073
|
-
onCeremonyComplete
|
|
1074
|
-
});
|
|
1075
|
-
const { threshold } = core.getTSSConfig(thresholdSignatureScheme);
|
|
1076
|
-
const clientKeygenResults = await Promise.all(clientKeygenInitResults.map(async (currentInit, index)=>{
|
|
1077
|
-
const otherClientKeygenIds = clientKeygenInitResults.filter((init)=>init.keygenId !== currentInit.keygenId).map((init)=>init.keygenId);
|
|
1078
|
-
if (index === 0) {
|
|
1079
|
-
const otherKeyGenIds = [
|
|
1080
|
-
...serverKeygenIds,
|
|
1081
|
-
...otherClientKeygenIds
|
|
1082
|
-
];
|
|
1083
|
-
const importerKeygenResult = await mpcSigner.importPrivateKeyImporter(roomId, threshold, privateKey, currentInit, otherKeyGenIds);
|
|
1084
|
-
return importerKeygenResult;
|
|
1085
|
-
} else {
|
|
1086
|
-
const recipientKeygenResult = await mpcSigner.importPrivateKeyRecipient(roomId, threshold, currentInit, [
|
|
1087
|
-
...serverKeygenIds,
|
|
1088
|
-
...otherClientKeygenIds
|
|
1089
|
-
]);
|
|
1090
|
-
return recipientKeygenResult;
|
|
1091
|
-
}
|
|
1092
|
-
}));
|
|
1093
|
-
const [clientKeygenResult] = clientKeygenResults;
|
|
1094
|
-
const rawPublicKey = await this.derivePublicKey({
|
|
1095
|
-
chainName,
|
|
1096
|
-
keyShare: clientKeygenResult,
|
|
1097
|
-
derivationPath: undefined
|
|
1098
|
-
});
|
|
1099
|
-
return {
|
|
1100
|
-
rawPublicKey,
|
|
1101
|
-
clientKeyShares: clientKeygenResults
|
|
1102
|
-
};
|
|
1103
|
-
}
|
|
1104
1438
|
async exportClientKeyshares({ accountAddress, password }) {
|
|
1105
1439
|
await this.verifyPassword({
|
|
1106
1440
|
accountAddress,
|
|
1107
1441
|
password,
|
|
1108
|
-
walletOperation: WalletOperation.REACH_ALL_PARTIES
|
|
1109
|
-
});
|
|
1110
|
-
await this.getWallet({
|
|
1111
|
-
accountAddress,
|
|
1112
|
-
walletOperation: WalletOperation.REACH_ALL_PARTIES,
|
|
1113
|
-
password
|
|
1442
|
+
walletOperation: core.WalletOperation.REACH_ALL_PARTIES
|
|
1114
1443
|
});
|
|
1115
|
-
const clientKeyShares = await this.
|
|
1116
|
-
accountAddress
|
|
1117
|
-
password
|
|
1444
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
1445
|
+
accountAddress
|
|
1118
1446
|
});
|
|
1119
1447
|
if (!accountAddress) {
|
|
1120
1448
|
throw new Error('Must provide an account address');
|
|
@@ -1136,19 +1464,21 @@ class DynamicWalletClient {
|
|
|
1136
1464
|
a.click();
|
|
1137
1465
|
}
|
|
1138
1466
|
async getClientKeyShares({ accountAddress, password }) {
|
|
1139
|
-
|
|
1467
|
+
await this.getWallet({
|
|
1140
1468
|
accountAddress,
|
|
1141
1469
|
password,
|
|
1142
|
-
walletOperation: WalletOperation.REACH_THRESHOLD
|
|
1470
|
+
walletOperation: core.WalletOperation.REACH_THRESHOLD
|
|
1471
|
+
});
|
|
1472
|
+
return this.getClientKeySharesFromLocalStorage({
|
|
1473
|
+
accountAddress
|
|
1143
1474
|
});
|
|
1144
|
-
return wallet.clientKeyShares;
|
|
1145
1475
|
}
|
|
1146
1476
|
/**
|
|
1147
1477
|
* Helper function to check if the required wallet fields are present and valid
|
|
1148
1478
|
* @param accountAddress - The account address of the wallet to check
|
|
1149
1479
|
* @param walletOperation - The wallet operation that determines required fields
|
|
1150
1480
|
* @returns boolean indicating if wallet needs to be re-fetched and restored from server
|
|
1151
|
-
*/ async checkWalletFields({ accountAddress, walletOperation = WalletOperation.REACH_THRESHOLD, shareCount }) {
|
|
1481
|
+
*/ async checkWalletFields({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD, shareCount }) {
|
|
1152
1482
|
let keyshareCheck = false;
|
|
1153
1483
|
let walletCheck = false;
|
|
1154
1484
|
let thresholdSignatureSchemeCheck = false;
|
|
@@ -1168,7 +1498,6 @@ class DynamicWalletClient {
|
|
|
1168
1498
|
}
|
|
1169
1499
|
// check if wallet already exists with sufficient keyshares
|
|
1170
1500
|
if (existingWallet) {
|
|
1171
|
-
var _existingWallet_clientKeyShares;
|
|
1172
1501
|
const { shares } = this.recoverStrategy({
|
|
1173
1502
|
clientKeyShareBackupInfo: existingWallet.clientKeySharesBackupInfo || {
|
|
1174
1503
|
backups: getClientKeyShareBackupInfo()
|
|
@@ -1178,7 +1507,10 @@ class DynamicWalletClient {
|
|
|
1178
1507
|
shareCount
|
|
1179
1508
|
});
|
|
1180
1509
|
const { dynamic: requiredDynamicKeyShareIds = [] } = shares;
|
|
1181
|
-
|
|
1510
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
1511
|
+
accountAddress
|
|
1512
|
+
});
|
|
1513
|
+
if (requiredDynamicKeyShareIds.length <= ((clientKeyShares == null ? void 0 : clientKeyShares.length) || 0)) {
|
|
1182
1514
|
keyshareCheck = true;
|
|
1183
1515
|
}
|
|
1184
1516
|
}
|
|
@@ -1188,7 +1520,7 @@ class DynamicWalletClient {
|
|
|
1188
1520
|
* verifyPassword attempts to recover and decrypt a single client key share using the provided password.
|
|
1189
1521
|
* If successful, the key share is encrypted with the new password. This method solely performs the recovery
|
|
1190
1522
|
* and decryption without storing the restored key shares. If unsuccessful, it throws an error.
|
|
1191
|
-
*/ async verifyPassword({ accountAddress, password = undefined, walletOperation = WalletOperation.NO_OPERATION }) {
|
|
1523
|
+
*/ async verifyPassword({ accountAddress, password = undefined, walletOperation = core.WalletOperation.NO_OPERATION }) {
|
|
1192
1524
|
await this.getWallet({
|
|
1193
1525
|
accountAddress,
|
|
1194
1526
|
password,
|
|
@@ -1232,7 +1564,7 @@ class DynamicWalletClient {
|
|
|
1232
1564
|
}
|
|
1233
1565
|
/**
|
|
1234
1566
|
* check if the operation requires a password
|
|
1235
|
-
*/ async requiresPasswordForOperation({ accountAddress, walletOperation = WalletOperation.REACH_THRESHOLD }) {
|
|
1567
|
+
*/ async requiresPasswordForOperation({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD }) {
|
|
1236
1568
|
const isEncrypted = await this.isPasswordEncrypted({
|
|
1237
1569
|
accountAddress
|
|
1238
1570
|
});
|
|
@@ -1246,12 +1578,14 @@ class DynamicWalletClient {
|
|
|
1246
1578
|
}
|
|
1247
1579
|
/**
|
|
1248
1580
|
* check if the operation requires restoring backup shares
|
|
1249
|
-
*/ async requiresRestoreBackupSharesForOperation({ accountAddress, walletOperation = WalletOperation.REACH_THRESHOLD }) {
|
|
1581
|
+
*/ async requiresRestoreBackupSharesForOperation({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD }) {
|
|
1250
1582
|
const clientKeySharesBackupInfo = await this.getWalletClientKeyShareBackupInfo({
|
|
1251
1583
|
accountAddress
|
|
1252
1584
|
});
|
|
1253
|
-
const clientKeyShares = this.
|
|
1254
|
-
|
|
1585
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
1586
|
+
accountAddress
|
|
1587
|
+
});
|
|
1588
|
+
if (walletOperation === core.WalletOperation.REACH_ALL_PARTIES || walletOperation === core.WalletOperation.REFRESH || walletOperation === core.WalletOperation.RESHARE) {
|
|
1255
1589
|
return true;
|
|
1256
1590
|
}
|
|
1257
1591
|
const { requiredShareCount } = this.recoverStrategy({
|
|
@@ -1277,7 +1611,7 @@ class DynamicWalletClient {
|
|
|
1277
1611
|
walletProperties: wallet == null ? void 0 : wallet.walletProperties
|
|
1278
1612
|
});
|
|
1279
1613
|
}
|
|
1280
|
-
async getWallet({ accountAddress, walletOperation = WalletOperation.NO_OPERATION, shareCount = undefined, password = undefined }) {
|
|
1614
|
+
async getWallet({ accountAddress, walletOperation = core.WalletOperation.NO_OPERATION, shareCount = undefined, password = undefined }) {
|
|
1281
1615
|
var _user_verifiedCredentials;
|
|
1282
1616
|
const existingWalletCheck = await this.checkWalletFields({
|
|
1283
1617
|
accountAddress,
|
|
@@ -1303,7 +1637,7 @@ class DynamicWalletClient {
|
|
|
1303
1637
|
walletProperties
|
|
1304
1638
|
})
|
|
1305
1639
|
});
|
|
1306
|
-
if (walletOperation !== WalletOperation.NO_OPERATION && await this.requiresRestoreBackupSharesForOperation({
|
|
1640
|
+
if (walletOperation !== core.WalletOperation.NO_OPERATION && await this.requiresRestoreBackupSharesForOperation({
|
|
1307
1641
|
accountAddress,
|
|
1308
1642
|
walletOperation
|
|
1309
1643
|
})) {
|
|
@@ -1313,6 +1647,12 @@ class DynamicWalletClient {
|
|
|
1313
1647
|
walletOperation: walletOperation,
|
|
1314
1648
|
shareCount
|
|
1315
1649
|
});
|
|
1650
|
+
if (this.useIframeStorage) {
|
|
1651
|
+
var _this_iframeStorage;
|
|
1652
|
+
(_this_iframeStorage = this.iframeStorage) == null ? void 0 : _this_iframeStorage.setItem(`${accountAddress}`, JSON.stringify({
|
|
1653
|
+
clientKeyShares: decryptedKeyShares
|
|
1654
|
+
}));
|
|
1655
|
+
}
|
|
1316
1656
|
this.logger.debug('Recovered backup', decryptedKeyShares);
|
|
1317
1657
|
}
|
|
1318
1658
|
const walletCount = Object.keys(this.walletMap).length;
|
|
@@ -1345,13 +1685,13 @@ class DynamicWalletClient {
|
|
|
1345
1685
|
};
|
|
1346
1686
|
});
|
|
1347
1687
|
this.walletMap = wallets.reduce((acc, wallet)=>{
|
|
1348
|
-
var _acc_accountAddress;
|
|
1688
|
+
var _acc_wallet_accountAddress, _acc_accountAddress;
|
|
1349
1689
|
const accountAddress = wallet.accountAddress;
|
|
1350
1690
|
acc[wallet.accountAddress] = {
|
|
1351
1691
|
walletId: wallet.walletId,
|
|
1352
1692
|
chainName: wallet.chainName,
|
|
1353
1693
|
accountAddress: wallet.accountAddress,
|
|
1354
|
-
clientKeyShares: wallet.clientKeyShares || [],
|
|
1694
|
+
clientKeyShares: ((_acc_wallet_accountAddress = acc[wallet.accountAddress]) == null ? void 0 : _acc_wallet_accountAddress.clientKeyShares) || [],
|
|
1355
1695
|
clientKeySharesBackupInfo: wallet.clientKeySharesBackupInfo,
|
|
1356
1696
|
derivationPath: ((_acc_accountAddress = acc[accountAddress]) == null ? void 0 : _acc_accountAddress.derivationPath) || undefined,
|
|
1357
1697
|
thresholdSignatureScheme: wallet.thresholdSignatureScheme
|
|
@@ -1365,7 +1705,14 @@ class DynamicWalletClient {
|
|
|
1365
1705
|
this.logger = logger;
|
|
1366
1706
|
this.walletMap = {} // todo: store in session storage
|
|
1367
1707
|
;
|
|
1708
|
+
this.iframeStorage = null;
|
|
1709
|
+
this.iframeDisplay = null;
|
|
1368
1710
|
this.memoryStorage = null;
|
|
1711
|
+
this.messageTransport = null;
|
|
1712
|
+
this.iframe = null;
|
|
1713
|
+
this.useIframeStorage = false // TODO: remove this when iframe is deployed
|
|
1714
|
+
;
|
|
1715
|
+
this.iframeLoadPromise = null;
|
|
1369
1716
|
this.environmentId = environmentId;
|
|
1370
1717
|
this.storageKey = `${STORAGE_KEY}-${storageKey != null ? storageKey : environmentId}`;
|
|
1371
1718
|
this.baseMPCRelayApiUrl = baseMPCRelayApiUrl;
|
|
@@ -1383,6 +1730,9 @@ class DynamicWalletClient {
|
|
|
1383
1730
|
this.memoryStorage = {};
|
|
1384
1731
|
this.storage = memoryLocalStorageAdapter(this.memoryStorage);
|
|
1385
1732
|
}
|
|
1733
|
+
this.iframeDomain = core.IFRAME_DOMAIN;
|
|
1734
|
+
// Generate unique instanceId when client is created
|
|
1735
|
+
this.instanceId = crypto.randomUUID();
|
|
1386
1736
|
// initialize the client
|
|
1387
1737
|
this.initialize();
|
|
1388
1738
|
}
|
|
@@ -1437,7 +1787,6 @@ Object.defineProperty(exports, "MessageHash", {
|
|
|
1437
1787
|
get: function () { return web.MessageHash; }
|
|
1438
1788
|
});
|
|
1439
1789
|
exports.DynamicWalletClient = DynamicWalletClient;
|
|
1440
|
-
exports.WalletOperation = WalletOperation;
|
|
1441
1790
|
exports.base64ToBytes = base64ToBytes;
|
|
1442
1791
|
exports.bytesToBase64 = bytesToBase64;
|
|
1443
1792
|
exports.ensureBase64Padding = ensureBase64Padding;
|