@dynamic-labs-wallet/browser 0.0.93 → 0.0.95
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 +221 -129
- package/index.esm.js +222 -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,77 @@ 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.
|
|
1216
|
+
*
|
|
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.
|
|
1205
1220
|
*
|
|
1206
|
-
*
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
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
|
|
1209
1225
|
*
|
|
1210
|
-
*
|
|
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 {
|
|
1242
|
+
var _this_walletMap_accountAddress;
|
|
1222
1243
|
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
1223
1244
|
accountAddress
|
|
1224
1245
|
});
|
|
1246
|
+
if (!((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.walletId)) {
|
|
1247
|
+
this.logger.error('[DynamicWaasWalletClient] Error in storeEncryptedBackupByWallet, wallet or walletId not found from the wallet map', {
|
|
1248
|
+
context: {
|
|
1249
|
+
accountAddress,
|
|
1250
|
+
walletMap: this.walletMap
|
|
1251
|
+
}
|
|
1252
|
+
});
|
|
1253
|
+
throw new Error(`WalletId not found for accountAddress ${accountAddress}`);
|
|
1254
|
+
}
|
|
1255
|
+
// TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
|
|
1256
|
+
let dynamicClientKeyShares = [];
|
|
1257
|
+
let googleDriveKeyShares = [];
|
|
1225
1258
|
const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
|
|
1226
1259
|
keyShare,
|
|
1227
1260
|
password
|
|
1228
1261
|
})));
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1262
|
+
const hasExistingGoogleDriveBackup = this.walletMap[accountAddress].clientKeySharesBackupInfo.backups[core.BackupLocation.GOOGLE_DRIVE].length > 0;
|
|
1263
|
+
// Backup to Google Drive if:
|
|
1264
|
+
// 1. Explicitly requested via flag, OR
|
|
1265
|
+
// 2. User already has Google Drive backups
|
|
1266
|
+
const shouldBackupToGoogleDrive = backupToGoogleDrive || hasExistingGoogleDriveBackup;
|
|
1267
|
+
if (shouldBackupToGoogleDrive && keySharesToBackup.length >= 2) {
|
|
1268
|
+
// For 2 shares: 1 to backend, 1 to Google Drive
|
|
1269
|
+
// For 3+ shares: N-1 to backend, 1 to Google Drive
|
|
1270
|
+
const googleDriveShareCount = 1;
|
|
1271
|
+
dynamicClientKeyShares = encryptedKeyShares.slice(0, -googleDriveShareCount);
|
|
1272
|
+
googleDriveKeyShares = encryptedKeyShares.slice(-googleDriveShareCount);
|
|
1273
|
+
} else {
|
|
1274
|
+
dynamicClientKeyShares = encryptedKeyShares;
|
|
1232
1275
|
}
|
|
1233
|
-
// TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
|
|
1234
1276
|
const data = await this.apiClient.storeEncryptedBackupByWallet({
|
|
1235
1277
|
walletId: this.walletMap[accountAddress].walletId,
|
|
1236
|
-
encryptedKeyShares,
|
|
1278
|
+
encryptedKeyShares: dynamicClientKeyShares,
|
|
1237
1279
|
passwordEncrypted: Boolean(password) && password !== this.environmentId,
|
|
1238
1280
|
signedSessionId
|
|
1239
1281
|
});
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
const googleDriveKeyShareIds = await this.backupKeySharesToGoogleDrive({
|
|
1282
|
+
if (googleDriveKeyShares.length > 0) {
|
|
1283
|
+
const googleDriveKeyShareIds = await this.uploadKeySharesToGoogleDrive({
|
|
1243
1284
|
accountAddress,
|
|
1244
|
-
|
|
1245
|
-
signedSessionId
|
|
1285
|
+
encryptedKeyShares: googleDriveKeyShares
|
|
1246
1286
|
});
|
|
1247
1287
|
data.keyShares.push({
|
|
1248
1288
|
backupLocation: core.BackupLocation.GOOGLE_DRIVE,
|
|
@@ -1262,7 +1302,7 @@ class DynamicWalletClient {
|
|
|
1262
1302
|
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
1263
1303
|
return data;
|
|
1264
1304
|
} catch (error) {
|
|
1265
|
-
const message =
|
|
1305
|
+
const message = '[DynamicWaasWalletClient] Error in storeEncryptedBackupByWallet';
|
|
1266
1306
|
const context = {
|
|
1267
1307
|
accountAddress
|
|
1268
1308
|
};
|
|
@@ -1329,7 +1369,7 @@ class DynamicWalletClient {
|
|
|
1329
1369
|
}
|
|
1330
1370
|
return oauthAccountId;
|
|
1331
1371
|
} catch (error) {
|
|
1332
|
-
const message =
|
|
1372
|
+
const message = '[DynamicWaasWalletClient] Error in getGoogleOauthAccountIdOrThrow';
|
|
1333
1373
|
if (error instanceof axios.AxiosError) {
|
|
1334
1374
|
handleAxiosError(error, message, {
|
|
1335
1375
|
accountAddress
|
|
@@ -1400,7 +1440,7 @@ class DynamicWalletClient {
|
|
|
1400
1440
|
}
|
|
1401
1441
|
return decryptedKeyShares;
|
|
1402
1442
|
} catch (error) {
|
|
1403
|
-
const message =
|
|
1443
|
+
const message = '[DynamicWaasWalletClient] Error in recoverEncryptedBackupByWallet';
|
|
1404
1444
|
const context = {
|
|
1405
1445
|
accountAddress,
|
|
1406
1446
|
password,
|
|
@@ -1426,7 +1466,17 @@ class DynamicWalletClient {
|
|
|
1426
1466
|
}
|
|
1427
1467
|
this.walletMap = JSON.parse(wallets);
|
|
1428
1468
|
}
|
|
1429
|
-
|
|
1469
|
+
/**
|
|
1470
|
+
* This method handles the complete flow for ensuring wallet key shares are backed up to Google Drive:
|
|
1471
|
+
* - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to Google Drive)
|
|
1472
|
+
* - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and Google Drive
|
|
1473
|
+
*
|
|
1474
|
+
* @param params - The backup parameters
|
|
1475
|
+
* @param params.accountAddress - The wallet account address to backup
|
|
1476
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1477
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
1478
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were backed up
|
|
1479
|
+
*/ async backupKeySharesToGoogleDrive({ accountAddress, password, signedSessionId }) {
|
|
1430
1480
|
try {
|
|
1431
1481
|
await this.getWallet({
|
|
1432
1482
|
accountAddress,
|
|
@@ -1434,16 +1484,59 @@ class DynamicWalletClient {
|
|
|
1434
1484
|
password,
|
|
1435
1485
|
signedSessionId
|
|
1436
1486
|
});
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1487
|
+
const currentThresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
|
|
1488
|
+
if (currentThresholdSignatureScheme === core.ThresholdSignatureScheme.TWO_OF_TWO) {
|
|
1489
|
+
// Reshare to 2-of-3, which will automatically handle the backup distribution
|
|
1490
|
+
await this.reshare({
|
|
1491
|
+
chainName: this.walletMap[accountAddress].chainName,
|
|
1492
|
+
accountAddress,
|
|
1493
|
+
oldThresholdSignatureScheme: currentThresholdSignatureScheme,
|
|
1494
|
+
newThresholdSignatureScheme: core.ThresholdSignatureScheme.TWO_OF_THREE,
|
|
1495
|
+
password,
|
|
1496
|
+
signedSessionId,
|
|
1497
|
+
backupToGoogleDrive: true
|
|
1498
|
+
});
|
|
1499
|
+
const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
|
|
1500
|
+
const googleDriveShares = backupInfo.backups[core.BackupLocation.GOOGLE_DRIVE] || [];
|
|
1501
|
+
return googleDriveShares;
|
|
1502
|
+
} else {
|
|
1503
|
+
// Already 2-of-3, only call backup
|
|
1504
|
+
const data = await this.storeEncryptedBackupByWallet({
|
|
1505
|
+
accountAddress,
|
|
1506
|
+
password,
|
|
1507
|
+
signedSessionId,
|
|
1508
|
+
backupToGoogleDrive: true
|
|
1509
|
+
});
|
|
1510
|
+
const googleDriveKeyShares = data.keyShares.filter((ks)=>ks.backupLocation === core.BackupLocation.GOOGLE_DRIVE);
|
|
1511
|
+
return googleDriveKeyShares.map((ks)=>ks.id);
|
|
1512
|
+
}
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
this.logger.error('[DynamicWaasWalletClient]: Error in backupKeySharesToGoogleDrive', error);
|
|
1515
|
+
if (error instanceof axios.AxiosError) {
|
|
1516
|
+
const message = '[DynamicWaasWalletClient] Error in backupKeySharesToGoogleDrive';
|
|
1517
|
+
handleAxiosError(error, message, {
|
|
1518
|
+
accountAddress
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
throw error;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* This method handles only the Google Drive upload mechanics without any reshare logic.
|
|
1526
|
+
* It encrypts the provided key shares, uploads them to Google Drive, and updates the
|
|
1527
|
+
* backup metadata. This method is intended for internal use by storeEncryptedBackupByWallet
|
|
1528
|
+
* and should not be called directly from external code.
|
|
1529
|
+
*
|
|
1530
|
+
* @param params - The upload parameters
|
|
1531
|
+
* @param params.accountAddress - The wallet account address
|
|
1532
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1533
|
+
* @param params.encryptedKeyShares - The specific key shares to upload to Google Drive
|
|
1534
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were uploaded
|
|
1535
|
+
*/ async uploadKeySharesToGoogleDrive({ accountAddress, encryptedKeyShares }) {
|
|
1536
|
+
try {
|
|
1537
|
+
if (encryptedKeyShares.length === 0) {
|
|
1441
1538
|
throw new Error('No key shares found');
|
|
1442
1539
|
}
|
|
1443
|
-
const encryptedKeyShares = await Promise.all(clientKeyShares.map((keyShare)=>this.encryptKeyShare({
|
|
1444
|
-
keyShare,
|
|
1445
|
-
password
|
|
1446
|
-
})));
|
|
1447
1540
|
const oauthAccountId = await this.getGoogleOauthAccountIdOrThrow(accountAddress);
|
|
1448
1541
|
const accessToken = await this.apiClient.getAccessToken({
|
|
1449
1542
|
oauthAccountId
|
|
@@ -1474,12 +1567,11 @@ class DynamicWalletClient {
|
|
|
1474
1567
|
storage: this.storage,
|
|
1475
1568
|
storageKey: this.storageKey
|
|
1476
1569
|
});
|
|
1570
|
+
return data.keyShares.map((ks)=>ks.id);
|
|
1477
1571
|
} catch (error) {
|
|
1478
|
-
const message =
|
|
1572
|
+
const message = '[DynamicWaasWalletClient] Error in backupKeySharesToGoogleDrive';
|
|
1479
1573
|
const context = {
|
|
1480
|
-
accountAddress
|
|
1481
|
-
password,
|
|
1482
|
-
signedSessionId
|
|
1574
|
+
accountAddress
|
|
1483
1575
|
};
|
|
1484
1576
|
if (error instanceof axios.AxiosError) {
|
|
1485
1577
|
handleAxiosError(error, message, context);
|
|
@@ -1547,7 +1639,7 @@ class DynamicWalletClient {
|
|
|
1547
1639
|
});
|
|
1548
1640
|
return decryptedKeyShares;
|
|
1549
1641
|
} catch (error) {
|
|
1550
|
-
const message =
|
|
1642
|
+
const message = '[DynamicWaasWalletClient] Error in restoreBackupFromGoogleDrive';
|
|
1551
1643
|
const context = {
|
|
1552
1644
|
accountAddress
|
|
1553
1645
|
};
|
|
@@ -1743,7 +1835,7 @@ class DynamicWalletClient {
|
|
|
1743
1835
|
walletProperties: wallet == null ? void 0 : wallet.walletProperties
|
|
1744
1836
|
});
|
|
1745
1837
|
} catch (error) {
|
|
1746
|
-
const message =
|
|
1838
|
+
const message = '[DynamicWaasWalletClient] Error in getWalletClientKeyShareBackupInfo';
|
|
1747
1839
|
if (error instanceof axios.AxiosError) {
|
|
1748
1840
|
handleAxiosError(error, message, {
|
|
1749
1841
|
accountAddress
|
|
@@ -1775,7 +1867,7 @@ class DynamicWalletClient {
|
|
|
1775
1867
|
const walletProperties = wallet.walletProperties;
|
|
1776
1868
|
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1777
1869
|
walletId: wallet.id,
|
|
1778
|
-
chainName: wallet.
|
|
1870
|
+
chainName: core.verifiedCredentialNameToChainEnum[wallet.chain],
|
|
1779
1871
|
accountAddress,
|
|
1780
1872
|
thresholdSignatureScheme: walletProperties.thresholdSignatureScheme,
|
|
1781
1873
|
derivationPath: walletProperties.derivationPath,
|
|
@@ -1814,7 +1906,7 @@ class DynamicWalletClient {
|
|
|
1814
1906
|
}
|
|
1815
1907
|
return this.walletMap[accountAddress];
|
|
1816
1908
|
} catch (error) {
|
|
1817
|
-
const message =
|
|
1909
|
+
const message = '[DynamicWaasWalletClient] Error in getWallet';
|
|
1818
1910
|
const context = {
|
|
1819
1911
|
accountAddress,
|
|
1820
1912
|
walletOperation,
|
|
@@ -1862,7 +1954,7 @@ class DynamicWalletClient {
|
|
|
1862
1954
|
}, {});
|
|
1863
1955
|
return wallets;
|
|
1864
1956
|
} catch (error) {
|
|
1865
|
-
const message =
|
|
1957
|
+
const message = '[DynamicWaasWalletClient] Error in getWallets';
|
|
1866
1958
|
if (error instanceof axios.AxiosError) {
|
|
1867
1959
|
handleAxiosError(error, message, {});
|
|
1868
1960
|
}
|
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,77 @@ 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.
|
|
1216
|
+
*
|
|
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.
|
|
1205
1220
|
*
|
|
1206
|
-
*
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
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
|
|
1209
1225
|
*
|
|
1210
|
-
*
|
|
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 {
|
|
1242
|
+
var _this_walletMap_accountAddress;
|
|
1222
1243
|
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
1223
1244
|
accountAddress
|
|
1224
1245
|
});
|
|
1246
|
+
if (!((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.walletId)) {
|
|
1247
|
+
this.logger.error('[DynamicWaasWalletClient] Error in storeEncryptedBackupByWallet, wallet or walletId not found from the wallet map', {
|
|
1248
|
+
context: {
|
|
1249
|
+
accountAddress,
|
|
1250
|
+
walletMap: this.walletMap
|
|
1251
|
+
}
|
|
1252
|
+
});
|
|
1253
|
+
throw new Error(`WalletId not found for accountAddress ${accountAddress}`);
|
|
1254
|
+
}
|
|
1255
|
+
// TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
|
|
1256
|
+
let dynamicClientKeyShares = [];
|
|
1257
|
+
let googleDriveKeyShares = [];
|
|
1225
1258
|
const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
|
|
1226
1259
|
keyShare,
|
|
1227
1260
|
password
|
|
1228
1261
|
})));
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1262
|
+
const hasExistingGoogleDriveBackup = this.walletMap[accountAddress].clientKeySharesBackupInfo.backups[BackupLocation.GOOGLE_DRIVE].length > 0;
|
|
1263
|
+
// Backup to Google Drive if:
|
|
1264
|
+
// 1. Explicitly requested via flag, OR
|
|
1265
|
+
// 2. User already has Google Drive backups
|
|
1266
|
+
const shouldBackupToGoogleDrive = backupToGoogleDrive || hasExistingGoogleDriveBackup;
|
|
1267
|
+
if (shouldBackupToGoogleDrive && keySharesToBackup.length >= 2) {
|
|
1268
|
+
// For 2 shares: 1 to backend, 1 to Google Drive
|
|
1269
|
+
// For 3+ shares: N-1 to backend, 1 to Google Drive
|
|
1270
|
+
const googleDriveShareCount = 1;
|
|
1271
|
+
dynamicClientKeyShares = encryptedKeyShares.slice(0, -googleDriveShareCount);
|
|
1272
|
+
googleDriveKeyShares = encryptedKeyShares.slice(-googleDriveShareCount);
|
|
1273
|
+
} else {
|
|
1274
|
+
dynamicClientKeyShares = encryptedKeyShares;
|
|
1232
1275
|
}
|
|
1233
|
-
// TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
|
|
1234
1276
|
const data = await this.apiClient.storeEncryptedBackupByWallet({
|
|
1235
1277
|
walletId: this.walletMap[accountAddress].walletId,
|
|
1236
|
-
encryptedKeyShares,
|
|
1278
|
+
encryptedKeyShares: dynamicClientKeyShares,
|
|
1237
1279
|
passwordEncrypted: Boolean(password) && password !== this.environmentId,
|
|
1238
1280
|
signedSessionId
|
|
1239
1281
|
});
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
const googleDriveKeyShareIds = await this.backupKeySharesToGoogleDrive({
|
|
1282
|
+
if (googleDriveKeyShares.length > 0) {
|
|
1283
|
+
const googleDriveKeyShareIds = await this.uploadKeySharesToGoogleDrive({
|
|
1243
1284
|
accountAddress,
|
|
1244
|
-
|
|
1245
|
-
signedSessionId
|
|
1285
|
+
encryptedKeyShares: googleDriveKeyShares
|
|
1246
1286
|
});
|
|
1247
1287
|
data.keyShares.push({
|
|
1248
1288
|
backupLocation: BackupLocation.GOOGLE_DRIVE,
|
|
@@ -1262,7 +1302,7 @@ class DynamicWalletClient {
|
|
|
1262
1302
|
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
1263
1303
|
return data;
|
|
1264
1304
|
} catch (error) {
|
|
1265
|
-
const message =
|
|
1305
|
+
const message = '[DynamicWaasWalletClient] Error in storeEncryptedBackupByWallet';
|
|
1266
1306
|
const context = {
|
|
1267
1307
|
accountAddress
|
|
1268
1308
|
};
|
|
@@ -1329,7 +1369,7 @@ class DynamicWalletClient {
|
|
|
1329
1369
|
}
|
|
1330
1370
|
return oauthAccountId;
|
|
1331
1371
|
} catch (error) {
|
|
1332
|
-
const message =
|
|
1372
|
+
const message = '[DynamicWaasWalletClient] Error in getGoogleOauthAccountIdOrThrow';
|
|
1333
1373
|
if (error instanceof AxiosError) {
|
|
1334
1374
|
handleAxiosError(error, message, {
|
|
1335
1375
|
accountAddress
|
|
@@ -1400,7 +1440,7 @@ class DynamicWalletClient {
|
|
|
1400
1440
|
}
|
|
1401
1441
|
return decryptedKeyShares;
|
|
1402
1442
|
} catch (error) {
|
|
1403
|
-
const message =
|
|
1443
|
+
const message = '[DynamicWaasWalletClient] Error in recoverEncryptedBackupByWallet';
|
|
1404
1444
|
const context = {
|
|
1405
1445
|
accountAddress,
|
|
1406
1446
|
password,
|
|
@@ -1426,7 +1466,17 @@ class DynamicWalletClient {
|
|
|
1426
1466
|
}
|
|
1427
1467
|
this.walletMap = JSON.parse(wallets);
|
|
1428
1468
|
}
|
|
1429
|
-
|
|
1469
|
+
/**
|
|
1470
|
+
* This method handles the complete flow for ensuring wallet key shares are backed up to Google Drive:
|
|
1471
|
+
* - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to Google Drive)
|
|
1472
|
+
* - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and Google Drive
|
|
1473
|
+
*
|
|
1474
|
+
* @param params - The backup parameters
|
|
1475
|
+
* @param params.accountAddress - The wallet account address to backup
|
|
1476
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1477
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
1478
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were backed up
|
|
1479
|
+
*/ async backupKeySharesToGoogleDrive({ accountAddress, password, signedSessionId }) {
|
|
1430
1480
|
try {
|
|
1431
1481
|
await this.getWallet({
|
|
1432
1482
|
accountAddress,
|
|
@@ -1434,16 +1484,59 @@ class DynamicWalletClient {
|
|
|
1434
1484
|
password,
|
|
1435
1485
|
signedSessionId
|
|
1436
1486
|
});
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1487
|
+
const currentThresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
|
|
1488
|
+
if (currentThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO) {
|
|
1489
|
+
// Reshare to 2-of-3, which will automatically handle the backup distribution
|
|
1490
|
+
await this.reshare({
|
|
1491
|
+
chainName: this.walletMap[accountAddress].chainName,
|
|
1492
|
+
accountAddress,
|
|
1493
|
+
oldThresholdSignatureScheme: currentThresholdSignatureScheme,
|
|
1494
|
+
newThresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_THREE,
|
|
1495
|
+
password,
|
|
1496
|
+
signedSessionId,
|
|
1497
|
+
backupToGoogleDrive: true
|
|
1498
|
+
});
|
|
1499
|
+
const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
|
|
1500
|
+
const googleDriveShares = backupInfo.backups[BackupLocation.GOOGLE_DRIVE] || [];
|
|
1501
|
+
return googleDriveShares;
|
|
1502
|
+
} else {
|
|
1503
|
+
// Already 2-of-3, only call backup
|
|
1504
|
+
const data = await this.storeEncryptedBackupByWallet({
|
|
1505
|
+
accountAddress,
|
|
1506
|
+
password,
|
|
1507
|
+
signedSessionId,
|
|
1508
|
+
backupToGoogleDrive: true
|
|
1509
|
+
});
|
|
1510
|
+
const googleDriveKeyShares = data.keyShares.filter((ks)=>ks.backupLocation === BackupLocation.GOOGLE_DRIVE);
|
|
1511
|
+
return googleDriveKeyShares.map((ks)=>ks.id);
|
|
1512
|
+
}
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
this.logger.error('[DynamicWaasWalletClient]: Error in backupKeySharesToGoogleDrive', error);
|
|
1515
|
+
if (error instanceof AxiosError) {
|
|
1516
|
+
const message = '[DynamicWaasWalletClient] Error in backupKeySharesToGoogleDrive';
|
|
1517
|
+
handleAxiosError(error, message, {
|
|
1518
|
+
accountAddress
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
throw error;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* This method handles only the Google Drive upload mechanics without any reshare logic.
|
|
1526
|
+
* It encrypts the provided key shares, uploads them to Google Drive, and updates the
|
|
1527
|
+
* backup metadata. This method is intended for internal use by storeEncryptedBackupByWallet
|
|
1528
|
+
* and should not be called directly from external code.
|
|
1529
|
+
*
|
|
1530
|
+
* @param params - The upload parameters
|
|
1531
|
+
* @param params.accountAddress - The wallet account address
|
|
1532
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1533
|
+
* @param params.encryptedKeyShares - The specific key shares to upload to Google Drive
|
|
1534
|
+
* @returns Promise<string[]> - Array of Google Drive key share IDs that were uploaded
|
|
1535
|
+
*/ async uploadKeySharesToGoogleDrive({ accountAddress, encryptedKeyShares }) {
|
|
1536
|
+
try {
|
|
1537
|
+
if (encryptedKeyShares.length === 0) {
|
|
1441
1538
|
throw new Error('No key shares found');
|
|
1442
1539
|
}
|
|
1443
|
-
const encryptedKeyShares = await Promise.all(clientKeyShares.map((keyShare)=>this.encryptKeyShare({
|
|
1444
|
-
keyShare,
|
|
1445
|
-
password
|
|
1446
|
-
})));
|
|
1447
1540
|
const oauthAccountId = await this.getGoogleOauthAccountIdOrThrow(accountAddress);
|
|
1448
1541
|
const accessToken = await this.apiClient.getAccessToken({
|
|
1449
1542
|
oauthAccountId
|
|
@@ -1474,12 +1567,11 @@ class DynamicWalletClient {
|
|
|
1474
1567
|
storage: this.storage,
|
|
1475
1568
|
storageKey: this.storageKey
|
|
1476
1569
|
});
|
|
1570
|
+
return data.keyShares.map((ks)=>ks.id);
|
|
1477
1571
|
} catch (error) {
|
|
1478
|
-
const message =
|
|
1572
|
+
const message = '[DynamicWaasWalletClient] Error in backupKeySharesToGoogleDrive';
|
|
1479
1573
|
const context = {
|
|
1480
|
-
accountAddress
|
|
1481
|
-
password,
|
|
1482
|
-
signedSessionId
|
|
1574
|
+
accountAddress
|
|
1483
1575
|
};
|
|
1484
1576
|
if (error instanceof AxiosError) {
|
|
1485
1577
|
handleAxiosError(error, message, context);
|
|
@@ -1547,7 +1639,7 @@ class DynamicWalletClient {
|
|
|
1547
1639
|
});
|
|
1548
1640
|
return decryptedKeyShares;
|
|
1549
1641
|
} catch (error) {
|
|
1550
|
-
const message =
|
|
1642
|
+
const message = '[DynamicWaasWalletClient] Error in restoreBackupFromGoogleDrive';
|
|
1551
1643
|
const context = {
|
|
1552
1644
|
accountAddress
|
|
1553
1645
|
};
|
|
@@ -1743,7 +1835,7 @@ class DynamicWalletClient {
|
|
|
1743
1835
|
walletProperties: wallet == null ? void 0 : wallet.walletProperties
|
|
1744
1836
|
});
|
|
1745
1837
|
} catch (error) {
|
|
1746
|
-
const message =
|
|
1838
|
+
const message = '[DynamicWaasWalletClient] Error in getWalletClientKeyShareBackupInfo';
|
|
1747
1839
|
if (error instanceof AxiosError) {
|
|
1748
1840
|
handleAxiosError(error, message, {
|
|
1749
1841
|
accountAddress
|
|
@@ -1775,7 +1867,7 @@ class DynamicWalletClient {
|
|
|
1775
1867
|
const walletProperties = wallet.walletProperties;
|
|
1776
1868
|
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1777
1869
|
walletId: wallet.id,
|
|
1778
|
-
chainName: wallet.
|
|
1870
|
+
chainName: verifiedCredentialNameToChainEnum[wallet.chain],
|
|
1779
1871
|
accountAddress,
|
|
1780
1872
|
thresholdSignatureScheme: walletProperties.thresholdSignatureScheme,
|
|
1781
1873
|
derivationPath: walletProperties.derivationPath,
|
|
@@ -1814,7 +1906,7 @@ class DynamicWalletClient {
|
|
|
1814
1906
|
}
|
|
1815
1907
|
return this.walletMap[accountAddress];
|
|
1816
1908
|
} catch (error) {
|
|
1817
|
-
const message =
|
|
1909
|
+
const message = '[DynamicWaasWalletClient] Error in getWallet';
|
|
1818
1910
|
const context = {
|
|
1819
1911
|
accountAddress,
|
|
1820
1912
|
walletOperation,
|
|
@@ -1862,7 +1954,7 @@ class DynamicWalletClient {
|
|
|
1862
1954
|
}, {});
|
|
1863
1955
|
return wallets;
|
|
1864
1956
|
} catch (error) {
|
|
1865
|
-
const message =
|
|
1957
|
+
const message = '[DynamicWaasWalletClient] Error in getWallets';
|
|
1866
1958
|
if (error instanceof AxiosError) {
|
|
1867
1959
|
handleAxiosError(error, message, {});
|
|
1868
1960
|
}
|
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.95",
|
|
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.95",
|
|
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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"}
|