@dynamic-labs-wallet/browser 0.0.92 → 0.0.94
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 +215 -129
- package/index.esm.js +216 -130
- package/package.json +2 -2
- package/src/backup/utils.d.ts.map +1 -1
- package/src/client.d.ts +52 -17
- package/src/client.d.ts.map +1 -1
package/index.cjs.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@dynamic-labs-wallet/core');
|
|
4
4
|
var web = require('./internal/web');
|
|
5
|
-
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
6
5
|
var logger$1 = require('@dynamic-labs/logger');
|
|
6
|
+
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
7
7
|
var axios = require('axios');
|
|
8
8
|
var createHttpError = require('http-errors');
|
|
9
9
|
|
|
@@ -369,6 +369,89 @@ const downloadFileFromGoogleDrive = async ({ accessToken, fileName })=>{
|
|
|
369
369
|
}
|
|
370
370
|
};
|
|
371
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Updates the wallet map with backup information after successful backup to Google Drive
|
|
374
|
+
* @param data - Response data containing key shares information
|
|
375
|
+
* @param walletMap - The wallet map to update
|
|
376
|
+
* @param accountAddress - The account address associated with the wallet
|
|
377
|
+
* @param backupLocation - The location where the backup is stored
|
|
378
|
+
* @param storage - Storage interface for persisting the updated wallet map
|
|
379
|
+
* @param storageKey - Key used to store the wallet map
|
|
380
|
+
* @returns The array of key share IDs that were backed up
|
|
381
|
+
*/ const updateWalletMapWithBackupInfo = async ({ data, walletMap, accountAddress, storage, storageKey })=>{
|
|
382
|
+
const ids = data.keyShares.map((keyShare)=>keyShare.id);
|
|
383
|
+
walletMap[accountAddress].clientKeySharesBackupInfo.backups[core.BackupLocation.GOOGLE_DRIVE] = ids;
|
|
384
|
+
await storage.setItem(storageKey, JSON.stringify(walletMap));
|
|
385
|
+
return ids;
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* Uploads a backup to Google Drive App
|
|
389
|
+
* @param accessToken - The access token for the Google Drive API
|
|
390
|
+
* @param fileName - The name of the file to upload
|
|
391
|
+
* @param backupData - The data to upload
|
|
392
|
+
* @param accountAddress - The account address associated with the backup
|
|
393
|
+
*/ const uploadBackupToGoogleDrive = async ({ accessToken, fileName, backupData, accountAddress })=>{
|
|
394
|
+
const uploadPromises = [
|
|
395
|
+
retryPromise(()=>uploadFileToGoogleDriveAppStorage({
|
|
396
|
+
accessToken,
|
|
397
|
+
fileName,
|
|
398
|
+
jsonData: backupData
|
|
399
|
+
})),
|
|
400
|
+
retryPromise(()=>uploadFileToGoogleDrivePersonal({
|
|
401
|
+
accessToken,
|
|
402
|
+
fileName,
|
|
403
|
+
jsonData: backupData
|
|
404
|
+
}))
|
|
405
|
+
];
|
|
406
|
+
const results = await Promise.allSettled(uploadPromises);
|
|
407
|
+
const errors = [];
|
|
408
|
+
// Check App Storage result
|
|
409
|
+
if (results[0].status === 'rejected') {
|
|
410
|
+
const error = results[0].reason;
|
|
411
|
+
logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive App Storage', {
|
|
412
|
+
accountAddress,
|
|
413
|
+
error
|
|
414
|
+
});
|
|
415
|
+
errors.push(`Failed to backup keyshares to Google Drive App Storage: ${error instanceof Error ? error.message : String(error)}`);
|
|
416
|
+
}
|
|
417
|
+
// Check Personal Drive result
|
|
418
|
+
if (results[1].status === 'rejected') {
|
|
419
|
+
const error = results[1].reason;
|
|
420
|
+
logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive Personal', {
|
|
421
|
+
accountAddress,
|
|
422
|
+
error
|
|
423
|
+
});
|
|
424
|
+
errors.push(`Failed to backup keyshares to Google Drive Personal: ${error instanceof Error ? error.message : String(error)}`);
|
|
425
|
+
}
|
|
426
|
+
// Throw if any uploads failed
|
|
427
|
+
if (errors.length > 0) {
|
|
428
|
+
throw new Error(`[DynamicWaasWalletClient] ${errors.join('; ')}`);
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const handleAxiosError = (error, message, context)=>{
|
|
433
|
+
var _error_response, _error_response1;
|
|
434
|
+
logger.debug("[DynamicWaasWalletClient] Axios error: " + message, {
|
|
435
|
+
error: (_error_response = error.response) == null ? void 0 : _error_response.status,
|
|
436
|
+
message: error.message,
|
|
437
|
+
context
|
|
438
|
+
});
|
|
439
|
+
switch((_error_response1 = error.response) == null ? void 0 : _error_response1.status){
|
|
440
|
+
case 400:
|
|
441
|
+
throw createHttpError(400, 'Invalid request');
|
|
442
|
+
case 401:
|
|
443
|
+
throw createHttpError(401, 'Authorization header or cookie is required');
|
|
444
|
+
case 403:
|
|
445
|
+
throw createHttpError(403, 'Forbidden');
|
|
446
|
+
case 422:
|
|
447
|
+
throw createHttpError(422, 'Unprocessable content');
|
|
448
|
+
case 500:
|
|
449
|
+
throw createHttpError(500, 'Internal server error');
|
|
450
|
+
default:
|
|
451
|
+
throw createHttpError(500, 'Internal server error');
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
|
|
372
455
|
const localStorageWriteTest = {
|
|
373
456
|
tested: false,
|
|
374
457
|
writable: false
|
|
@@ -438,79 +521,6 @@ const localStorageWriteTest = {
|
|
|
438
521
|
}
|
|
439
522
|
});
|
|
440
523
|
|
|
441
|
-
/**
|
|
442
|
-
* Updates the wallet map with backup information after successful backup to Google Drive
|
|
443
|
-
* @param data - Response data containing key shares information
|
|
444
|
-
* @param walletMap - The wallet map to update
|
|
445
|
-
* @param accountAddress - The account address associated with the wallet
|
|
446
|
-
* @param backupLocation - The location where the backup is stored
|
|
447
|
-
* @param storage - Storage interface for persisting the updated wallet map
|
|
448
|
-
* @param storageKey - Key used to store the wallet map
|
|
449
|
-
* @returns The array of key share IDs that were backed up
|
|
450
|
-
*/ const updateWalletMapWithBackupInfo = async ({ data, walletMap, accountAddress, storage, storageKey })=>{
|
|
451
|
-
const ids = data.keyShares.map((keyShare)=>keyShare.id);
|
|
452
|
-
walletMap[accountAddress].clientKeySharesBackupInfo.backups[core.BackupLocation.GOOGLE_DRIVE] = ids;
|
|
453
|
-
await storage.setItem(storageKey, JSON.stringify(walletMap));
|
|
454
|
-
return ids;
|
|
455
|
-
};
|
|
456
|
-
/**
|
|
457
|
-
* Uploads a backup to Google Drive App
|
|
458
|
-
* @param accessToken - The access token for the Google Drive API
|
|
459
|
-
* @param fileName - The name of the file to upload
|
|
460
|
-
* @param backupData - The data to upload
|
|
461
|
-
* @param accountAddress - The account address associated with the backup
|
|
462
|
-
*/ const uploadBackupToGoogleDrive = async ({ accessToken, fileName, backupData, accountAddress })=>{
|
|
463
|
-
try {
|
|
464
|
-
await retryPromise(()=>uploadFileToGoogleDriveAppStorage({
|
|
465
|
-
accessToken,
|
|
466
|
-
fileName,
|
|
467
|
-
jsonData: backupData
|
|
468
|
-
}));
|
|
469
|
-
} catch (error) {
|
|
470
|
-
logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive App Storage', {
|
|
471
|
-
accountAddress,
|
|
472
|
-
error
|
|
473
|
-
});
|
|
474
|
-
throw new Error(`[DynamicWaasWalletClient] Failed to backup keyshares to Google Drive App Storage: ${error instanceof Error ? error.message : String(error)}`);
|
|
475
|
-
}
|
|
476
|
-
try {
|
|
477
|
-
await retryPromise(()=>uploadFileToGoogleDrivePersonal({
|
|
478
|
-
accessToken,
|
|
479
|
-
fileName,
|
|
480
|
-
jsonData: backupData
|
|
481
|
-
}));
|
|
482
|
-
} catch (error) {
|
|
483
|
-
logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive Personal', {
|
|
484
|
-
accountAddress,
|
|
485
|
-
error
|
|
486
|
-
});
|
|
487
|
-
throw new Error(`[DynamicWaasWalletClient] Failed to backup keyshares to Google Drive Personal: ${error instanceof Error ? error.message : String(error)}`);
|
|
488
|
-
}
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
const handleAxiosError = (error, message, context)=>{
|
|
492
|
-
var _error_response, _error_response1;
|
|
493
|
-
logger.debug("[DynamicWaasWalletClient] Axios error: " + message, {
|
|
494
|
-
error: (_error_response = error.response) == null ? void 0 : _error_response.status,
|
|
495
|
-
message: error.message,
|
|
496
|
-
context
|
|
497
|
-
});
|
|
498
|
-
switch((_error_response1 = error.response) == null ? void 0 : _error_response1.status){
|
|
499
|
-
case 400:
|
|
500
|
-
throw createHttpError(400, 'Invalid request');
|
|
501
|
-
case 401:
|
|
502
|
-
throw createHttpError(401, 'Authorization header or cookie is required');
|
|
503
|
-
case 403:
|
|
504
|
-
throw createHttpError(403, 'Forbidden');
|
|
505
|
-
case 422:
|
|
506
|
-
throw createHttpError(422, 'Unprocessable content');
|
|
507
|
-
case 500:
|
|
508
|
-
throw createHttpError(500, 'Internal server error');
|
|
509
|
-
default:
|
|
510
|
-
throw createHttpError(500, 'Internal server error');
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
|
|
514
524
|
class DynamicWalletClient {
|
|
515
525
|
async initialize() {
|
|
516
526
|
if (this.initializePromise) {
|
|
@@ -659,7 +669,7 @@ class DynamicWalletClient {
|
|
|
659
669
|
clientKeyShares
|
|
660
670
|
};
|
|
661
671
|
} catch (error) {
|
|
662
|
-
const message =
|
|
672
|
+
const message = '[DynamicWaasWalletClient] Error in keyGen';
|
|
663
673
|
const context = {
|
|
664
674
|
chainName,
|
|
665
675
|
thresholdSignatureScheme
|
|
@@ -740,7 +750,7 @@ class DynamicWalletClient {
|
|
|
740
750
|
clientKeyShares: clientKeygenResults
|
|
741
751
|
};
|
|
742
752
|
} catch (error) {
|
|
743
|
-
const message =
|
|
753
|
+
const message = '[DynamicWaasWalletClient] Error in importRawPrivateKey';
|
|
744
754
|
const context = {
|
|
745
755
|
chainName,
|
|
746
756
|
thresholdSignatureScheme
|
|
@@ -843,7 +853,7 @@ class DynamicWalletClient {
|
|
|
843
853
|
});
|
|
844
854
|
return signature;
|
|
845
855
|
} catch (error) {
|
|
846
|
-
const message =
|
|
856
|
+
const message = '[DynamicWaasWalletClient] Error in sign';
|
|
847
857
|
const context = {
|
|
848
858
|
accountAddress,
|
|
849
859
|
chainName,
|
|
@@ -886,9 +896,6 @@ class DynamicWalletClient {
|
|
|
886
896
|
accountAddress
|
|
887
897
|
});
|
|
888
898
|
const refreshResults = await Promise.all(clientKeyShares.map((clientKeyShare)=>mpcSigner.refresh(roomId, clientKeyShare)));
|
|
889
|
-
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
890
|
-
clientKeySharesBackupInfo: getClientKeyShareBackupInfo()
|
|
891
|
-
});
|
|
892
899
|
await this.setClientKeySharesToLocalStorage({
|
|
893
900
|
accountAddress,
|
|
894
901
|
clientKeyShares: refreshResults,
|
|
@@ -900,7 +907,7 @@ class DynamicWalletClient {
|
|
|
900
907
|
signedSessionId
|
|
901
908
|
});
|
|
902
909
|
} catch (error) {
|
|
903
|
-
const message =
|
|
910
|
+
const message = '[DynamicWaasWalletClient] Error in refreshWalletAccountShares';
|
|
904
911
|
const context = {
|
|
905
912
|
accountAddress,
|
|
906
913
|
chainName
|
|
@@ -966,7 +973,7 @@ class DynamicWalletClient {
|
|
|
966
973
|
existingClientKeyShares
|
|
967
974
|
};
|
|
968
975
|
}
|
|
969
|
-
async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId }) {
|
|
976
|
+
async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId, backupToGoogleDrive = false }) {
|
|
970
977
|
try {
|
|
971
978
|
await this.verifyPassword({
|
|
972
979
|
accountAddress,
|
|
@@ -1020,6 +1027,9 @@ class DynamicWalletClient {
|
|
|
1020
1027
|
...newClientInitKeygenResults.map((keygenResult)=>mpcSigner.reshareNewParty(roomId, oldMpcConfig.threshold, newMpcConfig.threshold, keygenResult, allPartyKeygenIds)),
|
|
1021
1028
|
...existingClientKeyShares.map((keyShare)=>mpcSigner.reshareRemainingParty(roomId, newMpcConfig.threshold, keyShare, allPartyKeygenIds))
|
|
1022
1029
|
]);
|
|
1030
|
+
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1031
|
+
thresholdSignatureScheme: newThresholdSignatureScheme
|
|
1032
|
+
});
|
|
1023
1033
|
await this.setClientKeySharesToLocalStorage({
|
|
1024
1034
|
accountAddress,
|
|
1025
1035
|
clientKeyShares: reshareResults,
|
|
@@ -1028,10 +1038,11 @@ class DynamicWalletClient {
|
|
|
1028
1038
|
await this.storeEncryptedBackupByWallet({
|
|
1029
1039
|
accountAddress,
|
|
1030
1040
|
password,
|
|
1031
|
-
signedSessionId
|
|
1041
|
+
signedSessionId,
|
|
1042
|
+
backupToGoogleDrive
|
|
1032
1043
|
});
|
|
1033
1044
|
} catch (error) {
|
|
1034
|
-
const message =
|
|
1045
|
+
const message = '[DynamicWaasWalletClient] Error in reshare';
|
|
1035
1046
|
const context = {
|
|
1036
1047
|
accountAddress,
|
|
1037
1048
|
chainName,
|
|
@@ -1102,7 +1113,7 @@ class DynamicWalletClient {
|
|
|
1102
1113
|
derivedPrivateKey
|
|
1103
1114
|
};
|
|
1104
1115
|
} catch (error) {
|
|
1105
|
-
const message =
|
|
1116
|
+
const message = '[DynamicWaasWalletClient] Error in exportKey';
|
|
1106
1117
|
const context = {
|
|
1107
1118
|
accountAddress,
|
|
1108
1119
|
chainName
|
|
@@ -1201,48 +1212,71 @@ class DynamicWalletClient {
|
|
|
1201
1212
|
await ((_this_storage = this.storage) == null ? void 0 : _this_storage.setItem(accountAddress, stringifiedClientKeyShares));
|
|
1202
1213
|
}
|
|
1203
1214
|
/**
|
|
1204
|
-
*
|
|
1215
|
+
* Central backup orchestrator that encrypts and stores wallet key shares.
|
|
1205
1216
|
*
|
|
1206
|
-
* This method
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
1217
|
+
* This method serves as the main backup coordinator, handling the distribution of encrypted
|
|
1218
|
+
* key shares between Dynamic's backend and Google Drive based on the wallet's threshold scheme.
|
|
1219
|
+
* It is used by multiple operations including reshare, refresh, and manual backup requests.
|
|
1209
1220
|
*
|
|
1210
|
-
*
|
|
1221
|
+
* **Backup Distribution Strategy:**
|
|
1222
|
+
* - **Single share wallets**: All shares stored on Dynamic's backend only
|
|
1223
|
+
* - **Multi-share wallets (2+)**: When backing up to Google Drive, N-1 shares on Dynamic's backend, 1 share on Google Drive
|
|
1224
|
+
* - **Multi-share wallets (2+)**: When not backing up to Google Drive, all shares on Dynamic's backend
|
|
1225
|
+
*
|
|
1226
|
+
* **Process Flow:**
|
|
1211
1227
|
* 1. Encrypts all client key shares with the provided password (or environment ID if no password)
|
|
1212
|
-
* 2.
|
|
1213
|
-
* 3.
|
|
1214
|
-
* 4. Updates
|
|
1215
|
-
* 5. Persists the updated wallet map to storage
|
|
1228
|
+
* 2. For multi-share wallets (2+): conditionally distributes N-1 to backend, 1 to Google Drive
|
|
1229
|
+
* 3. For other configurations: stores all shares on Dynamic's backend
|
|
1230
|
+
* 4. Updates backup metadata and synchronizes wallet state
|
|
1231
|
+
* 5. Persists the updated wallet map to local storage
|
|
1216
1232
|
*
|
|
1217
|
-
* @param
|
|
1218
|
-
* @param
|
|
1219
|
-
* @param
|
|
1220
|
-
|
|
1233
|
+
* @param params - The backup operation parameters
|
|
1234
|
+
* @param params.accountAddress - The account address of the wallet to backup
|
|
1235
|
+
* @param params.clientKeyShares - Optional specific key shares to backup (uses localStorage if not provided)
|
|
1236
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1237
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
1238
|
+
* @param params.backupToGoogleDrive - Whether to backup to Google Drive (defaults to false)
|
|
1239
|
+
* @returns Promise with backup metadata including share locations and IDs
|
|
1240
|
+
*/ async storeEncryptedBackupByWallet({ accountAddress, clientKeyShares = undefined, password = undefined, signedSessionId, backupToGoogleDrive = false }) {
|
|
1221
1241
|
try {
|
|
1222
1242
|
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
1223
1243
|
accountAddress
|
|
1224
1244
|
});
|
|
1225
|
-
const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
|
|
1226
|
-
keyShare,
|
|
1227
|
-
password
|
|
1228
|
-
})));
|
|
1229
1245
|
if (!this.walletMap[accountAddress].walletId) {
|
|
1230
1246
|
this.logger.error(`[DynamicWaasWalletClient] WalletId not found for accountAddress: ${accountAddress}`);
|
|
1231
1247
|
throw new Error(`WalletId not found for accountAddress: ${accountAddress}`);
|
|
1232
1248
|
}
|
|
1233
1249
|
// TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
|
|
1250
|
+
let dynamicClientKeyShares = [];
|
|
1251
|
+
let googleDriveKeyShares = [];
|
|
1252
|
+
const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
|
|
1253
|
+
keyShare,
|
|
1254
|
+
password
|
|
1255
|
+
})));
|
|
1256
|
+
const hasExistingGoogleDriveBackup = this.walletMap[accountAddress].clientKeySharesBackupInfo.backups[core.BackupLocation.GOOGLE_DRIVE].length > 0;
|
|
1257
|
+
// Backup to Google Drive if:
|
|
1258
|
+
// 1. Explicitly requested via flag, OR
|
|
1259
|
+
// 2. User already has Google Drive backups
|
|
1260
|
+
const shouldBackupToGoogleDrive = backupToGoogleDrive || hasExistingGoogleDriveBackup;
|
|
1261
|
+
if (shouldBackupToGoogleDrive && keySharesToBackup.length >= 2) {
|
|
1262
|
+
// For 2 shares: 1 to backend, 1 to Google Drive
|
|
1263
|
+
// For 3+ shares: N-1 to backend, 1 to Google Drive
|
|
1264
|
+
const googleDriveShareCount = 1;
|
|
1265
|
+
dynamicClientKeyShares = encryptedKeyShares.slice(0, -googleDriveShareCount);
|
|
1266
|
+
googleDriveKeyShares = encryptedKeyShares.slice(-googleDriveShareCount);
|
|
1267
|
+
} else {
|
|
1268
|
+
dynamicClientKeyShares = encryptedKeyShares;
|
|
1269
|
+
}
|
|
1234
1270
|
const data = await this.apiClient.storeEncryptedBackupByWallet({
|
|
1235
1271
|
walletId: this.walletMap[accountAddress].walletId,
|
|
1236
|
-
encryptedKeyShares,
|
|
1272
|
+
encryptedKeyShares: dynamicClientKeyShares,
|
|
1237
1273
|
passwordEncrypted: Boolean(password) && password !== this.environmentId,
|
|
1238
1274
|
signedSessionId
|
|
1239
1275
|
});
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
const googleDriveKeyShareIds = await this.backupKeySharesToGoogleDrive({
|
|
1276
|
+
if (googleDriveKeyShares.length > 0) {
|
|
1277
|
+
const googleDriveKeyShareIds = await this.uploadKeySharesToGoogleDrive({
|
|
1243
1278
|
accountAddress,
|
|
1244
|
-
|
|
1245
|
-
signedSessionId
|
|
1279
|
+
encryptedKeyShares: googleDriveKeyShares
|
|
1246
1280
|
});
|
|
1247
1281
|
data.keyShares.push({
|
|
1248
1282
|
backupLocation: core.BackupLocation.GOOGLE_DRIVE,
|
|
@@ -1262,7 +1296,7 @@ class DynamicWalletClient {
|
|
|
1262
1296
|
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
1263
1297
|
return data;
|
|
1264
1298
|
} catch (error) {
|
|
1265
|
-
const message =
|
|
1299
|
+
const message = '[DynamicWaasWalletClient] Error in storeEncryptedBackupByWallet';
|
|
1266
1300
|
const context = {
|
|
1267
1301
|
accountAddress
|
|
1268
1302
|
};
|
|
@@ -1329,7 +1363,7 @@ class DynamicWalletClient {
|
|
|
1329
1363
|
}
|
|
1330
1364
|
return oauthAccountId;
|
|
1331
1365
|
} catch (error) {
|
|
1332
|
-
const message =
|
|
1366
|
+
const message = '[DynamicWaasWalletClient] Error in getGoogleOauthAccountIdOrThrow';
|
|
1333
1367
|
if (error instanceof axios.AxiosError) {
|
|
1334
1368
|
handleAxiosError(error, message, {
|
|
1335
1369
|
accountAddress
|
|
@@ -1400,7 +1434,7 @@ class DynamicWalletClient {
|
|
|
1400
1434
|
}
|
|
1401
1435
|
return decryptedKeyShares;
|
|
1402
1436
|
} catch (error) {
|
|
1403
|
-
const message =
|
|
1437
|
+
const message = '[DynamicWaasWalletClient] Error in recoverEncryptedBackupByWallet';
|
|
1404
1438
|
const context = {
|
|
1405
1439
|
accountAddress,
|
|
1406
1440
|
password,
|
|
@@ -1426,7 +1460,17 @@ class DynamicWalletClient {
|
|
|
1426
1460
|
}
|
|
1427
1461
|
this.walletMap = JSON.parse(wallets);
|
|
1428
1462
|
}
|
|
1429
|
-
|
|
1463
|
+
/**
|
|
1464
|
+
* This method handles the complete flow for ensuring wallet key shares are backed up to Google Drive:
|
|
1465
|
+
* - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to Google Drive)
|
|
1466
|
+
* - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and Google Drive
|
|
1467
|
+
*
|
|
1468
|
+
* @param params - The backup parameters
|
|
1469
|
+
* @param params.accountAddress - The wallet account address to backup
|
|
1470
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1471
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
1472
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were backed up
|
|
1473
|
+
*/ async backupKeySharesToGoogleDrive({ accountAddress, password, signedSessionId }) {
|
|
1430
1474
|
try {
|
|
1431
1475
|
await this.getWallet({
|
|
1432
1476
|
accountAddress,
|
|
@@ -1434,16 +1478,59 @@ class DynamicWalletClient {
|
|
|
1434
1478
|
password,
|
|
1435
1479
|
signedSessionId
|
|
1436
1480
|
});
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1481
|
+
const currentThresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
|
|
1482
|
+
if (currentThresholdSignatureScheme === core.ThresholdSignatureScheme.TWO_OF_TWO) {
|
|
1483
|
+
// Reshare to 2-of-3, which will automatically handle the backup distribution
|
|
1484
|
+
await this.reshare({
|
|
1485
|
+
chainName: this.walletMap[accountAddress].chainName,
|
|
1486
|
+
accountAddress,
|
|
1487
|
+
oldThresholdSignatureScheme: currentThresholdSignatureScheme,
|
|
1488
|
+
newThresholdSignatureScheme: core.ThresholdSignatureScheme.TWO_OF_THREE,
|
|
1489
|
+
password,
|
|
1490
|
+
signedSessionId,
|
|
1491
|
+
backupToGoogleDrive: true
|
|
1492
|
+
});
|
|
1493
|
+
const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
|
|
1494
|
+
const googleDriveShares = backupInfo.backups[core.BackupLocation.GOOGLE_DRIVE] || [];
|
|
1495
|
+
return googleDriveShares;
|
|
1496
|
+
} else {
|
|
1497
|
+
// Already 2-of-3, only call backup
|
|
1498
|
+
const data = await this.storeEncryptedBackupByWallet({
|
|
1499
|
+
accountAddress,
|
|
1500
|
+
password,
|
|
1501
|
+
signedSessionId,
|
|
1502
|
+
backupToGoogleDrive: true
|
|
1503
|
+
});
|
|
1504
|
+
const googleDriveKeyShares = data.keyShares.filter((ks)=>ks.backupLocation === core.BackupLocation.GOOGLE_DRIVE);
|
|
1505
|
+
return googleDriveKeyShares.map((ks)=>ks.id);
|
|
1506
|
+
}
|
|
1507
|
+
} catch (error) {
|
|
1508
|
+
this.logger.error('[DynamicWaasWalletClient]: Error in backupKeySharesToGoogleDrive', error);
|
|
1509
|
+
if (error instanceof axios.AxiosError) {
|
|
1510
|
+
const message = '[DynamicWaasWalletClient] Error in backupKeySharesToGoogleDrive';
|
|
1511
|
+
handleAxiosError(error, message, {
|
|
1512
|
+
accountAddress
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
throw error;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* This method handles only the Google Drive upload mechanics without any reshare logic.
|
|
1520
|
+
* It encrypts the provided key shares, uploads them to Google Drive, and updates the
|
|
1521
|
+
* backup metadata. This method is intended for internal use by storeEncryptedBackupByWallet
|
|
1522
|
+
* and should not be called directly from external code.
|
|
1523
|
+
*
|
|
1524
|
+
* @param params - The upload parameters
|
|
1525
|
+
* @param params.accountAddress - The wallet account address
|
|
1526
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1527
|
+
* @param params.encryptedKeyShares - The specific key shares to upload to Google Drive
|
|
1528
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were uploaded
|
|
1529
|
+
*/ async uploadKeySharesToGoogleDrive({ accountAddress, encryptedKeyShares }) {
|
|
1530
|
+
try {
|
|
1531
|
+
if (encryptedKeyShares.length === 0) {
|
|
1441
1532
|
throw new Error('No key shares found');
|
|
1442
1533
|
}
|
|
1443
|
-
const encryptedKeyShares = await Promise.all(clientKeyShares.map((keyShare)=>this.encryptKeyShare({
|
|
1444
|
-
keyShare,
|
|
1445
|
-
password
|
|
1446
|
-
})));
|
|
1447
1534
|
const oauthAccountId = await this.getGoogleOauthAccountIdOrThrow(accountAddress);
|
|
1448
1535
|
const accessToken = await this.apiClient.getAccessToken({
|
|
1449
1536
|
oauthAccountId
|
|
@@ -1474,12 +1561,11 @@ class DynamicWalletClient {
|
|
|
1474
1561
|
storage: this.storage,
|
|
1475
1562
|
storageKey: this.storageKey
|
|
1476
1563
|
});
|
|
1564
|
+
return data.keyShares.map((ks)=>ks.id);
|
|
1477
1565
|
} catch (error) {
|
|
1478
|
-
const message =
|
|
1566
|
+
const message = '[DynamicWaasWalletClient] Error in backupKeySharesToGoogleDrive';
|
|
1479
1567
|
const context = {
|
|
1480
|
-
accountAddress
|
|
1481
|
-
password,
|
|
1482
|
-
signedSessionId
|
|
1568
|
+
accountAddress
|
|
1483
1569
|
};
|
|
1484
1570
|
if (error instanceof axios.AxiosError) {
|
|
1485
1571
|
handleAxiosError(error, message, context);
|
|
@@ -1547,7 +1633,7 @@ class DynamicWalletClient {
|
|
|
1547
1633
|
});
|
|
1548
1634
|
return decryptedKeyShares;
|
|
1549
1635
|
} catch (error) {
|
|
1550
|
-
const message =
|
|
1636
|
+
const message = '[DynamicWaasWalletClient] Error in restoreBackupFromGoogleDrive';
|
|
1551
1637
|
const context = {
|
|
1552
1638
|
accountAddress
|
|
1553
1639
|
};
|
|
@@ -1743,7 +1829,7 @@ class DynamicWalletClient {
|
|
|
1743
1829
|
walletProperties: wallet == null ? void 0 : wallet.walletProperties
|
|
1744
1830
|
});
|
|
1745
1831
|
} catch (error) {
|
|
1746
|
-
const message =
|
|
1832
|
+
const message = '[DynamicWaasWalletClient] Error in getWalletClientKeyShareBackupInfo';
|
|
1747
1833
|
if (error instanceof axios.AxiosError) {
|
|
1748
1834
|
handleAxiosError(error, message, {
|
|
1749
1835
|
accountAddress
|
|
@@ -1775,7 +1861,7 @@ class DynamicWalletClient {
|
|
|
1775
1861
|
const walletProperties = wallet.walletProperties;
|
|
1776
1862
|
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1777
1863
|
walletId: wallet.id,
|
|
1778
|
-
chainName: wallet.
|
|
1864
|
+
chainName: core.verifiedCredentialNameToChainEnum[wallet.chain],
|
|
1779
1865
|
accountAddress,
|
|
1780
1866
|
thresholdSignatureScheme: walletProperties.thresholdSignatureScheme,
|
|
1781
1867
|
derivationPath: walletProperties.derivationPath,
|
|
@@ -1814,7 +1900,7 @@ class DynamicWalletClient {
|
|
|
1814
1900
|
}
|
|
1815
1901
|
return this.walletMap[accountAddress];
|
|
1816
1902
|
} catch (error) {
|
|
1817
|
-
const message =
|
|
1903
|
+
const message = '[DynamicWaasWalletClient] Error in getWallet';
|
|
1818
1904
|
const context = {
|
|
1819
1905
|
accountAddress,
|
|
1820
1906
|
walletOperation,
|
|
@@ -1862,7 +1948,7 @@ class DynamicWalletClient {
|
|
|
1862
1948
|
}, {});
|
|
1863
1949
|
return wallets;
|
|
1864
1950
|
} catch (error) {
|
|
1865
|
-
const message =
|
|
1951
|
+
const message = '[DynamicWaasWalletClient] Error in getWallets';
|
|
1866
1952
|
if (error instanceof axios.AxiosError) {
|
|
1867
1953
|
handleAxiosError(error, message, {});
|
|
1868
1954
|
}
|
package/index.esm.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { SigningAlgorithm, MPC_RELAY_PROD_API_URL, getMPCChainConfig, BackupLocation, getClientThreshold, MPC_CONFIG, getTSSConfig, WalletOperation, getReshareConfig, DynamicApiClient, getEnvironmentFromUrl, IFRAME_DOMAIN_MAP } from '@dynamic-labs-wallet/core';
|
|
1
|
+
import { SigningAlgorithm, MPC_RELAY_PROD_API_URL, getMPCChainConfig, BackupLocation, getClientThreshold, MPC_CONFIG, getTSSConfig, WalletOperation, getReshareConfig, ThresholdSignatureScheme, verifiedCredentialNameToChainEnum, DynamicApiClient, getEnvironmentFromUrl, IFRAME_DOMAIN_MAP } from '@dynamic-labs-wallet/core';
|
|
2
2
|
export * from '@dynamic-labs-wallet/core';
|
|
3
3
|
import { BIP340, ExportableEd25519, Ecdsa, MessageHash, EcdsaKeygenResult, ExportableEd25519KeygenResult, BIP340KeygenResult } from './internal/web';
|
|
4
4
|
export { BIP340, BIP340InitKeygenResult, BIP340KeygenResult, Ecdsa, EcdsaInitKeygenResult, EcdsaKeygenResult, EcdsaPublicKey, EcdsaSignature, Ed25519, Ed25519InitKeygenResult, Ed25519KeygenResult, MessageHash } from './internal/web';
|
|
5
|
-
import { ProviderEnum } from '@dynamic-labs/sdk-api-core';
|
|
6
5
|
import { LogLevel, Logger } from '@dynamic-labs/logger';
|
|
6
|
+
import { ProviderEnum } from '@dynamic-labs/sdk-api-core';
|
|
7
7
|
import { AxiosError } from 'axios';
|
|
8
8
|
import createHttpError from 'http-errors';
|
|
9
9
|
|
|
@@ -369,6 +369,89 @@ const downloadFileFromGoogleDrive = async ({ accessToken, fileName })=>{
|
|
|
369
369
|
}
|
|
370
370
|
};
|
|
371
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Updates the wallet map with backup information after successful backup to Google Drive
|
|
374
|
+
* @param data - Response data containing key shares information
|
|
375
|
+
* @param walletMap - The wallet map to update
|
|
376
|
+
* @param accountAddress - The account address associated with the wallet
|
|
377
|
+
* @param backupLocation - The location where the backup is stored
|
|
378
|
+
* @param storage - Storage interface for persisting the updated wallet map
|
|
379
|
+
* @param storageKey - Key used to store the wallet map
|
|
380
|
+
* @returns The array of key share IDs that were backed up
|
|
381
|
+
*/ const updateWalletMapWithBackupInfo = async ({ data, walletMap, accountAddress, storage, storageKey })=>{
|
|
382
|
+
const ids = data.keyShares.map((keyShare)=>keyShare.id);
|
|
383
|
+
walletMap[accountAddress].clientKeySharesBackupInfo.backups[BackupLocation.GOOGLE_DRIVE] = ids;
|
|
384
|
+
await storage.setItem(storageKey, JSON.stringify(walletMap));
|
|
385
|
+
return ids;
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* Uploads a backup to Google Drive App
|
|
389
|
+
* @param accessToken - The access token for the Google Drive API
|
|
390
|
+
* @param fileName - The name of the file to upload
|
|
391
|
+
* @param backupData - The data to upload
|
|
392
|
+
* @param accountAddress - The account address associated with the backup
|
|
393
|
+
*/ const uploadBackupToGoogleDrive = async ({ accessToken, fileName, backupData, accountAddress })=>{
|
|
394
|
+
const uploadPromises = [
|
|
395
|
+
retryPromise(()=>uploadFileToGoogleDriveAppStorage({
|
|
396
|
+
accessToken,
|
|
397
|
+
fileName,
|
|
398
|
+
jsonData: backupData
|
|
399
|
+
})),
|
|
400
|
+
retryPromise(()=>uploadFileToGoogleDrivePersonal({
|
|
401
|
+
accessToken,
|
|
402
|
+
fileName,
|
|
403
|
+
jsonData: backupData
|
|
404
|
+
}))
|
|
405
|
+
];
|
|
406
|
+
const results = await Promise.allSettled(uploadPromises);
|
|
407
|
+
const errors = [];
|
|
408
|
+
// Check App Storage result
|
|
409
|
+
if (results[0].status === 'rejected') {
|
|
410
|
+
const error = results[0].reason;
|
|
411
|
+
logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive App Storage', {
|
|
412
|
+
accountAddress,
|
|
413
|
+
error
|
|
414
|
+
});
|
|
415
|
+
errors.push(`Failed to backup keyshares to Google Drive App Storage: ${error instanceof Error ? error.message : String(error)}`);
|
|
416
|
+
}
|
|
417
|
+
// Check Personal Drive result
|
|
418
|
+
if (results[1].status === 'rejected') {
|
|
419
|
+
const error = results[1].reason;
|
|
420
|
+
logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive Personal', {
|
|
421
|
+
accountAddress,
|
|
422
|
+
error
|
|
423
|
+
});
|
|
424
|
+
errors.push(`Failed to backup keyshares to Google Drive Personal: ${error instanceof Error ? error.message : String(error)}`);
|
|
425
|
+
}
|
|
426
|
+
// Throw if any uploads failed
|
|
427
|
+
if (errors.length > 0) {
|
|
428
|
+
throw new Error(`[DynamicWaasWalletClient] ${errors.join('; ')}`);
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const handleAxiosError = (error, message, context)=>{
|
|
433
|
+
var _error_response, _error_response1;
|
|
434
|
+
logger.debug("[DynamicWaasWalletClient] Axios error: " + message, {
|
|
435
|
+
error: (_error_response = error.response) == null ? void 0 : _error_response.status,
|
|
436
|
+
message: error.message,
|
|
437
|
+
context
|
|
438
|
+
});
|
|
439
|
+
switch((_error_response1 = error.response) == null ? void 0 : _error_response1.status){
|
|
440
|
+
case 400:
|
|
441
|
+
throw createHttpError(400, 'Invalid request');
|
|
442
|
+
case 401:
|
|
443
|
+
throw createHttpError(401, 'Authorization header or cookie is required');
|
|
444
|
+
case 403:
|
|
445
|
+
throw createHttpError(403, 'Forbidden');
|
|
446
|
+
case 422:
|
|
447
|
+
throw createHttpError(422, 'Unprocessable content');
|
|
448
|
+
case 500:
|
|
449
|
+
throw createHttpError(500, 'Internal server error');
|
|
450
|
+
default:
|
|
451
|
+
throw createHttpError(500, 'Internal server error');
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
|
|
372
455
|
const localStorageWriteTest = {
|
|
373
456
|
tested: false,
|
|
374
457
|
writable: false
|
|
@@ -438,79 +521,6 @@ const localStorageWriteTest = {
|
|
|
438
521
|
}
|
|
439
522
|
});
|
|
440
523
|
|
|
441
|
-
/**
|
|
442
|
-
* Updates the wallet map with backup information after successful backup to Google Drive
|
|
443
|
-
* @param data - Response data containing key shares information
|
|
444
|
-
* @param walletMap - The wallet map to update
|
|
445
|
-
* @param accountAddress - The account address associated with the wallet
|
|
446
|
-
* @param backupLocation - The location where the backup is stored
|
|
447
|
-
* @param storage - Storage interface for persisting the updated wallet map
|
|
448
|
-
* @param storageKey - Key used to store the wallet map
|
|
449
|
-
* @returns The array of key share IDs that were backed up
|
|
450
|
-
*/ const updateWalletMapWithBackupInfo = async ({ data, walletMap, accountAddress, storage, storageKey })=>{
|
|
451
|
-
const ids = data.keyShares.map((keyShare)=>keyShare.id);
|
|
452
|
-
walletMap[accountAddress].clientKeySharesBackupInfo.backups[BackupLocation.GOOGLE_DRIVE] = ids;
|
|
453
|
-
await storage.setItem(storageKey, JSON.stringify(walletMap));
|
|
454
|
-
return ids;
|
|
455
|
-
};
|
|
456
|
-
/**
|
|
457
|
-
* Uploads a backup to Google Drive App
|
|
458
|
-
* @param accessToken - The access token for the Google Drive API
|
|
459
|
-
* @param fileName - The name of the file to upload
|
|
460
|
-
* @param backupData - The data to upload
|
|
461
|
-
* @param accountAddress - The account address associated with the backup
|
|
462
|
-
*/ const uploadBackupToGoogleDrive = async ({ accessToken, fileName, backupData, accountAddress })=>{
|
|
463
|
-
try {
|
|
464
|
-
await retryPromise(()=>uploadFileToGoogleDriveAppStorage({
|
|
465
|
-
accessToken,
|
|
466
|
-
fileName,
|
|
467
|
-
jsonData: backupData
|
|
468
|
-
}));
|
|
469
|
-
} catch (error) {
|
|
470
|
-
logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive App Storage', {
|
|
471
|
-
accountAddress,
|
|
472
|
-
error
|
|
473
|
-
});
|
|
474
|
-
throw new Error(`[DynamicWaasWalletClient] Failed to backup keyshares to Google Drive App Storage: ${error instanceof Error ? error.message : String(error)}`);
|
|
475
|
-
}
|
|
476
|
-
try {
|
|
477
|
-
await retryPromise(()=>uploadFileToGoogleDrivePersonal({
|
|
478
|
-
accessToken,
|
|
479
|
-
fileName,
|
|
480
|
-
jsonData: backupData
|
|
481
|
-
}));
|
|
482
|
-
} catch (error) {
|
|
483
|
-
logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive Personal', {
|
|
484
|
-
accountAddress,
|
|
485
|
-
error
|
|
486
|
-
});
|
|
487
|
-
throw new Error(`[DynamicWaasWalletClient] Failed to backup keyshares to Google Drive Personal: ${error instanceof Error ? error.message : String(error)}`);
|
|
488
|
-
}
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
const handleAxiosError = (error, message, context)=>{
|
|
492
|
-
var _error_response, _error_response1;
|
|
493
|
-
logger.debug("[DynamicWaasWalletClient] Axios error: " + message, {
|
|
494
|
-
error: (_error_response = error.response) == null ? void 0 : _error_response.status,
|
|
495
|
-
message: error.message,
|
|
496
|
-
context
|
|
497
|
-
});
|
|
498
|
-
switch((_error_response1 = error.response) == null ? void 0 : _error_response1.status){
|
|
499
|
-
case 400:
|
|
500
|
-
throw createHttpError(400, 'Invalid request');
|
|
501
|
-
case 401:
|
|
502
|
-
throw createHttpError(401, 'Authorization header or cookie is required');
|
|
503
|
-
case 403:
|
|
504
|
-
throw createHttpError(403, 'Forbidden');
|
|
505
|
-
case 422:
|
|
506
|
-
throw createHttpError(422, 'Unprocessable content');
|
|
507
|
-
case 500:
|
|
508
|
-
throw createHttpError(500, 'Internal server error');
|
|
509
|
-
default:
|
|
510
|
-
throw createHttpError(500, 'Internal server error');
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
|
|
514
524
|
class DynamicWalletClient {
|
|
515
525
|
async initialize() {
|
|
516
526
|
if (this.initializePromise) {
|
|
@@ -659,7 +669,7 @@ class DynamicWalletClient {
|
|
|
659
669
|
clientKeyShares
|
|
660
670
|
};
|
|
661
671
|
} catch (error) {
|
|
662
|
-
const message =
|
|
672
|
+
const message = '[DynamicWaasWalletClient] Error in keyGen';
|
|
663
673
|
const context = {
|
|
664
674
|
chainName,
|
|
665
675
|
thresholdSignatureScheme
|
|
@@ -740,7 +750,7 @@ class DynamicWalletClient {
|
|
|
740
750
|
clientKeyShares: clientKeygenResults
|
|
741
751
|
};
|
|
742
752
|
} catch (error) {
|
|
743
|
-
const message =
|
|
753
|
+
const message = '[DynamicWaasWalletClient] Error in importRawPrivateKey';
|
|
744
754
|
const context = {
|
|
745
755
|
chainName,
|
|
746
756
|
thresholdSignatureScheme
|
|
@@ -843,7 +853,7 @@ class DynamicWalletClient {
|
|
|
843
853
|
});
|
|
844
854
|
return signature;
|
|
845
855
|
} catch (error) {
|
|
846
|
-
const message =
|
|
856
|
+
const message = '[DynamicWaasWalletClient] Error in sign';
|
|
847
857
|
const context = {
|
|
848
858
|
accountAddress,
|
|
849
859
|
chainName,
|
|
@@ -886,9 +896,6 @@ class DynamicWalletClient {
|
|
|
886
896
|
accountAddress
|
|
887
897
|
});
|
|
888
898
|
const refreshResults = await Promise.all(clientKeyShares.map((clientKeyShare)=>mpcSigner.refresh(roomId, clientKeyShare)));
|
|
889
|
-
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
890
|
-
clientKeySharesBackupInfo: getClientKeyShareBackupInfo()
|
|
891
|
-
});
|
|
892
899
|
await this.setClientKeySharesToLocalStorage({
|
|
893
900
|
accountAddress,
|
|
894
901
|
clientKeyShares: refreshResults,
|
|
@@ -900,7 +907,7 @@ class DynamicWalletClient {
|
|
|
900
907
|
signedSessionId
|
|
901
908
|
});
|
|
902
909
|
} catch (error) {
|
|
903
|
-
const message =
|
|
910
|
+
const message = '[DynamicWaasWalletClient] Error in refreshWalletAccountShares';
|
|
904
911
|
const context = {
|
|
905
912
|
accountAddress,
|
|
906
913
|
chainName
|
|
@@ -966,7 +973,7 @@ class DynamicWalletClient {
|
|
|
966
973
|
existingClientKeyShares
|
|
967
974
|
};
|
|
968
975
|
}
|
|
969
|
-
async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId }) {
|
|
976
|
+
async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId, backupToGoogleDrive = false }) {
|
|
970
977
|
try {
|
|
971
978
|
await this.verifyPassword({
|
|
972
979
|
accountAddress,
|
|
@@ -1020,6 +1027,9 @@ class DynamicWalletClient {
|
|
|
1020
1027
|
...newClientInitKeygenResults.map((keygenResult)=>mpcSigner.reshareNewParty(roomId, oldMpcConfig.threshold, newMpcConfig.threshold, keygenResult, allPartyKeygenIds)),
|
|
1021
1028
|
...existingClientKeyShares.map((keyShare)=>mpcSigner.reshareRemainingParty(roomId, newMpcConfig.threshold, keyShare, allPartyKeygenIds))
|
|
1022
1029
|
]);
|
|
1030
|
+
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1031
|
+
thresholdSignatureScheme: newThresholdSignatureScheme
|
|
1032
|
+
});
|
|
1023
1033
|
await this.setClientKeySharesToLocalStorage({
|
|
1024
1034
|
accountAddress,
|
|
1025
1035
|
clientKeyShares: reshareResults,
|
|
@@ -1028,10 +1038,11 @@ class DynamicWalletClient {
|
|
|
1028
1038
|
await this.storeEncryptedBackupByWallet({
|
|
1029
1039
|
accountAddress,
|
|
1030
1040
|
password,
|
|
1031
|
-
signedSessionId
|
|
1041
|
+
signedSessionId,
|
|
1042
|
+
backupToGoogleDrive
|
|
1032
1043
|
});
|
|
1033
1044
|
} catch (error) {
|
|
1034
|
-
const message =
|
|
1045
|
+
const message = '[DynamicWaasWalletClient] Error in reshare';
|
|
1035
1046
|
const context = {
|
|
1036
1047
|
accountAddress,
|
|
1037
1048
|
chainName,
|
|
@@ -1102,7 +1113,7 @@ class DynamicWalletClient {
|
|
|
1102
1113
|
derivedPrivateKey
|
|
1103
1114
|
};
|
|
1104
1115
|
} catch (error) {
|
|
1105
|
-
const message =
|
|
1116
|
+
const message = '[DynamicWaasWalletClient] Error in exportKey';
|
|
1106
1117
|
const context = {
|
|
1107
1118
|
accountAddress,
|
|
1108
1119
|
chainName
|
|
@@ -1201,48 +1212,71 @@ class DynamicWalletClient {
|
|
|
1201
1212
|
await ((_this_storage = this.storage) == null ? void 0 : _this_storage.setItem(accountAddress, stringifiedClientKeyShares));
|
|
1202
1213
|
}
|
|
1203
1214
|
/**
|
|
1204
|
-
*
|
|
1215
|
+
* Central backup orchestrator that encrypts and stores wallet key shares.
|
|
1205
1216
|
*
|
|
1206
|
-
* This method
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
1217
|
+
* This method serves as the main backup coordinator, handling the distribution of encrypted
|
|
1218
|
+
* key shares between Dynamic's backend and Google Drive based on the wallet's threshold scheme.
|
|
1219
|
+
* It is used by multiple operations including reshare, refresh, and manual backup requests.
|
|
1209
1220
|
*
|
|
1210
|
-
*
|
|
1221
|
+
* **Backup Distribution Strategy:**
|
|
1222
|
+
* - **Single share wallets**: All shares stored on Dynamic's backend only
|
|
1223
|
+
* - **Multi-share wallets (2+)**: When backing up to Google Drive, N-1 shares on Dynamic's backend, 1 share on Google Drive
|
|
1224
|
+
* - **Multi-share wallets (2+)**: When not backing up to Google Drive, all shares on Dynamic's backend
|
|
1225
|
+
*
|
|
1226
|
+
* **Process Flow:**
|
|
1211
1227
|
* 1. Encrypts all client key shares with the provided password (or environment ID if no password)
|
|
1212
|
-
* 2.
|
|
1213
|
-
* 3.
|
|
1214
|
-
* 4. Updates
|
|
1215
|
-
* 5. Persists the updated wallet map to storage
|
|
1228
|
+
* 2. For multi-share wallets (2+): conditionally distributes N-1 to backend, 1 to Google Drive
|
|
1229
|
+
* 3. For other configurations: stores all shares on Dynamic's backend
|
|
1230
|
+
* 4. Updates backup metadata and synchronizes wallet state
|
|
1231
|
+
* 5. Persists the updated wallet map to local storage
|
|
1216
1232
|
*
|
|
1217
|
-
* @param
|
|
1218
|
-
* @param
|
|
1219
|
-
* @param
|
|
1220
|
-
|
|
1233
|
+
* @param params - The backup operation parameters
|
|
1234
|
+
* @param params.accountAddress - The account address of the wallet to backup
|
|
1235
|
+
* @param params.clientKeyShares - Optional specific key shares to backup (uses localStorage if not provided)
|
|
1236
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1237
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
1238
|
+
* @param params.backupToGoogleDrive - Whether to backup to Google Drive (defaults to false)
|
|
1239
|
+
* @returns Promise with backup metadata including share locations and IDs
|
|
1240
|
+
*/ async storeEncryptedBackupByWallet({ accountAddress, clientKeyShares = undefined, password = undefined, signedSessionId, backupToGoogleDrive = false }) {
|
|
1221
1241
|
try {
|
|
1222
1242
|
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
1223
1243
|
accountAddress
|
|
1224
1244
|
});
|
|
1225
|
-
const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
|
|
1226
|
-
keyShare,
|
|
1227
|
-
password
|
|
1228
|
-
})));
|
|
1229
1245
|
if (!this.walletMap[accountAddress].walletId) {
|
|
1230
1246
|
this.logger.error(`[DynamicWaasWalletClient] WalletId not found for accountAddress: ${accountAddress}`);
|
|
1231
1247
|
throw new Error(`WalletId not found for accountAddress: ${accountAddress}`);
|
|
1232
1248
|
}
|
|
1233
1249
|
// TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
|
|
1250
|
+
let dynamicClientKeyShares = [];
|
|
1251
|
+
let googleDriveKeyShares = [];
|
|
1252
|
+
const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
|
|
1253
|
+
keyShare,
|
|
1254
|
+
password
|
|
1255
|
+
})));
|
|
1256
|
+
const hasExistingGoogleDriveBackup = this.walletMap[accountAddress].clientKeySharesBackupInfo.backups[BackupLocation.GOOGLE_DRIVE].length > 0;
|
|
1257
|
+
// Backup to Google Drive if:
|
|
1258
|
+
// 1. Explicitly requested via flag, OR
|
|
1259
|
+
// 2. User already has Google Drive backups
|
|
1260
|
+
const shouldBackupToGoogleDrive = backupToGoogleDrive || hasExistingGoogleDriveBackup;
|
|
1261
|
+
if (shouldBackupToGoogleDrive && keySharesToBackup.length >= 2) {
|
|
1262
|
+
// For 2 shares: 1 to backend, 1 to Google Drive
|
|
1263
|
+
// For 3+ shares: N-1 to backend, 1 to Google Drive
|
|
1264
|
+
const googleDriveShareCount = 1;
|
|
1265
|
+
dynamicClientKeyShares = encryptedKeyShares.slice(0, -googleDriveShareCount);
|
|
1266
|
+
googleDriveKeyShares = encryptedKeyShares.slice(-googleDriveShareCount);
|
|
1267
|
+
} else {
|
|
1268
|
+
dynamicClientKeyShares = encryptedKeyShares;
|
|
1269
|
+
}
|
|
1234
1270
|
const data = await this.apiClient.storeEncryptedBackupByWallet({
|
|
1235
1271
|
walletId: this.walletMap[accountAddress].walletId,
|
|
1236
|
-
encryptedKeyShares,
|
|
1272
|
+
encryptedKeyShares: dynamicClientKeyShares,
|
|
1237
1273
|
passwordEncrypted: Boolean(password) && password !== this.environmentId,
|
|
1238
1274
|
signedSessionId
|
|
1239
1275
|
});
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
const googleDriveKeyShareIds = await this.backupKeySharesToGoogleDrive({
|
|
1276
|
+
if (googleDriveKeyShares.length > 0) {
|
|
1277
|
+
const googleDriveKeyShareIds = await this.uploadKeySharesToGoogleDrive({
|
|
1243
1278
|
accountAddress,
|
|
1244
|
-
|
|
1245
|
-
signedSessionId
|
|
1279
|
+
encryptedKeyShares: googleDriveKeyShares
|
|
1246
1280
|
});
|
|
1247
1281
|
data.keyShares.push({
|
|
1248
1282
|
backupLocation: BackupLocation.GOOGLE_DRIVE,
|
|
@@ -1262,7 +1296,7 @@ class DynamicWalletClient {
|
|
|
1262
1296
|
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
1263
1297
|
return data;
|
|
1264
1298
|
} catch (error) {
|
|
1265
|
-
const message =
|
|
1299
|
+
const message = '[DynamicWaasWalletClient] Error in storeEncryptedBackupByWallet';
|
|
1266
1300
|
const context = {
|
|
1267
1301
|
accountAddress
|
|
1268
1302
|
};
|
|
@@ -1329,7 +1363,7 @@ class DynamicWalletClient {
|
|
|
1329
1363
|
}
|
|
1330
1364
|
return oauthAccountId;
|
|
1331
1365
|
} catch (error) {
|
|
1332
|
-
const message =
|
|
1366
|
+
const message = '[DynamicWaasWalletClient] Error in getGoogleOauthAccountIdOrThrow';
|
|
1333
1367
|
if (error instanceof AxiosError) {
|
|
1334
1368
|
handleAxiosError(error, message, {
|
|
1335
1369
|
accountAddress
|
|
@@ -1400,7 +1434,7 @@ class DynamicWalletClient {
|
|
|
1400
1434
|
}
|
|
1401
1435
|
return decryptedKeyShares;
|
|
1402
1436
|
} catch (error) {
|
|
1403
|
-
const message =
|
|
1437
|
+
const message = '[DynamicWaasWalletClient] Error in recoverEncryptedBackupByWallet';
|
|
1404
1438
|
const context = {
|
|
1405
1439
|
accountAddress,
|
|
1406
1440
|
password,
|
|
@@ -1426,7 +1460,17 @@ class DynamicWalletClient {
|
|
|
1426
1460
|
}
|
|
1427
1461
|
this.walletMap = JSON.parse(wallets);
|
|
1428
1462
|
}
|
|
1429
|
-
|
|
1463
|
+
/**
|
|
1464
|
+
* This method handles the complete flow for ensuring wallet key shares are backed up to Google Drive:
|
|
1465
|
+
* - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to Google Drive)
|
|
1466
|
+
* - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and Google Drive
|
|
1467
|
+
*
|
|
1468
|
+
* @param params - The backup parameters
|
|
1469
|
+
* @param params.accountAddress - The wallet account address to backup
|
|
1470
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1471
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
1472
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were backed up
|
|
1473
|
+
*/ async backupKeySharesToGoogleDrive({ accountAddress, password, signedSessionId }) {
|
|
1430
1474
|
try {
|
|
1431
1475
|
await this.getWallet({
|
|
1432
1476
|
accountAddress,
|
|
@@ -1434,16 +1478,59 @@ class DynamicWalletClient {
|
|
|
1434
1478
|
password,
|
|
1435
1479
|
signedSessionId
|
|
1436
1480
|
});
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1481
|
+
const currentThresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
|
|
1482
|
+
if (currentThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO) {
|
|
1483
|
+
// Reshare to 2-of-3, which will automatically handle the backup distribution
|
|
1484
|
+
await this.reshare({
|
|
1485
|
+
chainName: this.walletMap[accountAddress].chainName,
|
|
1486
|
+
accountAddress,
|
|
1487
|
+
oldThresholdSignatureScheme: currentThresholdSignatureScheme,
|
|
1488
|
+
newThresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_THREE,
|
|
1489
|
+
password,
|
|
1490
|
+
signedSessionId,
|
|
1491
|
+
backupToGoogleDrive: true
|
|
1492
|
+
});
|
|
1493
|
+
const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
|
|
1494
|
+
const googleDriveShares = backupInfo.backups[BackupLocation.GOOGLE_DRIVE] || [];
|
|
1495
|
+
return googleDriveShares;
|
|
1496
|
+
} else {
|
|
1497
|
+
// Already 2-of-3, only call backup
|
|
1498
|
+
const data = await this.storeEncryptedBackupByWallet({
|
|
1499
|
+
accountAddress,
|
|
1500
|
+
password,
|
|
1501
|
+
signedSessionId,
|
|
1502
|
+
backupToGoogleDrive: true
|
|
1503
|
+
});
|
|
1504
|
+
const googleDriveKeyShares = data.keyShares.filter((ks)=>ks.backupLocation === BackupLocation.GOOGLE_DRIVE);
|
|
1505
|
+
return googleDriveKeyShares.map((ks)=>ks.id);
|
|
1506
|
+
}
|
|
1507
|
+
} catch (error) {
|
|
1508
|
+
this.logger.error('[DynamicWaasWalletClient]: Error in backupKeySharesToGoogleDrive', error);
|
|
1509
|
+
if (error instanceof AxiosError) {
|
|
1510
|
+
const message = '[DynamicWaasWalletClient] Error in backupKeySharesToGoogleDrive';
|
|
1511
|
+
handleAxiosError(error, message, {
|
|
1512
|
+
accountAddress
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
throw error;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* This method handles only the Google Drive upload mechanics without any reshare logic.
|
|
1520
|
+
* It encrypts the provided key shares, uploads them to Google Drive, and updates the
|
|
1521
|
+
* backup metadata. This method is intended for internal use by storeEncryptedBackupByWallet
|
|
1522
|
+
* and should not be called directly from external code.
|
|
1523
|
+
*
|
|
1524
|
+
* @param params - The upload parameters
|
|
1525
|
+
* @param params.accountAddress - The wallet account address
|
|
1526
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1527
|
+
* @param params.encryptedKeyShares - The specific key shares to upload to Google Drive
|
|
1528
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were uploaded
|
|
1529
|
+
*/ async uploadKeySharesToGoogleDrive({ accountAddress, encryptedKeyShares }) {
|
|
1530
|
+
try {
|
|
1531
|
+
if (encryptedKeyShares.length === 0) {
|
|
1441
1532
|
throw new Error('No key shares found');
|
|
1442
1533
|
}
|
|
1443
|
-
const encryptedKeyShares = await Promise.all(clientKeyShares.map((keyShare)=>this.encryptKeyShare({
|
|
1444
|
-
keyShare,
|
|
1445
|
-
password
|
|
1446
|
-
})));
|
|
1447
1534
|
const oauthAccountId = await this.getGoogleOauthAccountIdOrThrow(accountAddress);
|
|
1448
1535
|
const accessToken = await this.apiClient.getAccessToken({
|
|
1449
1536
|
oauthAccountId
|
|
@@ -1474,12 +1561,11 @@ class DynamicWalletClient {
|
|
|
1474
1561
|
storage: this.storage,
|
|
1475
1562
|
storageKey: this.storageKey
|
|
1476
1563
|
});
|
|
1564
|
+
return data.keyShares.map((ks)=>ks.id);
|
|
1477
1565
|
} catch (error) {
|
|
1478
|
-
const message =
|
|
1566
|
+
const message = '[DynamicWaasWalletClient] Error in backupKeySharesToGoogleDrive';
|
|
1479
1567
|
const context = {
|
|
1480
|
-
accountAddress
|
|
1481
|
-
password,
|
|
1482
|
-
signedSessionId
|
|
1568
|
+
accountAddress
|
|
1483
1569
|
};
|
|
1484
1570
|
if (error instanceof AxiosError) {
|
|
1485
1571
|
handleAxiosError(error, message, context);
|
|
@@ -1547,7 +1633,7 @@ class DynamicWalletClient {
|
|
|
1547
1633
|
});
|
|
1548
1634
|
return decryptedKeyShares;
|
|
1549
1635
|
} catch (error) {
|
|
1550
|
-
const message =
|
|
1636
|
+
const message = '[DynamicWaasWalletClient] Error in restoreBackupFromGoogleDrive';
|
|
1551
1637
|
const context = {
|
|
1552
1638
|
accountAddress
|
|
1553
1639
|
};
|
|
@@ -1743,7 +1829,7 @@ class DynamicWalletClient {
|
|
|
1743
1829
|
walletProperties: wallet == null ? void 0 : wallet.walletProperties
|
|
1744
1830
|
});
|
|
1745
1831
|
} catch (error) {
|
|
1746
|
-
const message =
|
|
1832
|
+
const message = '[DynamicWaasWalletClient] Error in getWalletClientKeyShareBackupInfo';
|
|
1747
1833
|
if (error instanceof AxiosError) {
|
|
1748
1834
|
handleAxiosError(error, message, {
|
|
1749
1835
|
accountAddress
|
|
@@ -1775,7 +1861,7 @@ class DynamicWalletClient {
|
|
|
1775
1861
|
const walletProperties = wallet.walletProperties;
|
|
1776
1862
|
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1777
1863
|
walletId: wallet.id,
|
|
1778
|
-
chainName: wallet.
|
|
1864
|
+
chainName: verifiedCredentialNameToChainEnum[wallet.chain],
|
|
1779
1865
|
accountAddress,
|
|
1780
1866
|
thresholdSignatureScheme: walletProperties.thresholdSignatureScheme,
|
|
1781
1867
|
derivationPath: walletProperties.derivationPath,
|
|
@@ -1814,7 +1900,7 @@ class DynamicWalletClient {
|
|
|
1814
1900
|
}
|
|
1815
1901
|
return this.walletMap[accountAddress];
|
|
1816
1902
|
} catch (error) {
|
|
1817
|
-
const message =
|
|
1903
|
+
const message = '[DynamicWaasWalletClient] Error in getWallet';
|
|
1818
1904
|
const context = {
|
|
1819
1905
|
accountAddress,
|
|
1820
1906
|
walletOperation,
|
|
@@ -1862,7 +1948,7 @@ class DynamicWalletClient {
|
|
|
1862
1948
|
}, {});
|
|
1863
1949
|
return wallets;
|
|
1864
1950
|
} catch (error) {
|
|
1865
|
-
const message =
|
|
1951
|
+
const message = '[DynamicWaasWalletClient] Error in getWallets';
|
|
1866
1952
|
if (error instanceof AxiosError) {
|
|
1867
1953
|
handleAxiosError(error, message, {});
|
|
1868
1954
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs-wallet/browser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.94",
|
|
4
4
|
"license": "Licensed under the Dynamic Labs, Inc. Terms Of Service (https://www.dynamic.xyz/terms-conditions)",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@dynamic-labs-wallet/core": "0.0.
|
|
6
|
+
"@dynamic-labs-wallet/core": "0.0.94",
|
|
7
7
|
"@dynamic-labs/logger": "^4.9.9",
|
|
8
8
|
"@dynamic-labs/sdk-api-core": "^0.0.663",
|
|
9
9
|
"axios": "1.9.0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/backup/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/backup/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAOjD;;;;;;;;;GASG;AACH,eAAO,MAAM,6BAA6B,8DAMvC;IACD,IAAI,EAAE;QAAE,SAAS,EAAE,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,KAAG,OAAO,CAAC,MAAM,EAAE,CAQnB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,2DAKnC;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,GAAG,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB,kBA2DA,CAAC"}
|
package/src/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { BackupLocation, DynamicApiClient, type DynamicWalletClientProps, type InitializeResult, type KeyShareBackupInfo, ThresholdSignatureScheme, WalletOperation } from '@dynamic-labs-wallet/core';
|
|
2
|
+
import { BIP340KeygenResult, EcdsaKeygenResult, type EcdsaPublicKey, type EcdsaSignature, ExportableEd25519 } from '../../internal/web';
|
|
3
3
|
import type { ClientInitKeygenResult, ClientKeyShare } from './mpc/types';
|
|
4
4
|
import { type SupportedStorage } from './services/localStorage';
|
|
5
5
|
import type { WalletProperties } from './types';
|
|
@@ -127,13 +127,14 @@ export declare class DynamicWalletClient {
|
|
|
127
127
|
existingClientKeygenIds: string[];
|
|
128
128
|
existingClientKeyShares: ClientKeyShare[];
|
|
129
129
|
}>;
|
|
130
|
-
reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password, signedSessionId, }: {
|
|
130
|
+
reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password, signedSessionId, backupToGoogleDrive, }: {
|
|
131
131
|
chainName: string;
|
|
132
132
|
accountAddress: string;
|
|
133
133
|
oldThresholdSignatureScheme: ThresholdSignatureScheme;
|
|
134
134
|
newThresholdSignatureScheme: ThresholdSignatureScheme;
|
|
135
135
|
password?: string;
|
|
136
136
|
signedSessionId?: string;
|
|
137
|
+
backupToGoogleDrive?: boolean;
|
|
137
138
|
}): Promise<void>;
|
|
138
139
|
exportKey({ accountAddress, chainName, password, signedSessionId, }: {
|
|
139
140
|
accountAddress: string;
|
|
@@ -170,28 +171,38 @@ export declare class DynamicWalletClient {
|
|
|
170
171
|
overwriteOrMerge?: 'overwrite' | 'merge';
|
|
171
172
|
}): Promise<void>;
|
|
172
173
|
/**
|
|
173
|
-
*
|
|
174
|
+
* Central backup orchestrator that encrypts and stores wallet key shares.
|
|
174
175
|
*
|
|
175
|
-
* This method
|
|
176
|
-
*
|
|
177
|
-
*
|
|
176
|
+
* This method serves as the main backup coordinator, handling the distribution of encrypted
|
|
177
|
+
* key shares between Dynamic's backend and Google Drive based on the wallet's threshold scheme.
|
|
178
|
+
* It is used by multiple operations including reshare, refresh, and manual backup requests.
|
|
178
179
|
*
|
|
179
|
-
*
|
|
180
|
+
* **Backup Distribution Strategy:**
|
|
181
|
+
* - **Single share wallets**: All shares stored on Dynamic's backend only
|
|
182
|
+
* - **Multi-share wallets (2+)**: When backing up to Google Drive, N-1 shares on Dynamic's backend, 1 share on Google Drive
|
|
183
|
+
* - **Multi-share wallets (2+)**: When not backing up to Google Drive, all shares on Dynamic's backend
|
|
184
|
+
*
|
|
185
|
+
* **Process Flow:**
|
|
180
186
|
* 1. Encrypts all client key shares with the provided password (or environment ID if no password)
|
|
181
|
-
* 2.
|
|
182
|
-
* 3.
|
|
183
|
-
* 4. Updates
|
|
184
|
-
* 5. Persists the updated wallet map to storage
|
|
187
|
+
* 2. For multi-share wallets (2+): conditionally distributes N-1 to backend, 1 to Google Drive
|
|
188
|
+
* 3. For other configurations: stores all shares on Dynamic's backend
|
|
189
|
+
* 4. Updates backup metadata and synchronizes wallet state
|
|
190
|
+
* 5. Persists the updated wallet map to local storage
|
|
185
191
|
*
|
|
186
|
-
* @param
|
|
187
|
-
* @param
|
|
188
|
-
* @param
|
|
192
|
+
* @param params - The backup operation parameters
|
|
193
|
+
* @param params.accountAddress - The account address of the wallet to backup
|
|
194
|
+
* @param params.clientKeyShares - Optional specific key shares to backup (uses localStorage if not provided)
|
|
195
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
196
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
197
|
+
* @param params.backupToGoogleDrive - Whether to backup to Google Drive (defaults to false)
|
|
198
|
+
* @returns Promise with backup metadata including share locations and IDs
|
|
189
199
|
*/
|
|
190
|
-
storeEncryptedBackupByWallet({ accountAddress, clientKeyShares, password, signedSessionId, }: {
|
|
200
|
+
storeEncryptedBackupByWallet({ accountAddress, clientKeyShares, password, signedSessionId, backupToGoogleDrive, }: {
|
|
191
201
|
accountAddress: string;
|
|
192
202
|
clientKeyShares?: ClientKeyShare[];
|
|
193
203
|
password?: string;
|
|
194
204
|
signedSessionId?: string;
|
|
205
|
+
backupToGoogleDrive?: boolean;
|
|
195
206
|
}): Promise<any>;
|
|
196
207
|
storeEncryptedBackupByWalletWithRetry({ accountAddress, clientKeyShares, password, signedSessionId, }: {
|
|
197
208
|
accountAddress: string;
|
|
@@ -246,11 +257,35 @@ export declare class DynamicWalletClient {
|
|
|
246
257
|
storeRecoveredShares?: boolean;
|
|
247
258
|
}): Promise<any[]>;
|
|
248
259
|
restoreWallets(): Promise<void>;
|
|
260
|
+
/**
|
|
261
|
+
* This method handles the complete flow for ensuring wallet key shares are backed up to Google Drive:
|
|
262
|
+
* - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to Google Drive)
|
|
263
|
+
* - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and Google Drive
|
|
264
|
+
*
|
|
265
|
+
* @param params - The backup parameters
|
|
266
|
+
* @param params.accountAddress - The wallet account address to backup
|
|
267
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
268
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
269
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were backed up
|
|
270
|
+
*/
|
|
249
271
|
backupKeySharesToGoogleDrive({ accountAddress, password, signedSessionId, }: {
|
|
250
272
|
accountAddress: string;
|
|
251
273
|
password?: string;
|
|
252
274
|
signedSessionId?: string;
|
|
253
|
-
}): Promise<
|
|
275
|
+
}): Promise<string[]>;
|
|
276
|
+
/**
|
|
277
|
+
* This method handles only the Google Drive upload mechanics without any reshare logic.
|
|
278
|
+
* It encrypts the provided key shares, uploads them to Google Drive, and updates the
|
|
279
|
+
* backup metadata. This method is intended for internal use by storeEncryptedBackupByWallet
|
|
280
|
+
* and should not be called directly from external code.
|
|
281
|
+
*
|
|
282
|
+
* @param params - The upload parameters
|
|
283
|
+
* @param params.accountAddress - The wallet account address
|
|
284
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
285
|
+
* @param params.encryptedKeyShares - The specific key shares to upload to Google Drive
|
|
286
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were uploaded
|
|
287
|
+
*/
|
|
288
|
+
private uploadKeySharesToGoogleDrive;
|
|
254
289
|
restoreBackupFromGoogleDrive({ accountAddress, password, signedSessionId, }: {
|
|
255
290
|
accountAddress: string;
|
|
256
291
|
password?: string;
|
package/src/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../packages/src/client.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../packages/src/client.ts"],"names":[],"mappings":"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"}
|