@dynamic-labs-wallet/browser 0.0.0-pr384.2 → 0.0.0-pr534.0
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 +719 -341
- package/index.esm.js +714 -344
- package/internal/core/bip340.cjs +1 -0
- package/internal/core/bip340.d.ts +1 -1
- package/internal/core/common.cjs +1 -0
- package/internal/core/common.d.ts +1 -0
- package/internal/core/ecdsa.cjs +1 -0
- package/internal/core/ecdsa.d.ts +1 -1
- package/internal/core/ed25519.cjs +1 -0
- package/internal/core/ed25519_exportable.cjs +1 -0
- package/internal/core/ed25519_exportable.d.ts +0 -1
- package/internal/core/index.cjs +1 -0
- package/internal/core/native.d.ts +2 -2
- package/internal/core/sr25519.cjs +1 -0
- package/internal/core/types.cjs +1 -0
- package/internal/web/generated/libmpc_executor.d.ts +30 -30
- package/internal/web/generated/libmpc_executor.js +2 -2
- package/internal/web/generated/libmpc_executor_bg.wasm +0 -0
- package/internal/web/index.d.ts +1 -1
- package/internal/web/index.js +1 -1
- package/package.json +4 -4
- package/src/client.d.ts +99 -34
- package/src/client.d.ts.map +1 -1
- package/src/constants.d.ts +2 -0
- package/src/constants.d.ts.map +1 -1
- package/src/services/encryption.d.ts +19 -0
- package/src/services/encryption.d.ts.map +1 -0
- package/src/types.d.ts +36 -1
- package/src/types.d.ts.map +1 -1
- package/src/utils.d.ts +8 -2
- package/src/utils.d.ts.map +1 -1
- package/internal/core/bip340.js +0 -1
- package/internal/core/common.js +0 -1
- package/internal/core/ecdsa.js +0 -1
- package/internal/core/ed25519.js +0 -1
- package/internal/core/ed25519_exportable.js +0 -1
- package/internal/core/index.js +0 -1
- package/internal/core/package.json +0 -17
- package/internal/core/sr25519.js +0 -1
- package/internal/core/types.js +0 -1
- package/internal/web/package.json +0 -17
- /package/internal/core/{native.js → native.cjs} +0 -0
package/index.cjs.js
CHANGED
|
@@ -5,10 +5,10 @@ var web = require('#internal/web');
|
|
|
5
5
|
var semver = require('semver');
|
|
6
6
|
var uuid = require('uuid');
|
|
7
7
|
var logger$1 = require('@dynamic-labs/logger');
|
|
8
|
+
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
8
9
|
var loadArgon2idWasm = require('argon2id');
|
|
9
10
|
var axios = require('axios');
|
|
10
11
|
var createHttpError = require('http-errors');
|
|
11
|
-
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
12
12
|
|
|
13
13
|
function _extends() {
|
|
14
14
|
_extends = Object.assign || function assign(target) {
|
|
@@ -463,10 +463,13 @@ const SIGNED_SESSION_ID_MIN_VERSION_BY_NAMESPACE = {
|
|
|
463
463
|
WalletKit: '4.25.4',
|
|
464
464
|
ClientSDK: '0.1.0-alpha.0'
|
|
465
465
|
};
|
|
466
|
+
const ROOM_EXPIRATION_TIME = 1000 * 60 * 10; // 10 minutes
|
|
467
|
+
const ROOM_CACHE_COUNT = 5;
|
|
466
468
|
|
|
467
469
|
const isBrowser = ()=>typeof window !== 'undefined';
|
|
468
|
-
const getClientKeyShareExportFileName = ({ thresholdSignatureScheme, accountAddress })=>{
|
|
469
|
-
|
|
470
|
+
const getClientKeyShareExportFileName = ({ thresholdSignatureScheme, accountAddress, isGoogleDrive = false })=>{
|
|
471
|
+
const suffix = isGoogleDrive ? '-google-drive' : '';
|
|
472
|
+
return `${CLIENT_KEYSHARE_EXPORT_FILENAME_PREFIX}-${thresholdSignatureScheme}-${accountAddress}${suffix}.json`;
|
|
470
473
|
};
|
|
471
474
|
const getClientKeyShareBackupInfo = (params)=>{
|
|
472
475
|
var _params_walletProperties, _params_walletProperties_keyShares_;
|
|
@@ -475,7 +478,8 @@ const getClientKeyShareBackupInfo = (params)=>{
|
|
|
475
478
|
[core.BackupLocation.GOOGLE_DRIVE]: [],
|
|
476
479
|
[core.BackupLocation.ICLOUD]: [],
|
|
477
480
|
[core.BackupLocation.USER]: [],
|
|
478
|
-
[core.BackupLocation.EXTERNAL]: []
|
|
481
|
+
[core.BackupLocation.EXTERNAL]: [],
|
|
482
|
+
[core.BackupLocation.DELEGATED]: []
|
|
479
483
|
};
|
|
480
484
|
if (!(params == null ? void 0 : (_params_walletProperties = params.walletProperties) == null ? void 0 : _params_walletProperties.keyShares)) {
|
|
481
485
|
return {
|
|
@@ -605,6 +609,19 @@ const createBackupData = ({ encryptedKeyShares, accountAddress, thresholdSignatu
|
|
|
605
609
|
}
|
|
606
610
|
};
|
|
607
611
|
};
|
|
612
|
+
const downloadStringAsFile = ({ filename, content, mimeType = 'application/json' })=>{
|
|
613
|
+
const blob = new Blob([
|
|
614
|
+
content
|
|
615
|
+
], {
|
|
616
|
+
type: mimeType
|
|
617
|
+
});
|
|
618
|
+
const url = URL.createObjectURL(blob);
|
|
619
|
+
const a = document.createElement('a');
|
|
620
|
+
a.href = url;
|
|
621
|
+
a.download = filename;
|
|
622
|
+
a.click();
|
|
623
|
+
URL.revokeObjectURL(url);
|
|
624
|
+
};
|
|
608
625
|
|
|
609
626
|
/**
|
|
610
627
|
* Uploads a backup to Google Drive App
|
|
@@ -651,6 +668,84 @@ const createBackupData = ({ encryptedKeyShares, accountAddress, thresholdSignatu
|
|
|
651
668
|
}
|
|
652
669
|
};
|
|
653
670
|
|
|
671
|
+
const ALG_LABEL_RSA = 'HYBRID-RSA-AES-256';
|
|
672
|
+
/**
|
|
673
|
+
* Convert base64 to base64url encoding
|
|
674
|
+
*/ const toBase64Url = (buffer)=>{
|
|
675
|
+
const base64 = Buffer.from(buffer).toString('base64');
|
|
676
|
+
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
677
|
+
};
|
|
678
|
+
/**
|
|
679
|
+
* Convert ArrayBuffer to base64url
|
|
680
|
+
*/ const arrayBufferToBase64Url = (buffer)=>{
|
|
681
|
+
return toBase64Url(buffer);
|
|
682
|
+
};
|
|
683
|
+
/**
|
|
684
|
+
* Import RSA public key from PEM format
|
|
685
|
+
*/ const importRSAPublicKey = async (publicKeyPem)=>{
|
|
686
|
+
// Remove PEM headers and decode base64
|
|
687
|
+
const pemHeader = '-----BEGIN PUBLIC KEY-----';
|
|
688
|
+
const pemFooter = '-----END PUBLIC KEY-----';
|
|
689
|
+
const pemContents = publicKeyPem.replace(pemHeader, '').replace(pemFooter, '').replace(/\s/g, '');
|
|
690
|
+
const binaryDer = Buffer.from(pemContents, 'base64').toString('binary');
|
|
691
|
+
const keyData = new Uint8Array(binaryDer.length);
|
|
692
|
+
for(let i = 0; i < binaryDer.length; i++){
|
|
693
|
+
keyData[i] = binaryDer.charCodeAt(i);
|
|
694
|
+
}
|
|
695
|
+
return await crypto.subtle.importKey('spki', keyData, {
|
|
696
|
+
name: 'RSA-OAEP',
|
|
697
|
+
hash: 'SHA-256'
|
|
698
|
+
}, false, [
|
|
699
|
+
'encrypt'
|
|
700
|
+
]);
|
|
701
|
+
};
|
|
702
|
+
// encodedEnvelopeBytes intentionally omitted; alg/ct/ek/iv/tag/kid is sufficient
|
|
703
|
+
/**
|
|
704
|
+
* Encrypts data using HYBRID-RSA-AES-256 encryption scheme with Web Crypto API.
|
|
705
|
+
* 1. Generate random AES-256 key
|
|
706
|
+
* 2. Encrypt AES key with RSA public key
|
|
707
|
+
* 3. Encrypt data with AES-256-GCM
|
|
708
|
+
*/ const encryptDelegatedKeyShare = async (data, publicKeyPem, keyId)=>{
|
|
709
|
+
try {
|
|
710
|
+
// Step 1: Generate a random AES-256 key and 16-byte IV
|
|
711
|
+
const aesKey = await crypto.subtle.generateKey({
|
|
712
|
+
name: 'AES-GCM',
|
|
713
|
+
length: 256
|
|
714
|
+
}, true, [
|
|
715
|
+
'encrypt'
|
|
716
|
+
]);
|
|
717
|
+
const iv = crypto.getRandomValues(new Uint8Array(16)); // 128-bit IV for GCM
|
|
718
|
+
// Step 2: Encrypt the data with AES-256-GCM
|
|
719
|
+
const plaintext = new TextEncoder().encode(data);
|
|
720
|
+
const encryptedData = await crypto.subtle.encrypt({
|
|
721
|
+
name: 'AES-GCM',
|
|
722
|
+
iv: iv
|
|
723
|
+
}, aesKey, plaintext);
|
|
724
|
+
// Extract the auth tag from the encrypted data (last 16 bytes)
|
|
725
|
+
const encryptedDataArray = new Uint8Array(encryptedData);
|
|
726
|
+
const authTag = encryptedDataArray.slice(-16);
|
|
727
|
+
const ciphertext = encryptedDataArray.slice(0, -16);
|
|
728
|
+
// Step 3: Encrypt the AES key with RSA public key
|
|
729
|
+
const rsaPublicKey = await importRSAPublicKey(publicKeyPem);
|
|
730
|
+
// Export the AES key to encrypt it
|
|
731
|
+
const aesKeyData = await crypto.subtle.exportKey('raw', aesKey);
|
|
732
|
+
const encryptedAesKey = await crypto.subtle.encrypt({
|
|
733
|
+
name: 'RSA-OAEP'
|
|
734
|
+
}, rsaPublicKey, aesKeyData);
|
|
735
|
+
return _extends({
|
|
736
|
+
alg: ALG_LABEL_RSA,
|
|
737
|
+
iv: arrayBufferToBase64Url(iv.buffer),
|
|
738
|
+
ct: arrayBufferToBase64Url(ciphertext.buffer),
|
|
739
|
+
tag: arrayBufferToBase64Url(authTag.buffer),
|
|
740
|
+
ek: arrayBufferToBase64Url(encryptedAesKey)
|
|
741
|
+
}, keyId ? {
|
|
742
|
+
kid: keyId
|
|
743
|
+
} : {});
|
|
744
|
+
} catch (error) {
|
|
745
|
+
throw new Error(`Encryption failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
|
|
654
749
|
const localStorageWriteTest = {
|
|
655
750
|
tested: false,
|
|
656
751
|
writable: false
|
|
@@ -720,7 +815,61 @@ const localStorageWriteTest = {
|
|
|
720
815
|
}
|
|
721
816
|
});
|
|
722
817
|
|
|
818
|
+
const createDelegationWithGoogleDriveDistribution = ({ existingShares, delegatedShare })=>({
|
|
819
|
+
dynamicBackendShares: existingShares,
|
|
820
|
+
googleDriveShares: existingShares,
|
|
821
|
+
delegatedShare
|
|
822
|
+
});
|
|
823
|
+
const createDelegationOnlyDistribution = ({ existingShares, delegatedShare })=>({
|
|
824
|
+
dynamicBackendShares: existingShares,
|
|
825
|
+
googleDriveShares: [],
|
|
826
|
+
delegatedShare
|
|
827
|
+
});
|
|
828
|
+
const createGoogleDriveOnlyDistribution = ({ allShares })=>({
|
|
829
|
+
dynamicBackendShares: allShares.slice(0, -1),
|
|
830
|
+
googleDriveShares: allShares.slice(-1)
|
|
831
|
+
});
|
|
832
|
+
const createDynamicOnlyDistribution = ({ allShares })=>({
|
|
833
|
+
dynamicBackendShares: allShares,
|
|
834
|
+
googleDriveShares: []
|
|
835
|
+
});
|
|
836
|
+
const hasGoogleDriveBackup = (backupInfo)=>{
|
|
837
|
+
var _backupInfo_backups_BackupLocation_GOOGLE_DRIVE, _backupInfo_backups;
|
|
838
|
+
var _backupInfo_backups_BackupLocation_GOOGLE_DRIVE_length;
|
|
839
|
+
return ((_backupInfo_backups_BackupLocation_GOOGLE_DRIVE_length = backupInfo == null ? void 0 : (_backupInfo_backups = backupInfo.backups) == null ? void 0 : (_backupInfo_backups_BackupLocation_GOOGLE_DRIVE = _backupInfo_backups[core.BackupLocation.GOOGLE_DRIVE]) == null ? void 0 : _backupInfo_backups_BackupLocation_GOOGLE_DRIVE.length) != null ? _backupInfo_backups_BackupLocation_GOOGLE_DRIVE_length : 0) > 0;
|
|
840
|
+
};
|
|
841
|
+
const hasDelegatedBackup = (backupInfo)=>{
|
|
842
|
+
var _backupInfo_backups_BackupLocation_DELEGATED, _backupInfo_backups;
|
|
843
|
+
var _backupInfo_backups_BackupLocation_DELEGATED_length;
|
|
844
|
+
return ((_backupInfo_backups_BackupLocation_DELEGATED_length = backupInfo == null ? void 0 : (_backupInfo_backups = backupInfo.backups) == null ? void 0 : (_backupInfo_backups_BackupLocation_DELEGATED = _backupInfo_backups[core.BackupLocation.DELEGATED]) == null ? void 0 : _backupInfo_backups_BackupLocation_DELEGATED.length) != null ? _backupInfo_backups_BackupLocation_DELEGATED_length : 0) > 0;
|
|
845
|
+
};
|
|
846
|
+
/**
|
|
847
|
+
* Distribution for adding Google Drive backup to an existing delegation.
|
|
848
|
+
* Client's shares go to both Dynamic and Google Drive.
|
|
849
|
+
* delegatedShare is undefined - we don't re-publish, but preserve the location.
|
|
850
|
+
*/ const createAddGoogleDriveToExistingDelegationDistribution = ({ clientShares })=>({
|
|
851
|
+
dynamicBackendShares: clientShares,
|
|
852
|
+
googleDriveShares: clientShares
|
|
853
|
+
});
|
|
854
|
+
|
|
723
855
|
class DynamicWalletClient {
|
|
856
|
+
async initializeForwardMPCClient() {
|
|
857
|
+
try {
|
|
858
|
+
await this.apiClient.forwardMPCClient.connect();
|
|
859
|
+
this.logger.info('Connected to ForwardMPC enclave websocket. Instance: ' + this.instanceId);
|
|
860
|
+
try {
|
|
861
|
+
await this.apiClient.forwardMPCClient.handshake();
|
|
862
|
+
this.logger.debug('Handshaked with ForwardMPC enclave websocket. Instance: ' + this.instanceId);
|
|
863
|
+
} catch (error) {
|
|
864
|
+
this.logger.error('Error handshaking with ForwardMPC enclave websocket. Instance: ' + this.instanceId, error);
|
|
865
|
+
}
|
|
866
|
+
} catch (error) {
|
|
867
|
+
this.logger.error('Error connecting to ForwardMPC enclave websocket. Instance: ' + this.instanceId, {
|
|
868
|
+
error,
|
|
869
|
+
environmentId: this.environmentId
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
}
|
|
724
873
|
getAuthMode() {
|
|
725
874
|
return this.authMode;
|
|
726
875
|
}
|
|
@@ -792,30 +941,41 @@ class DynamicWalletClient {
|
|
|
792
941
|
throw error;
|
|
793
942
|
}
|
|
794
943
|
}
|
|
795
|
-
async initialize() {
|
|
944
|
+
async initialize(traceContext) {
|
|
796
945
|
if (this.initializePromise) {
|
|
797
946
|
return await this.initializePromise;
|
|
798
947
|
}
|
|
799
948
|
this.logger.debug('[DynamicWaasWalletClient] Initializing Dynamic Waas Wallet SDK');
|
|
800
|
-
this.initializePromise = this._initialize();
|
|
949
|
+
this.initializePromise = this._initialize(traceContext);
|
|
801
950
|
const result = await this.initializePromise;
|
|
802
951
|
this.logger.debug('[DynamicWaasWalletClient] Dynamic Waas Wallet SDK initialized');
|
|
803
952
|
return result;
|
|
804
953
|
}
|
|
805
954
|
/**
|
|
806
955
|
* Client initialization logic
|
|
807
|
-
*/ async _initialize() {
|
|
956
|
+
*/ async _initialize(traceContext) {
|
|
808
957
|
try {
|
|
809
958
|
const initializePromises = [
|
|
810
959
|
this.restoreWallets()
|
|
811
960
|
];
|
|
961
|
+
if (this.featureFlags[core.FEATURE_FLAGS.ENABLE_ROOM_CACHE_FLAG] === true) {
|
|
962
|
+
// Restore rooms first, then create rooms if needed (in series, but not blocking other initialization)
|
|
963
|
+
initializePromises.push(this.restoreRooms().then(()=>// assume two of two threshold signature scheme
|
|
964
|
+
this.createRooms({
|
|
965
|
+
roomType: sdkApiCore.RoomTypeEnum.Threshold,
|
|
966
|
+
thresholdSignatureScheme: core.ThresholdSignatureScheme.TWO_OF_TWO,
|
|
967
|
+
roomCount: ROOM_CACHE_COUNT
|
|
968
|
+
})));
|
|
969
|
+
}
|
|
812
970
|
await Promise.all(initializePromises);
|
|
813
971
|
return {
|
|
814
|
-
error: null
|
|
972
|
+
error: null,
|
|
973
|
+
traceContext
|
|
815
974
|
};
|
|
816
975
|
} catch (error) {
|
|
817
976
|
return {
|
|
818
|
-
error
|
|
977
|
+
error,
|
|
978
|
+
traceContext
|
|
819
979
|
};
|
|
820
980
|
}
|
|
821
981
|
}
|
|
@@ -894,7 +1054,7 @@ class DynamicWalletClient {
|
|
|
894
1054
|
clientKeygenResults
|
|
895
1055
|
};
|
|
896
1056
|
}
|
|
897
|
-
async keyGen({ chainName, thresholdSignatureScheme, onError, onCeremonyComplete }) {
|
|
1057
|
+
async keyGen({ chainName, thresholdSignatureScheme, onError, onCeremonyComplete, traceContext }) {
|
|
898
1058
|
const dynamicRequestId = uuid.v4();
|
|
899
1059
|
try {
|
|
900
1060
|
const clientKeygenInitResults = await this.clientInitializeKeyGen({
|
|
@@ -902,11 +1062,12 @@ class DynamicWalletClient {
|
|
|
902
1062
|
thresholdSignatureScheme
|
|
903
1063
|
});
|
|
904
1064
|
const clientKeygenIds = clientKeygenInitResults.map((result)=>result.keygenId);
|
|
905
|
-
this.
|
|
1065
|
+
this.instrument('[DynamicWaasWalletClient] Initialized client key generation', _extends({
|
|
906
1066
|
clientKeygenIds: clientKeygenIds.join(', '),
|
|
907
1067
|
chainName,
|
|
908
|
-
thresholdSignatureScheme
|
|
909
|
-
|
|
1068
|
+
thresholdSignatureScheme,
|
|
1069
|
+
key: 'keyGen'
|
|
1070
|
+
}, this.getTraceContext(traceContext)));
|
|
910
1071
|
const { roomId, serverKeygenIds } = await this.serverInitializeKeyGen({
|
|
911
1072
|
chainName,
|
|
912
1073
|
clientKeygenIds,
|
|
@@ -914,12 +1075,14 @@ class DynamicWalletClient {
|
|
|
914
1075
|
thresholdSignatureScheme,
|
|
915
1076
|
onCeremonyComplete
|
|
916
1077
|
});
|
|
917
|
-
this.
|
|
1078
|
+
this.instrument('[DynamicWaasWalletClient] Server key generation initialized', _extends({
|
|
918
1079
|
roomId,
|
|
919
1080
|
clientKeygenIds: clientKeygenIds.join(', '),
|
|
920
1081
|
serverKeygenIds: serverKeygenIds.join(', '),
|
|
921
|
-
chainName
|
|
922
|
-
|
|
1082
|
+
chainName,
|
|
1083
|
+
key: 'keyGen',
|
|
1084
|
+
operation: 'serverKeyGen'
|
|
1085
|
+
}, this.getTraceContext(traceContext)));
|
|
923
1086
|
const { rawPublicKey, clientKeygenResults: clientKeyShares } = await this.clientKeyGen({
|
|
924
1087
|
chainName,
|
|
925
1088
|
roomId,
|
|
@@ -927,15 +1090,17 @@ class DynamicWalletClient {
|
|
|
927
1090
|
clientKeygenInitResults,
|
|
928
1091
|
thresholdSignatureScheme
|
|
929
1092
|
});
|
|
930
|
-
this.
|
|
1093
|
+
this.instrument('[DynamicWaasWalletClient] Client key generation completed', _extends({
|
|
931
1094
|
roomId,
|
|
932
1095
|
serverKeygenIds: serverKeygenIds.join(', '),
|
|
933
1096
|
clientKeygenIds: clientKeygenIds.join(', '),
|
|
934
1097
|
chainName,
|
|
935
1098
|
thresholdSignatureScheme,
|
|
936
1099
|
rawPublicKey,
|
|
937
|
-
clientKeySharesCount: clientKeyShares.length
|
|
938
|
-
|
|
1100
|
+
clientKeySharesCount: clientKeyShares.length,
|
|
1101
|
+
key: 'keyGen',
|
|
1102
|
+
operation: 'clientKeyGen'
|
|
1103
|
+
}, this.getTraceContext(traceContext)));
|
|
939
1104
|
return {
|
|
940
1105
|
rawPublicKey,
|
|
941
1106
|
clientKeyShares
|
|
@@ -944,16 +1109,16 @@ class DynamicWalletClient {
|
|
|
944
1109
|
logError({
|
|
945
1110
|
message: 'Error in keyGen',
|
|
946
1111
|
error: error,
|
|
947
|
-
context: {
|
|
1112
|
+
context: _extends({
|
|
948
1113
|
chainName,
|
|
949
1114
|
thresholdSignatureScheme,
|
|
950
1115
|
dynamicRequestId
|
|
951
|
-
}
|
|
1116
|
+
}, this.getTraceContext(traceContext))
|
|
952
1117
|
});
|
|
953
1118
|
throw error;
|
|
954
1119
|
}
|
|
955
1120
|
}
|
|
956
|
-
async importRawPrivateKey({ chainName, privateKey, thresholdSignatureScheme, onError, onCeremonyComplete }) {
|
|
1121
|
+
async importRawPrivateKey({ chainName, privateKey, thresholdSignatureScheme, onError, onCeremonyComplete, traceContext }) {
|
|
957
1122
|
const dynamicRequestId = uuid.v4();
|
|
958
1123
|
try {
|
|
959
1124
|
const mpcSigner = getMPCSigner({
|
|
@@ -965,11 +1130,13 @@ class DynamicWalletClient {
|
|
|
965
1130
|
thresholdSignatureScheme
|
|
966
1131
|
});
|
|
967
1132
|
const clientKeygenIds = clientKeygenInitResults.map((result)=>result.keygenId);
|
|
968
|
-
this.
|
|
1133
|
+
this.instrument('[DynamicWaasWalletClient] Client key generation initialized', _extends({
|
|
969
1134
|
clientKeygenIds: clientKeygenIds.join(', '),
|
|
970
1135
|
chainName,
|
|
971
|
-
thresholdSignatureScheme
|
|
972
|
-
|
|
1136
|
+
thresholdSignatureScheme,
|
|
1137
|
+
key: 'importRawPrivateKey',
|
|
1138
|
+
operation: 'clientKeyGen'
|
|
1139
|
+
}, this.getTraceContext(traceContext)));
|
|
973
1140
|
const { roomId, serverKeygenIds } = await this.apiClient.importPrivateKey({
|
|
974
1141
|
chainName,
|
|
975
1142
|
clientKeygenIds,
|
|
@@ -978,12 +1145,14 @@ class DynamicWalletClient {
|
|
|
978
1145
|
onError,
|
|
979
1146
|
onCeremonyComplete
|
|
980
1147
|
});
|
|
981
|
-
this.
|
|
1148
|
+
this.instrument('[DynamicWaasWalletClient] Server key generation initialized', _extends({
|
|
982
1149
|
roomId,
|
|
983
1150
|
clientKeygenIds: clientKeygenIds.join(', '),
|
|
984
1151
|
serverKeygenIds: serverKeygenIds.join(', '),
|
|
985
|
-
chainName
|
|
986
|
-
|
|
1152
|
+
chainName,
|
|
1153
|
+
key: 'importRawPrivateKey',
|
|
1154
|
+
operation: 'serverImportPrivateKey'
|
|
1155
|
+
}, this.getTraceContext(traceContext)));
|
|
987
1156
|
const { threshold } = core.getTSSConfig(thresholdSignatureScheme);
|
|
988
1157
|
const clientKeygenResults = await Promise.all(clientKeygenInitResults.map(async (currentInit, index)=>{
|
|
989
1158
|
const otherClientKeygenIds = clientKeygenInitResults.filter((init)=>init.keygenId !== currentInit.keygenId).map((init)=>init.keygenId);
|
|
@@ -1008,14 +1177,16 @@ class DynamicWalletClient {
|
|
|
1008
1177
|
keyShare: clientKeygenResult,
|
|
1009
1178
|
derivationPath: undefined
|
|
1010
1179
|
});
|
|
1011
|
-
this.
|
|
1180
|
+
this.instrument('[DynamicWaasWalletClient] Completed import of raw private key', _extends({
|
|
1012
1181
|
rawPublicKey,
|
|
1013
1182
|
chainName,
|
|
1014
1183
|
thresholdSignatureScheme,
|
|
1015
1184
|
roomId,
|
|
1016
1185
|
serverKeygenIds: serverKeygenIds.join(', '),
|
|
1017
|
-
clientKeygenIds: clientKeygenIds.join(', ')
|
|
1018
|
-
|
|
1186
|
+
clientKeygenIds: clientKeygenIds.join(', '),
|
|
1187
|
+
key: 'importRawPrivateKey',
|
|
1188
|
+
operation: 'importRawPrivateKey'
|
|
1189
|
+
}, this.getTraceContext(traceContext)));
|
|
1019
1190
|
return {
|
|
1020
1191
|
rawPublicKey,
|
|
1021
1192
|
clientKeyShares: clientKeygenResults
|
|
@@ -1024,16 +1195,16 @@ class DynamicWalletClient {
|
|
|
1024
1195
|
logError({
|
|
1025
1196
|
message: 'Error in importRawPrivateKey',
|
|
1026
1197
|
error: error,
|
|
1027
|
-
context: {
|
|
1198
|
+
context: _extends({
|
|
1028
1199
|
chainName,
|
|
1029
1200
|
thresholdSignatureScheme,
|
|
1030
1201
|
dynamicRequestId
|
|
1031
|
-
}
|
|
1202
|
+
}, this.getTraceContext(traceContext))
|
|
1032
1203
|
});
|
|
1033
1204
|
throw error;
|
|
1034
1205
|
}
|
|
1035
1206
|
}
|
|
1036
|
-
async serverSign({ walletId, message, isFormatted, mfaToken, context, onError, dynamicRequestId }) {
|
|
1207
|
+
async serverSign({ walletId, message, isFormatted, mfaToken, roomId, context, onError, dynamicRequestId, traceContext }) {
|
|
1037
1208
|
// Create the room and sign the message
|
|
1038
1209
|
if (typeof message !== 'string') {
|
|
1039
1210
|
message = `0x${Buffer.from(message).toString('hex')}`;
|
|
@@ -1044,44 +1215,101 @@ class DynamicWalletClient {
|
|
|
1044
1215
|
isFormatted,
|
|
1045
1216
|
dynamicRequestId,
|
|
1046
1217
|
mfaToken,
|
|
1218
|
+
roomId,
|
|
1047
1219
|
context: context ? JSON.parse(JSON.stringify(context, (_key, value)=>typeof value === 'bigint' ? value.toString() : value)) : undefined,
|
|
1048
|
-
onError
|
|
1220
|
+
onError,
|
|
1221
|
+
forwardMPCClientEnabled: this.forwardMPCEnabled,
|
|
1222
|
+
traceContext
|
|
1049
1223
|
});
|
|
1050
1224
|
return data;
|
|
1051
1225
|
}
|
|
1052
|
-
async
|
|
1226
|
+
async forwardMPCClientSign({ chainName, message, roomId, keyShare, derivationPath, formattedMessage, dynamicRequestId, isFormatted, traceContext }) {
|
|
1227
|
+
try {
|
|
1228
|
+
if (!this.apiClient.forwardMPCClient.connected) {
|
|
1229
|
+
await this.initializeForwardMPCClient();
|
|
1230
|
+
}
|
|
1231
|
+
const messageForForwardMPC = core.serializeMessageForForwardMPC({
|
|
1232
|
+
message,
|
|
1233
|
+
isFormatted,
|
|
1234
|
+
chainName
|
|
1235
|
+
});
|
|
1236
|
+
this.logger.info('Forward MPC enabled, signing message with forward MPC', this.getTraceContext(traceContext));
|
|
1237
|
+
const signature = await this.apiClient.forwardMPCClient.signMessage({
|
|
1238
|
+
keyshare: keyShare,
|
|
1239
|
+
message: chainName === 'SVM' ? formattedMessage : messageForForwardMPC,
|
|
1240
|
+
relayDomain: this.baseMPCRelayApiUrl || '',
|
|
1241
|
+
signingAlgo: chainName === 'EVM' ? 'ECDSA' : 'ED25519',
|
|
1242
|
+
hashAlgo: chainName === 'EVM' && !isFormatted ? 'keccak256' : undefined,
|
|
1243
|
+
derivationPath: derivationPath,
|
|
1244
|
+
roomUuid: roomId
|
|
1245
|
+
});
|
|
1246
|
+
const signatureBytes = signature.data.signature;
|
|
1247
|
+
if (!(signatureBytes instanceof Uint8Array)) {
|
|
1248
|
+
throw new TypeError(`Invalid signature format: expected Uint8Array, got ${typeof signatureBytes}`);
|
|
1249
|
+
}
|
|
1250
|
+
// Convert to EcdsaSignature
|
|
1251
|
+
if (chainName === 'EVM') {
|
|
1252
|
+
const ecdsaSignature = web.EcdsaSignature.fromBuffer(signatureBytes);
|
|
1253
|
+
return ecdsaSignature;
|
|
1254
|
+
} else {
|
|
1255
|
+
return signatureBytes;
|
|
1256
|
+
}
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
this.logger.error('Error signing message with forward MPC client', {
|
|
1259
|
+
error,
|
|
1260
|
+
environmentId: this.environmentId,
|
|
1261
|
+
userId: this.userId,
|
|
1262
|
+
dynamicRequestId
|
|
1263
|
+
});
|
|
1264
|
+
throw error;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
async clientSign({ chainName, message, roomId, keyShare, derivationPath, isFormatted, dynamicRequestId, traceContext }) {
|
|
1053
1268
|
try {
|
|
1054
1269
|
const mpcSigner = getMPCSigner({
|
|
1055
1270
|
chainName,
|
|
1056
1271
|
baseRelayUrl: this.baseMPCRelayApiUrl
|
|
1057
1272
|
});
|
|
1058
1273
|
const formattedMessage = isFormatted ? new web.MessageHash(message) : formatMessage(chainName, message);
|
|
1059
|
-
this.logger.debug('[DynamicWaasWalletClient] Starting client sign', {
|
|
1274
|
+
this.logger.debug('[DynamicWaasWalletClient] Starting client sign', _extends({
|
|
1060
1275
|
chainName,
|
|
1061
1276
|
message,
|
|
1062
1277
|
roomId,
|
|
1063
1278
|
derivationPath,
|
|
1064
1279
|
isFormatted
|
|
1065
|
-
});
|
|
1280
|
+
}, this.getTraceContext(traceContext)));
|
|
1281
|
+
if (this.forwardMPCEnabled) {
|
|
1282
|
+
return this.forwardMPCClientSign({
|
|
1283
|
+
chainName,
|
|
1284
|
+
message,
|
|
1285
|
+
roomId,
|
|
1286
|
+
keyShare,
|
|
1287
|
+
derivationPath,
|
|
1288
|
+
formattedMessage,
|
|
1289
|
+
dynamicRequestId,
|
|
1290
|
+
isFormatted,
|
|
1291
|
+
traceContext
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1066
1294
|
const signature = await mpcSigner.sign(roomId, keyShare, formattedMessage, derivationPath);
|
|
1067
1295
|
return signature;
|
|
1068
1296
|
} catch (error) {
|
|
1069
1297
|
logError({
|
|
1070
1298
|
message: 'Error in clientSign',
|
|
1071
1299
|
error: error,
|
|
1072
|
-
context: {
|
|
1300
|
+
context: _extends({
|
|
1073
1301
|
chainName,
|
|
1074
1302
|
roomId,
|
|
1075
1303
|
derivationPath,
|
|
1076
1304
|
isFormatted,
|
|
1077
1305
|
dynamicRequestId
|
|
1078
|
-
}
|
|
1306
|
+
}, this.getTraceContext(traceContext))
|
|
1079
1307
|
});
|
|
1080
1308
|
throw error;
|
|
1081
1309
|
}
|
|
1082
1310
|
}
|
|
1083
1311
|
//todo: need to modify with imported flag
|
|
1084
|
-
async sign({ accountAddress, message, chainName, password = undefined, isFormatted = false, signedSessionId, mfaToken, context, onError }) {
|
|
1312
|
+
async sign({ accountAddress, message, chainName, password = undefined, isFormatted = false, signedSessionId, mfaToken, context, onError, traceContext }) {
|
|
1085
1313
|
const dynamicRequestId = uuid.v4();
|
|
1086
1314
|
try {
|
|
1087
1315
|
await this.verifyPassword({
|
|
@@ -1096,23 +1324,44 @@ class DynamicWalletClient {
|
|
|
1096
1324
|
walletOperation: core.WalletOperation.SIGN_MESSAGE,
|
|
1097
1325
|
signedSessionId
|
|
1098
1326
|
});
|
|
1099
|
-
|
|
1100
|
-
|
|
1327
|
+
let roomId;
|
|
1328
|
+
if (this.featureFlags[core.FEATURE_FLAGS.ENABLE_ROOM_CACHE_FLAG] === true) {
|
|
1329
|
+
const room = await this.getRoom(sdkApiCore.RoomTypeEnum.Threshold, wallet.thresholdSignatureScheme);
|
|
1330
|
+
roomId = room == null ? void 0 : room.roomId;
|
|
1331
|
+
if (roomId) {
|
|
1332
|
+
this.instrument('[DynamicWaasWalletClient] Using cached room', _extends({
|
|
1333
|
+
key: 'sign',
|
|
1334
|
+
operation: 'cachedRoomFound',
|
|
1335
|
+
accountAddress,
|
|
1336
|
+
chainName,
|
|
1337
|
+
walletId: wallet.walletId,
|
|
1338
|
+
roomId
|
|
1339
|
+
}, this.getTraceContext(traceContext)));
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
// Perform the server sign - always call, but only await if roomId is not provided
|
|
1343
|
+
const serverSignPromise = this.serverSign({
|
|
1101
1344
|
walletId: wallet.walletId,
|
|
1102
1345
|
message,
|
|
1103
1346
|
isFormatted,
|
|
1104
1347
|
mfaToken,
|
|
1348
|
+
roomId,
|
|
1105
1349
|
context,
|
|
1106
1350
|
onError,
|
|
1107
|
-
dynamicRequestId
|
|
1351
|
+
dynamicRequestId,
|
|
1352
|
+
traceContext
|
|
1108
1353
|
});
|
|
1109
|
-
|
|
1354
|
+
// Only await if roomId is not provided
|
|
1355
|
+
roomId = roomId != null ? roomId : (await serverSignPromise).roomId;
|
|
1356
|
+
this.instrument('[DynamicWaasWalletClient] Server sign completed', _extends({
|
|
1110
1357
|
message,
|
|
1111
1358
|
accountAddress,
|
|
1112
1359
|
walletId: wallet.walletId,
|
|
1113
|
-
roomId
|
|
1114
|
-
dynamicRequestId
|
|
1115
|
-
|
|
1360
|
+
roomId,
|
|
1361
|
+
dynamicRequestId,
|
|
1362
|
+
key: 'sign',
|
|
1363
|
+
operation: 'serverSign'
|
|
1364
|
+
}, this.getTraceContext(traceContext)));
|
|
1116
1365
|
const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
|
|
1117
1366
|
// Perform the client sign and return the signature
|
|
1118
1367
|
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
@@ -1121,35 +1370,39 @@ class DynamicWalletClient {
|
|
|
1121
1370
|
const signature = await this.clientSign({
|
|
1122
1371
|
chainName,
|
|
1123
1372
|
message,
|
|
1124
|
-
roomId
|
|
1373
|
+
roomId,
|
|
1125
1374
|
keyShare: clientKeyShares[0],
|
|
1126
1375
|
derivationPath,
|
|
1127
1376
|
isFormatted,
|
|
1128
|
-
dynamicRequestId
|
|
1377
|
+
dynamicRequestId,
|
|
1378
|
+
traceContext
|
|
1129
1379
|
});
|
|
1130
|
-
this.
|
|
1380
|
+
this.instrument('[DynamicWaasWalletClient] Client sign completed', _extends({
|
|
1381
|
+
accountAddress,
|
|
1131
1382
|
chainName,
|
|
1132
1383
|
message,
|
|
1133
|
-
roomId
|
|
1384
|
+
roomId,
|
|
1134
1385
|
derivationPath,
|
|
1135
|
-
isFormatted
|
|
1136
|
-
|
|
1386
|
+
isFormatted,
|
|
1387
|
+
key: 'sign',
|
|
1388
|
+
operation: 'clientSign'
|
|
1389
|
+
}, this.getTraceContext(traceContext)));
|
|
1137
1390
|
return signature;
|
|
1138
1391
|
} catch (error) {
|
|
1139
1392
|
logError({
|
|
1140
1393
|
message: 'Error in sign',
|
|
1141
1394
|
error: error,
|
|
1142
|
-
context: {
|
|
1395
|
+
context: _extends({
|
|
1143
1396
|
accountAddress,
|
|
1144
1397
|
chainName,
|
|
1145
1398
|
isFormatted: isFormatted ? 'true' : 'false',
|
|
1146
1399
|
dynamicRequestId
|
|
1147
|
-
}
|
|
1400
|
+
}, this.getTraceContext(traceContext))
|
|
1148
1401
|
});
|
|
1149
1402
|
throw error;
|
|
1150
1403
|
}
|
|
1151
1404
|
}
|
|
1152
|
-
async refreshWalletAccountShares({ accountAddress, chainName, password = undefined, signedSessionId, mfaToken }) {
|
|
1405
|
+
async refreshWalletAccountShares({ accountAddress, chainName, password = undefined, signedSessionId, mfaToken, traceContext }) {
|
|
1153
1406
|
const dynamicRequestId = uuid.v4();
|
|
1154
1407
|
try {
|
|
1155
1408
|
await this.verifyPassword({
|
|
@@ -1193,11 +1446,11 @@ class DynamicWalletClient {
|
|
|
1193
1446
|
logError({
|
|
1194
1447
|
message: 'Error in refreshWalletAccountShares',
|
|
1195
1448
|
error: error,
|
|
1196
|
-
context: {
|
|
1449
|
+
context: _extends({
|
|
1197
1450
|
accountAddress,
|
|
1198
1451
|
chainName,
|
|
1199
1452
|
dynamicRequestId
|
|
1200
|
-
}
|
|
1453
|
+
}, this.getTraceContext(traceContext))
|
|
1201
1454
|
});
|
|
1202
1455
|
throw error;
|
|
1203
1456
|
}
|
|
@@ -1253,7 +1506,7 @@ class DynamicWalletClient {
|
|
|
1253
1506
|
existingClientKeyShares
|
|
1254
1507
|
};
|
|
1255
1508
|
}
|
|
1256
|
-
async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId, backupToGoogleDrive = false, delegateToProjectEnvironment = false, mfaToken }) {
|
|
1509
|
+
async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId, backupToGoogleDrive = false, delegateToProjectEnvironment = false, mfaToken, revokeDelegation = false }) {
|
|
1257
1510
|
const dynamicRequestId = uuid.v4();
|
|
1258
1511
|
try {
|
|
1259
1512
|
await this.verifyPassword({
|
|
@@ -1292,7 +1545,8 @@ class DynamicWalletClient {
|
|
|
1292
1545
|
newThresholdSignatureScheme,
|
|
1293
1546
|
dynamicRequestId,
|
|
1294
1547
|
delegateToProjectEnvironment,
|
|
1295
|
-
mfaToken
|
|
1548
|
+
mfaToken,
|
|
1549
|
+
revokeDelegation
|
|
1296
1550
|
});
|
|
1297
1551
|
const { roomId, serverKeygenIds, newServerKeygenIds = [] } = data;
|
|
1298
1552
|
// Get the MPC config for the threshold signature scheme
|
|
@@ -1307,35 +1561,68 @@ class DynamicWalletClient {
|
|
|
1307
1561
|
chainName,
|
|
1308
1562
|
baseRelayUrl: this.baseMPCRelayApiUrl
|
|
1309
1563
|
});
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1564
|
+
const existingResharePromises = existingClientKeyShares.map((keyShare)=>mpcSigner.reshareRemainingParty(roomId, newMpcConfig.threshold, keyShare, allPartyKeygenIds));
|
|
1565
|
+
const newResharePromises = newClientInitKeygenResults.map((keygenResult)=>mpcSigner.reshareNewParty(roomId, oldMpcConfig.threshold, newMpcConfig.threshold, keygenResult, allPartyKeygenIds));
|
|
1566
|
+
// Run both share parties in parallel by group
|
|
1567
|
+
const [existingReshareResults, newReshareResults] = await Promise.all([
|
|
1568
|
+
Promise.all(existingResharePromises),
|
|
1569
|
+
Promise.all(newResharePromises)
|
|
1313
1570
|
]);
|
|
1571
|
+
const clientKeysharesToLocalStorage = delegateToProjectEnvironment ? [
|
|
1572
|
+
...existingReshareResults
|
|
1573
|
+
] : [
|
|
1574
|
+
...existingReshareResults,
|
|
1575
|
+
...newReshareResults
|
|
1576
|
+
];
|
|
1314
1577
|
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1315
1578
|
thresholdSignatureScheme: newThresholdSignatureScheme
|
|
1316
1579
|
});
|
|
1580
|
+
// store client key shares to localStorage
|
|
1317
1581
|
await this.setClientKeySharesToLocalStorage({
|
|
1318
1582
|
accountAddress,
|
|
1319
|
-
clientKeyShares:
|
|
1583
|
+
clientKeyShares: clientKeysharesToLocalStorage,
|
|
1320
1584
|
overwriteOrMerge: 'overwrite'
|
|
1321
1585
|
});
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1586
|
+
const allClientShares = [
|
|
1587
|
+
...existingReshareResults,
|
|
1588
|
+
...newReshareResults
|
|
1589
|
+
];
|
|
1590
|
+
let distribution;
|
|
1591
|
+
if (delegateToProjectEnvironment && backupToGoogleDrive) {
|
|
1592
|
+
// Delegation + Google Drive: Client's existing share backs up to both Dynamic and Google Drive.
|
|
1593
|
+
// The new share goes to the webhook for delegation.
|
|
1594
|
+
distribution = createDelegationWithGoogleDriveDistribution({
|
|
1595
|
+
existingShares: existingReshareResults,
|
|
1596
|
+
delegatedShare: newReshareResults[0]
|
|
1597
|
+
});
|
|
1598
|
+
} else if (delegateToProjectEnvironment) {
|
|
1599
|
+
// Delegation only: Client's existing share backs up to Dynamic.
|
|
1600
|
+
// The new share goes to the webhook for delegation. No Google Drive backup.
|
|
1601
|
+
distribution = createDelegationOnlyDistribution({
|
|
1602
|
+
existingShares: existingReshareResults,
|
|
1603
|
+
delegatedShare: newReshareResults[0]
|
|
1604
|
+
});
|
|
1605
|
+
} else if (backupToGoogleDrive) {
|
|
1606
|
+
// Google Drive only: Split shares between Dynamic (N-1) and Google Drive (1).
|
|
1607
|
+
// The last share (new share) goes to Google Drive.
|
|
1608
|
+
distribution = createGoogleDriveOnlyDistribution({
|
|
1609
|
+
allShares: allClientShares
|
|
1327
1610
|
});
|
|
1328
1611
|
} else {
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
signedSessionId,
|
|
1333
|
-
backupToGoogleDrive
|
|
1612
|
+
// No delegation, no Google Drive: All shares go to Dynamic backend only.
|
|
1613
|
+
distribution = createDynamicOnlyDistribution({
|
|
1614
|
+
allShares: allClientShares
|
|
1334
1615
|
});
|
|
1335
1616
|
}
|
|
1617
|
+
await this.backupSharesWithDistribution({
|
|
1618
|
+
accountAddress,
|
|
1619
|
+
password,
|
|
1620
|
+
signedSessionId,
|
|
1621
|
+
distribution
|
|
1622
|
+
});
|
|
1336
1623
|
} catch (error) {
|
|
1337
1624
|
logError({
|
|
1338
|
-
message: 'Error in reshare',
|
|
1625
|
+
message: 'Error in reshare, resetting wallet to previous state',
|
|
1339
1626
|
error: error,
|
|
1340
1627
|
context: {
|
|
1341
1628
|
accountAddress,
|
|
@@ -1346,52 +1633,25 @@ class DynamicWalletClient {
|
|
|
1346
1633
|
dynamicRequestId
|
|
1347
1634
|
}
|
|
1348
1635
|
});
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
async sendKeySharesToDelegatedAccess({ accountAddress, chainName, delegatedKeyShares, environmentId, userId, walletId }) {
|
|
1353
|
-
try {
|
|
1354
|
-
if (!this.delegatedAccessEndpoint) {
|
|
1355
|
-
throw new Error('Cannot send key shares to delegated access because delegated access endpoint is not set');
|
|
1356
|
-
}
|
|
1357
|
-
const delegatedAccessEndpoint = this.delegatedAccessEndpoint;
|
|
1358
|
-
const response = await fetch(delegatedAccessEndpoint, {
|
|
1359
|
-
method: 'POST',
|
|
1360
|
-
body: JSON.stringify({
|
|
1361
|
-
chainName,
|
|
1362
|
-
accountAddress,
|
|
1363
|
-
delegatedKeyShares,
|
|
1364
|
-
environmentId,
|
|
1365
|
-
userId,
|
|
1366
|
-
walletId
|
|
1367
|
-
})
|
|
1636
|
+
// reset user wallet when reshare fails, this would allow the client to recover wallets from an active state
|
|
1637
|
+
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1638
|
+
thresholdSignatureScheme: oldThresholdSignatureScheme
|
|
1368
1639
|
});
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
message: 'Error in sendKeySharesToDelegatedAccess',
|
|
1374
|
-
error: error,
|
|
1375
|
-
context: {
|
|
1376
|
-
accountAddress,
|
|
1377
|
-
chainName
|
|
1378
|
-
}
|
|
1640
|
+
await this.setClientKeySharesToLocalStorage({
|
|
1641
|
+
accountAddress,
|
|
1642
|
+
clientKeyShares: [],
|
|
1643
|
+
overwriteOrMerge: 'overwrite'
|
|
1379
1644
|
});
|
|
1380
1645
|
throw error;
|
|
1381
1646
|
}
|
|
1382
1647
|
}
|
|
1383
|
-
async
|
|
1648
|
+
async performDelegationOperation({ accountAddress, password, signedSessionId, mfaToken, newThresholdSignatureScheme, revokeDelegation = false, operationName }) {
|
|
1384
1649
|
try {
|
|
1650
|
+
var _this_walletMap_accountAddress;
|
|
1385
1651
|
const delegateToProjectEnvironment = this.featureFlags && this.featureFlags[core.FEATURE_FLAGS.ENABLE_DELEGATED_KEY_SHARES_FLAG] === true;
|
|
1386
1652
|
if (!delegateToProjectEnvironment) {
|
|
1387
1653
|
throw new Error('Delegation is not allowed for this project environment');
|
|
1388
1654
|
}
|
|
1389
|
-
const environmentSettings = await this.apiClient.getEnvironmentSettings();
|
|
1390
|
-
const delegatedAccessEndpoint = environmentSettings.sdk.waas.delegatedAccessEndpoint;
|
|
1391
|
-
if (!delegatedAccessEndpoint) {
|
|
1392
|
-
throw new Error('Cannot delegate key shares because verified access endpoint is not set in the environment settings');
|
|
1393
|
-
}
|
|
1394
|
-
this.delegatedAccessEndpoint = delegatedAccessEndpoint;
|
|
1395
1655
|
const wallet = await this.getWallet({
|
|
1396
1656
|
accountAddress,
|
|
1397
1657
|
walletOperation: core.WalletOperation.REACH_ALL_PARTIES,
|
|
@@ -1402,28 +1662,21 @@ class DynamicWalletClient {
|
|
|
1402
1662
|
throw new Error('Delegation is not allowed for SUI');
|
|
1403
1663
|
}
|
|
1404
1664
|
const currentThresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
});
|
|
1418
|
-
const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
|
|
1419
|
-
const delegatedKeyShares = backupInfo.backups[core.BackupLocation.EXTERNAL] || [];
|
|
1420
|
-
return delegatedKeyShares;
|
|
1421
|
-
} else {
|
|
1422
|
-
throw new Error('Delegation is not allowed for this threshold signature scheme');
|
|
1423
|
-
}
|
|
1665
|
+
await this.reshare({
|
|
1666
|
+
chainName: this.walletMap[accountAddress].chainName,
|
|
1667
|
+
accountAddress,
|
|
1668
|
+
oldThresholdSignatureScheme: currentThresholdSignatureScheme,
|
|
1669
|
+
newThresholdSignatureScheme,
|
|
1670
|
+
password,
|
|
1671
|
+
signedSessionId,
|
|
1672
|
+
backupToGoogleDrive: hasGoogleDriveBackup((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.clientKeySharesBackupInfo),
|
|
1673
|
+
delegateToProjectEnvironment: true,
|
|
1674
|
+
mfaToken,
|
|
1675
|
+
revokeDelegation
|
|
1676
|
+
});
|
|
1424
1677
|
} catch (error) {
|
|
1425
1678
|
logError({
|
|
1426
|
-
message:
|
|
1679
|
+
message: `Error in ${operationName}`,
|
|
1427
1680
|
error: error,
|
|
1428
1681
|
context: {
|
|
1429
1682
|
accountAddress
|
|
@@ -1432,7 +1685,31 @@ class DynamicWalletClient {
|
|
|
1432
1685
|
throw error;
|
|
1433
1686
|
}
|
|
1434
1687
|
}
|
|
1435
|
-
async
|
|
1688
|
+
async delegateKeyShares({ accountAddress, password = undefined, signedSessionId, mfaToken }) {
|
|
1689
|
+
await this.performDelegationOperation({
|
|
1690
|
+
accountAddress,
|
|
1691
|
+
password,
|
|
1692
|
+
signedSessionId,
|
|
1693
|
+
mfaToken,
|
|
1694
|
+
newThresholdSignatureScheme: core.ThresholdSignatureScheme.TWO_OF_THREE,
|
|
1695
|
+
operationName: 'delegateKeyShares'
|
|
1696
|
+
});
|
|
1697
|
+
const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
|
|
1698
|
+
const delegatedKeyShares = backupInfo.backups[core.BackupLocation.DELEGATED] || [];
|
|
1699
|
+
return delegatedKeyShares;
|
|
1700
|
+
}
|
|
1701
|
+
async revokeDelegation({ accountAddress, password = undefined, signedSessionId, mfaToken }) {
|
|
1702
|
+
await this.performDelegationOperation({
|
|
1703
|
+
accountAddress,
|
|
1704
|
+
password,
|
|
1705
|
+
signedSessionId,
|
|
1706
|
+
mfaToken,
|
|
1707
|
+
newThresholdSignatureScheme: core.ThresholdSignatureScheme.TWO_OF_TWO,
|
|
1708
|
+
revokeDelegation: true,
|
|
1709
|
+
operationName: 'revokeDelegation'
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
async exportKey({ accountAddress, chainName, password = undefined, signedSessionId, mfaToken, traceContext }) {
|
|
1436
1713
|
const dynamicRequestId = uuid.v4();
|
|
1437
1714
|
try {
|
|
1438
1715
|
const wallet = await this.getWallet({
|
|
@@ -1458,24 +1735,24 @@ class DynamicWalletClient {
|
|
|
1458
1735
|
dynamicRequestId,
|
|
1459
1736
|
mfaToken
|
|
1460
1737
|
});
|
|
1461
|
-
this.logger.debug('[DynamicWaasWalletClient] Starting export of private key', {
|
|
1738
|
+
this.logger.debug('[DynamicWaasWalletClient] Starting export of private key', _extends({
|
|
1462
1739
|
accountAddress,
|
|
1463
1740
|
chainName,
|
|
1464
1741
|
walletId: wallet.walletId,
|
|
1465
1742
|
exportId,
|
|
1466
1743
|
roomId: data.roomId
|
|
1467
|
-
});
|
|
1744
|
+
}, this.getTraceContext(traceContext)));
|
|
1468
1745
|
const keyExportRaw = await mpcSigner.exportFullPrivateKey(data.roomId, clientKeyShares[0], exportId);
|
|
1469
1746
|
if (!keyExportRaw) {
|
|
1470
1747
|
throw new Error('Error exporting private key');
|
|
1471
1748
|
}
|
|
1472
|
-
this.logger.debug('[DynamicWaasWalletClient] Completed export of private key', {
|
|
1749
|
+
this.logger.debug('[DynamicWaasWalletClient] Completed export of private key', _extends({
|
|
1473
1750
|
accountAddress,
|
|
1474
1751
|
chainName,
|
|
1475
1752
|
walletId: wallet.walletId,
|
|
1476
1753
|
exportId,
|
|
1477
1754
|
roomId: data.roomId
|
|
1478
|
-
});
|
|
1755
|
+
}, this.getTraceContext(traceContext)));
|
|
1479
1756
|
const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
|
|
1480
1757
|
let derivedPrivateKey;
|
|
1481
1758
|
if (mpcSigner instanceof web.Ecdsa) {
|
|
@@ -1492,11 +1769,11 @@ class DynamicWalletClient {
|
|
|
1492
1769
|
logError({
|
|
1493
1770
|
message: 'Error in exportKey',
|
|
1494
1771
|
error: error,
|
|
1495
|
-
context: {
|
|
1772
|
+
context: _extends({
|
|
1496
1773
|
accountAddress,
|
|
1497
1774
|
chainName,
|
|
1498
1775
|
dynamicRequestId
|
|
1499
|
-
}
|
|
1776
|
+
}, this.getTraceContext(traceContext))
|
|
1500
1777
|
});
|
|
1501
1778
|
throw error;
|
|
1502
1779
|
}
|
|
@@ -1596,43 +1873,14 @@ class DynamicWalletClient {
|
|
|
1596
1873
|
});
|
|
1597
1874
|
await ((_this_storage = this.storage) == null ? void 0 : _this_storage.setItem(accountAddress, stringifiedClientKeyShares));
|
|
1598
1875
|
}
|
|
1599
|
-
|
|
1600
|
-
* Central backup orchestrator that encrypts and stores wallet key shares.
|
|
1601
|
-
*
|
|
1602
|
-
* This method serves as the main backup coordinator, handling the distribution of encrypted
|
|
1603
|
-
* key shares between Dynamic's backend and Google Drive based on the wallet's threshold scheme.
|
|
1604
|
-
* It is used by multiple operations including reshare, refresh, and manual backup requests.
|
|
1605
|
-
*
|
|
1606
|
-
* **Backup Distribution Strategy:**
|
|
1607
|
-
* - **Single share wallets**: All shares stored on Dynamic's backend only
|
|
1608
|
-
* - **Multi-share wallets (2+)**: When backing up to Google Drive, N-1 shares on Dynamic's backend, 1 share on Google Drive
|
|
1609
|
-
* - **Multi-share wallets (2+)**: When not backing up to Google Drive, all shares on Dynamic's backend
|
|
1610
|
-
*
|
|
1611
|
-
* **Process Flow:**
|
|
1612
|
-
* 1. Encrypts all client key shares with the provided password (or environment ID if no password)
|
|
1613
|
-
* 2. For multi-share wallets (2+): conditionally distributes N-1 to backend, 1 to Google Drive
|
|
1614
|
-
* 3. For other configurations: stores all shares on Dynamic's backend
|
|
1615
|
-
* 4. Updates backup metadata and synchronizes wallet state
|
|
1616
|
-
* 5. Persists the updated wallet map to local storage
|
|
1617
|
-
*
|
|
1618
|
-
* @param params - The backup operation parameters
|
|
1619
|
-
* @param params.accountAddress - The account address of the wallet to backup
|
|
1620
|
-
* @param params.clientKeyShares - Optional specific key shares to backup (uses localStorage if not provided)
|
|
1621
|
-
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
1622
|
-
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
1623
|
-
* @param params.backupToGoogleDrive - Whether to backup to Google Drive (defaults to false)
|
|
1624
|
-
* @returns Promise with backup metadata including share locations and IDs
|
|
1625
|
-
*/ async storeEncryptedBackupByWallet({ accountAddress, clientKeyShares = undefined, password = undefined, signedSessionId, backupToGoogleDrive = false }) {
|
|
1876
|
+
async backupSharesWithDistribution({ accountAddress, password, signedSessionId, distribution, preserveDelegatedLocation = false }) {
|
|
1626
1877
|
const dynamicRequestId = uuid.v4();
|
|
1627
1878
|
try {
|
|
1628
|
-
var _this_walletMap_accountAddress
|
|
1629
|
-
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
1630
|
-
accountAddress
|
|
1631
|
-
});
|
|
1879
|
+
var _this_walletMap_accountAddress;
|
|
1632
1880
|
if (!((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.walletId)) {
|
|
1633
1881
|
const error = new Error(`WalletId not found for accountAddress ${accountAddress}`);
|
|
1634
1882
|
logError({
|
|
1635
|
-
message: 'Error in
|
|
1883
|
+
message: 'Error in backupSharesWithDistribution, wallet or walletId not found from the wallet map',
|
|
1636
1884
|
error,
|
|
1637
1885
|
context: {
|
|
1638
1886
|
accountAddress,
|
|
@@ -1641,55 +1889,73 @@ class DynamicWalletClient {
|
|
|
1641
1889
|
});
|
|
1642
1890
|
throw error;
|
|
1643
1891
|
}
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
}
|
|
1665
|
-
const data = await this.apiClient.storeEncryptedBackupByWallet({
|
|
1666
|
-
walletId: this.walletMap[accountAddress].walletId,
|
|
1667
|
-
encryptedKeyShares: dynamicClientKeyShares,
|
|
1668
|
-
passwordEncrypted: Boolean(password) && password !== this.environmentId,
|
|
1669
|
-
encryptionVersion: ENCRYPTION_VERSION_CURRENT,
|
|
1670
|
-
signedSessionId,
|
|
1671
|
-
authMode: this.authMode,
|
|
1672
|
-
requiresSignedSessionId: this.requiresSignedSessionId(),
|
|
1673
|
-
dynamicRequestId
|
|
1674
|
-
});
|
|
1675
|
-
if (data.keyShareIds.length === 0) {
|
|
1676
|
-
throw new Error('No key shares were backed up');
|
|
1677
|
-
}
|
|
1678
|
-
const locations = [
|
|
1679
|
-
{
|
|
1892
|
+
const locations = [];
|
|
1893
|
+
if (distribution.dynamicBackendShares.length > 0) {
|
|
1894
|
+
const encryptedDynamicShares = await Promise.all(distribution.dynamicBackendShares.map((keyShare)=>this.encryptKeyShare({
|
|
1895
|
+
keyShare,
|
|
1896
|
+
password
|
|
1897
|
+
})));
|
|
1898
|
+
const data = await this.apiClient.storeEncryptedBackupByWallet({
|
|
1899
|
+
walletId: this.walletMap[accountAddress].walletId,
|
|
1900
|
+
encryptedKeyShares: encryptedDynamicShares,
|
|
1901
|
+
passwordEncrypted: Boolean(password) && password !== this.environmentId,
|
|
1902
|
+
encryptionVersion: ENCRYPTION_VERSION_CURRENT,
|
|
1903
|
+
signedSessionId,
|
|
1904
|
+
authMode: this.authMode,
|
|
1905
|
+
requiresSignedSessionId: this.requiresSignedSessionId(),
|
|
1906
|
+
dynamicRequestId
|
|
1907
|
+
});
|
|
1908
|
+
if (data.keyShareIds.length === 0) {
|
|
1909
|
+
throw new Error('No key shares were backed up to Dynamic backend');
|
|
1910
|
+
}
|
|
1911
|
+
locations.push({
|
|
1680
1912
|
location: core.BackupLocation.DYNAMIC,
|
|
1681
1913
|
externalKeyShareId: data.keyShareIds[0]
|
|
1682
|
-
}
|
|
1683
|
-
|
|
1684
|
-
if (
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
if (distribution.googleDriveShares.length > 0) {
|
|
1917
|
+
const encryptedGoogleDriveShares = await Promise.all(distribution.googleDriveShares.map((keyShare)=>this.encryptKeyShare({
|
|
1918
|
+
keyShare,
|
|
1919
|
+
password
|
|
1920
|
+
})));
|
|
1685
1921
|
await this.uploadKeySharesToGoogleDrive({
|
|
1686
1922
|
accountAddress,
|
|
1687
|
-
encryptedKeyShares:
|
|
1923
|
+
encryptedKeyShares: encryptedGoogleDriveShares
|
|
1688
1924
|
});
|
|
1689
1925
|
locations.push({
|
|
1690
1926
|
location: core.BackupLocation.GOOGLE_DRIVE
|
|
1691
1927
|
});
|
|
1692
1928
|
}
|
|
1929
|
+
if (distribution.delegatedShare) {
|
|
1930
|
+
var _publicKey_key, _publicKey_key1, _publicKey_key2;
|
|
1931
|
+
const publicKey = await this.apiClient.getDelegatedEncryptionKey({
|
|
1932
|
+
environmentId: this.environmentId
|
|
1933
|
+
});
|
|
1934
|
+
if (!(publicKey == null ? void 0 : (_publicKey_key = publicKey.key) == null ? void 0 : _publicKey_key.publicKeyPemB64)) {
|
|
1935
|
+
throw new Error('Public key not found');
|
|
1936
|
+
}
|
|
1937
|
+
var _publicKey_key_keyId;
|
|
1938
|
+
const encryptedDelegatedKeyShareEnvelope = await encryptDelegatedKeyShare(JSON.stringify(distribution.delegatedShare), publicKey == null ? void 0 : (_publicKey_key1 = publicKey.key) == null ? void 0 : _publicKey_key1.publicKeyPemB64, (_publicKey_key_keyId = publicKey == null ? void 0 : (_publicKey_key2 = publicKey.key) == null ? void 0 : _publicKey_key2.keyId) != null ? _publicKey_key_keyId : publicKey == null ? void 0 : publicKey.keyId);
|
|
1939
|
+
const { status } = await this.apiClient.publishDelegatedKeyShare({
|
|
1940
|
+
walletId: this.walletMap[accountAddress].walletId,
|
|
1941
|
+
encryptedKeyShare: encryptedDelegatedKeyShareEnvelope,
|
|
1942
|
+
signedSessionId,
|
|
1943
|
+
requiresSignedSessionId: this.requiresSignedSessionId(),
|
|
1944
|
+
dynamicRequestId
|
|
1945
|
+
});
|
|
1946
|
+
if (status !== 200) {
|
|
1947
|
+
throw new Error('Failed to publish delegated key share');
|
|
1948
|
+
}
|
|
1949
|
+
locations.push({
|
|
1950
|
+
location: core.BackupLocation.DELEGATED
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
// Preserve existing delegated location without re-publishing
|
|
1954
|
+
if (preserveDelegatedLocation && !distribution.delegatedShare) {
|
|
1955
|
+
locations.push({
|
|
1956
|
+
location: core.BackupLocation.DELEGATED
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1693
1959
|
const backupData = await this.apiClient.markKeySharesAsBackedUp({
|
|
1694
1960
|
walletId: this.walletMap[accountAddress].walletId,
|
|
1695
1961
|
locations,
|
|
@@ -1711,10 +1977,10 @@ class DynamicWalletClient {
|
|
|
1711
1977
|
clientKeySharesBackupInfo: updatedBackupInfo
|
|
1712
1978
|
});
|
|
1713
1979
|
await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
|
|
1714
|
-
return
|
|
1980
|
+
return backupData;
|
|
1715
1981
|
} catch (error) {
|
|
1716
1982
|
logError({
|
|
1717
|
-
message: 'Error in
|
|
1983
|
+
message: 'Error in backupSharesWithDistribution',
|
|
1718
1984
|
error: error,
|
|
1719
1985
|
context: {
|
|
1720
1986
|
accountAddress,
|
|
@@ -1724,109 +1990,87 @@ class DynamicWalletClient {
|
|
|
1724
1990
|
throw error;
|
|
1725
1991
|
}
|
|
1726
1992
|
}
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
});
|
|
1792
|
-
data.keyShares.push({
|
|
1793
|
-
backupLocation: core.BackupLocation.EXTERNAL,
|
|
1794
|
-
id: delegatedKeyShareIds
|
|
1795
|
-
});
|
|
1796
|
-
//todo: combine with user share service backup once other branch is merged
|
|
1797
|
-
await this.apiClient.markKeySharesAsBackedUp({
|
|
1798
|
-
walletId: this.walletMap[accountAddress].walletId,
|
|
1799
|
-
locations: [
|
|
1800
|
-
{
|
|
1801
|
-
location: core.BackupLocation.EXTERNAL
|
|
1802
|
-
}
|
|
1803
|
-
],
|
|
1804
|
-
dynamicRequestId
|
|
1805
|
-
});
|
|
1806
|
-
}
|
|
1807
|
-
const updatedBackupInfo = getClientKeyShareBackupInfo({
|
|
1808
|
-
walletProperties: {
|
|
1809
|
-
derivationPath: this.walletMap[accountAddress].derivationPath,
|
|
1810
|
-
keyShares: data.keyShares,
|
|
1811
|
-
thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme
|
|
1812
|
-
}
|
|
1813
|
-
});
|
|
1814
|
-
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
1815
|
-
clientKeySharesBackupInfo: updatedBackupInfo
|
|
1993
|
+
/**
|
|
1994
|
+
* Central backup orchestrator that encrypts and stores wallet key shares.
|
|
1995
|
+
*
|
|
1996
|
+
* This method serves as the main backup coordinator, handling the distribution of encrypted
|
|
1997
|
+
* key shares between Dynamic's backend and Google Drive based on the wallet's threshold scheme.
|
|
1998
|
+
* It is used by multiple operations including reshare, refresh, and manual backup requests.
|
|
1999
|
+
*
|
|
2000
|
+
* **Backup Distribution Strategy:**
|
|
2001
|
+
* - **Single share wallets**: All shares stored on Dynamic's backend only
|
|
2002
|
+
* - **Multi-share wallets (2+)**: When backing up to Google Drive, N-1 shares on Dynamic's backend, 1 share on Google Drive
|
|
2003
|
+
* - **Multi-share wallets (2+)**: When not backing up to Google Drive, all shares on Dynamic's backend
|
|
2004
|
+
*
|
|
2005
|
+
* **Process Flow:**
|
|
2006
|
+
* 1. Encrypts all client key shares with the provided password (or environment ID if no password)
|
|
2007
|
+
* 2. For multi-share wallets (2+): conditionally distributes N-1 to backend, 1 to Google Drive
|
|
2008
|
+
* 3. For other configurations: stores all shares on Dynamic's backend
|
|
2009
|
+
* 4. Updates backup metadata and synchronizes wallet state
|
|
2010
|
+
* 5. Persists the updated wallet map to local storage
|
|
2011
|
+
*
|
|
2012
|
+
* **Delegated Key Shares:**
|
|
2013
|
+
* - When delegatedKeyshare is provided, the method will not store the delegated key share but it will mark the delegated share as backed up on Dynamic's backend
|
|
2014
|
+
* - and encrypt the delegated key share to publish it to the webhook
|
|
2015
|
+
*
|
|
2016
|
+
* @param params - The backup operation parameters
|
|
2017
|
+
* @param params.accountAddress - The account address of the wallet to backup
|
|
2018
|
+
* @param params.clientKeyShares - Optional specific key shares to backup (uses localStorage if not provided)
|
|
2019
|
+
* @param params.password - Optional password for encryption (uses environment ID if not provided)
|
|
2020
|
+
* @param params.signedSessionId - Optional signed session ID for authentication
|
|
2021
|
+
* @param params.backupToGoogleDrive - Whether to backup to Google Drive (defaults to false)
|
|
2022
|
+
* @returns Promise with backup metadata including share locations and IDs
|
|
2023
|
+
*/ async storeEncryptedBackupByWallet({ accountAddress, clientKeyShares = undefined, password = undefined, signedSessionId, backupToGoogleDrive = false, delegatedKeyshare = undefined }) {
|
|
2024
|
+
var _this_walletMap_accountAddress, _this_walletMap_accountAddress1;
|
|
2025
|
+
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
2026
|
+
accountAddress
|
|
2027
|
+
});
|
|
2028
|
+
const shouldBackupToGoogleDrive = backupToGoogleDrive || hasGoogleDriveBackup((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.clientKeySharesBackupInfo);
|
|
2029
|
+
const hasExistingDelegation = hasDelegatedBackup((_this_walletMap_accountAddress1 = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress1.clientKeySharesBackupInfo);
|
|
2030
|
+
let distribution;
|
|
2031
|
+
let preserveDelegatedLocation = false;
|
|
2032
|
+
if (delegatedKeyshare && shouldBackupToGoogleDrive) {
|
|
2033
|
+
// NEW delegation + Google Drive: Client's shares back up to both Dynamic and Google Drive.
|
|
2034
|
+
// The delegated share goes to the webhook.
|
|
2035
|
+
distribution = createDelegationWithGoogleDriveDistribution({
|
|
2036
|
+
existingShares: keySharesToBackup,
|
|
2037
|
+
delegatedShare: delegatedKeyshare
|
|
2038
|
+
});
|
|
2039
|
+
} else if (delegatedKeyshare) {
|
|
2040
|
+
// NEW delegation only: Client's shares back up to Dynamic.
|
|
2041
|
+
// The delegated share goes to the webhook. No Google Drive backup.
|
|
2042
|
+
distribution = createDelegationOnlyDistribution({
|
|
2043
|
+
existingShares: keySharesToBackup,
|
|
2044
|
+
delegatedShare: delegatedKeyshare
|
|
2045
|
+
});
|
|
2046
|
+
} else if (hasExistingDelegation && shouldBackupToGoogleDrive) {
|
|
2047
|
+
// ADD Google Drive to EXISTING delegation: Client's share backs up to both Dynamic and GD.
|
|
2048
|
+
// Don't re-publish delegated share, just preserve the location.
|
|
2049
|
+
distribution = createAddGoogleDriveToExistingDelegationDistribution({
|
|
2050
|
+
clientShares: keySharesToBackup
|
|
2051
|
+
});
|
|
2052
|
+
preserveDelegatedLocation = true;
|
|
2053
|
+
} else if (shouldBackupToGoogleDrive && keySharesToBackup.length >= 2) {
|
|
2054
|
+
// Google Drive only (no delegation): Split shares between Dynamic (N-1) and Google Drive (1).
|
|
2055
|
+
distribution = createGoogleDriveOnlyDistribution({
|
|
2056
|
+
allShares: keySharesToBackup
|
|
1816
2057
|
});
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
message: 'Error in storeEncryptedBackupByDelegatedWallet',
|
|
1822
|
-
error: error,
|
|
1823
|
-
context: {
|
|
1824
|
-
accountAddress,
|
|
1825
|
-
dynamicRequestId
|
|
1826
|
-
}
|
|
2058
|
+
} else {
|
|
2059
|
+
// No delegation, no Google Drive: All shares go to Dynamic backend only.
|
|
2060
|
+
distribution = createDynamicOnlyDistribution({
|
|
2061
|
+
allShares: keySharesToBackup
|
|
1827
2062
|
});
|
|
1828
|
-
throw error;
|
|
1829
2063
|
}
|
|
2064
|
+
const backupData = await this.backupSharesWithDistribution({
|
|
2065
|
+
accountAddress,
|
|
2066
|
+
password,
|
|
2067
|
+
signedSessionId,
|
|
2068
|
+
distribution,
|
|
2069
|
+
preserveDelegatedLocation
|
|
2070
|
+
});
|
|
2071
|
+
return _extends({}, backupData, {
|
|
2072
|
+
keyShareIds: backupData.locationsWithKeyShares.map((ks)=>ks.keyShareId)
|
|
2073
|
+
});
|
|
1830
2074
|
}
|
|
1831
2075
|
async storeEncryptedBackupByWalletWithRetry({ accountAddress, clientKeyShares, password, signedSessionId }) {
|
|
1832
2076
|
await retryPromise(()=>this.storeEncryptedBackupByWallet({
|
|
@@ -2017,14 +2261,18 @@ class DynamicWalletClient {
|
|
|
2017
2261
|
return (_ks_externalKeyShareId = ks.externalKeyShareId) != null ? _ks_externalKeyShareId : '';
|
|
2018
2262
|
});
|
|
2019
2263
|
} else {
|
|
2020
|
-
|
|
2021
|
-
const data = await this.storeEncryptedBackupByWallet({
|
|
2264
|
+
await this.storeEncryptedBackupByWallet({
|
|
2022
2265
|
accountAddress,
|
|
2023
2266
|
password,
|
|
2024
2267
|
signedSessionId,
|
|
2025
2268
|
backupToGoogleDrive: true
|
|
2026
2269
|
});
|
|
2027
|
-
|
|
2270
|
+
const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
|
|
2271
|
+
const googleDriveShares = backupInfo.backups[core.BackupLocation.GOOGLE_DRIVE] || [];
|
|
2272
|
+
return googleDriveShares.map((ks)=>{
|
|
2273
|
+
var _ks_externalKeyShareId;
|
|
2274
|
+
return (_ks_externalKeyShareId = ks.externalKeyShareId) != null ? _ks_externalKeyShareId : '';
|
|
2275
|
+
});
|
|
2028
2276
|
}
|
|
2029
2277
|
} catch (error) {
|
|
2030
2278
|
logError({
|
|
@@ -2060,7 +2308,8 @@ class DynamicWalletClient {
|
|
|
2060
2308
|
const thresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
|
|
2061
2309
|
const fileName = getClientKeyShareExportFileName({
|
|
2062
2310
|
thresholdSignatureScheme,
|
|
2063
|
-
accountAddress
|
|
2311
|
+
accountAddress,
|
|
2312
|
+
isGoogleDrive: true
|
|
2064
2313
|
});
|
|
2065
2314
|
const backupData = createBackupData({
|
|
2066
2315
|
encryptedKeyShares,
|
|
@@ -2085,7 +2334,7 @@ class DynamicWalletClient {
|
|
|
2085
2334
|
throw error;
|
|
2086
2335
|
}
|
|
2087
2336
|
}
|
|
2088
|
-
async
|
|
2337
|
+
async exportClientKeysharesFromGoogleDrive({ accountAddress, password, signedSessionId }) {
|
|
2089
2338
|
try {
|
|
2090
2339
|
await this.getWallet({
|
|
2091
2340
|
accountAddress,
|
|
@@ -2096,15 +2345,16 @@ class DynamicWalletClient {
|
|
|
2096
2345
|
oauthAccountId
|
|
2097
2346
|
});
|
|
2098
2347
|
const thresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
|
|
2099
|
-
const
|
|
2348
|
+
const backupFileName = getClientKeyShareExportFileName({
|
|
2100
2349
|
thresholdSignatureScheme,
|
|
2101
|
-
accountAddress
|
|
2350
|
+
accountAddress,
|
|
2351
|
+
isGoogleDrive: true
|
|
2102
2352
|
});
|
|
2103
2353
|
let backupData = null;
|
|
2104
2354
|
try {
|
|
2105
2355
|
backupData = await retryPromise(()=>downloadFileFromGoogleDrive({
|
|
2106
2356
|
accessToken,
|
|
2107
|
-
fileName
|
|
2357
|
+
fileName: backupFileName
|
|
2108
2358
|
}));
|
|
2109
2359
|
} catch (error) {
|
|
2110
2360
|
logError({
|
|
@@ -2112,7 +2362,7 @@ class DynamicWalletClient {
|
|
|
2112
2362
|
error: error,
|
|
2113
2363
|
context: {
|
|
2114
2364
|
accountAddress,
|
|
2115
|
-
fileName
|
|
2365
|
+
fileName: backupFileName
|
|
2116
2366
|
}
|
|
2117
2367
|
});
|
|
2118
2368
|
throw error;
|
|
@@ -2124,7 +2374,7 @@ class DynamicWalletClient {
|
|
|
2124
2374
|
error: new Error('No backup file found'),
|
|
2125
2375
|
context: {
|
|
2126
2376
|
accountAddress,
|
|
2127
|
-
fileName
|
|
2377
|
+
fileName: backupFileName
|
|
2128
2378
|
}
|
|
2129
2379
|
});
|
|
2130
2380
|
throw error;
|
|
@@ -2137,7 +2387,7 @@ class DynamicWalletClient {
|
|
|
2137
2387
|
error,
|
|
2138
2388
|
context: {
|
|
2139
2389
|
accountAddress,
|
|
2140
|
-
fileName
|
|
2390
|
+
fileName: backupFileName
|
|
2141
2391
|
}
|
|
2142
2392
|
});
|
|
2143
2393
|
throw error;
|
|
@@ -2147,15 +2397,20 @@ class DynamicWalletClient {
|
|
|
2147
2397
|
keyShare,
|
|
2148
2398
|
password
|
|
2149
2399
|
})));
|
|
2150
|
-
|
|
2400
|
+
const text = JSON.stringify(decryptedKeyShares, null, 2);
|
|
2401
|
+
const exportFileName = getClientKeyShareExportFileName({
|
|
2402
|
+
thresholdSignatureScheme,
|
|
2151
2403
|
accountAddress,
|
|
2152
|
-
|
|
2153
|
-
|
|
2404
|
+
isGoogleDrive: true
|
|
2405
|
+
});
|
|
2406
|
+
downloadStringAsFile({
|
|
2407
|
+
filename: exportFileName,
|
|
2408
|
+
content: text,
|
|
2409
|
+
mimeType: 'application/json'
|
|
2154
2410
|
});
|
|
2155
|
-
return decryptedKeyShares;
|
|
2156
2411
|
} catch (error) {
|
|
2157
2412
|
logError({
|
|
2158
|
-
message: 'Error in
|
|
2413
|
+
message: 'Error in exportClientKeysharesFromGoogleDrive',
|
|
2159
2414
|
error: error,
|
|
2160
2415
|
context: {
|
|
2161
2416
|
accountAddress
|
|
@@ -2182,16 +2437,11 @@ class DynamicWalletClient {
|
|
|
2182
2437
|
keyShares: clientKeyShares,
|
|
2183
2438
|
derivationPath
|
|
2184
2439
|
});
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2440
|
+
downloadStringAsFile({
|
|
2441
|
+
filename: `${CLIENT_KEYSHARE_EXPORT_FILENAME_PREFIX}-${accountAddress}.txt`,
|
|
2442
|
+
content: text,
|
|
2443
|
+
mimeType: 'text/plain'
|
|
2189
2444
|
});
|
|
2190
|
-
const url = URL.createObjectURL(blob);
|
|
2191
|
-
const a = document.createElement('a');
|
|
2192
|
-
a.href = url;
|
|
2193
|
-
a.download = `${CLIENT_KEYSHARE_EXPORT_FILENAME_PREFIX}-${accountAddress}.txt`;
|
|
2194
|
-
a.click();
|
|
2195
2445
|
}
|
|
2196
2446
|
async getClientKeyShares({ accountAddress, password, signedSessionId }) {
|
|
2197
2447
|
await this.getWallet({
|
|
@@ -2491,29 +2741,142 @@ class DynamicWalletClient {
|
|
|
2491
2741
|
}
|
|
2492
2742
|
this.apiClient.syncAuthToken(authToken);
|
|
2493
2743
|
}
|
|
2744
|
+
async createRooms({ roomType, thresholdSignatureScheme, roomCount = 5 }) {
|
|
2745
|
+
const numberOfParties = this.getNumberOfParties(roomType, thresholdSignatureScheme);
|
|
2746
|
+
try {
|
|
2747
|
+
var _rooms_roomIds;
|
|
2748
|
+
if (DynamicWalletClient.roomsInitializing[numberOfParties]) {
|
|
2749
|
+
return;
|
|
2750
|
+
}
|
|
2751
|
+
DynamicWalletClient.roomsInitializing[numberOfParties] = true;
|
|
2752
|
+
// Check if rooms for this number of parties already exist (from previous restore or creation)
|
|
2753
|
+
const existingRooms = DynamicWalletClient.rooms[numberOfParties];
|
|
2754
|
+
if (existingRooms && existingRooms.length > 0) {
|
|
2755
|
+
DynamicWalletClient.roomsInitializing[numberOfParties] = false;
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
const rooms = await this.apiClient.createRoomsWithoutWalletId({
|
|
2759
|
+
roomType,
|
|
2760
|
+
roomCount,
|
|
2761
|
+
thresholdSignatureScheme
|
|
2762
|
+
});
|
|
2763
|
+
const newRooms = (rooms == null ? void 0 : (_rooms_roomIds = rooms.roomIds) == null ? void 0 : _rooms_roomIds.map((roomId)=>({
|
|
2764
|
+
roomId,
|
|
2765
|
+
createdAt: Date.now(),
|
|
2766
|
+
expiresAt: Date.now() + ROOM_EXPIRATION_TIME
|
|
2767
|
+
}))) || [];
|
|
2768
|
+
const updatedRooms = [
|
|
2769
|
+
...newRooms,
|
|
2770
|
+
...existingRooms || []
|
|
2771
|
+
];
|
|
2772
|
+
await this.setRooms(numberOfParties, updatedRooms);
|
|
2773
|
+
DynamicWalletClient.roomsInitializing[numberOfParties] = false;
|
|
2774
|
+
} catch (error) {
|
|
2775
|
+
DynamicWalletClient.roomsInitializing[numberOfParties] = false;
|
|
2776
|
+
this.logger.error('Error creating rooms', error);
|
|
2777
|
+
throw error;
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
async restoreRooms() {
|
|
2781
|
+
const roomData = await this.storage.getItem(`${this.storageKey}-rooms`);
|
|
2782
|
+
if (!roomData) {
|
|
2783
|
+
return {};
|
|
2784
|
+
}
|
|
2785
|
+
const parsedRoomData = JSON.parse(roomData);
|
|
2786
|
+
const now = Date.now();
|
|
2787
|
+
// Filter out expired rooms for all party counts
|
|
2788
|
+
const restoredRooms = {};
|
|
2789
|
+
for (const [partiesStr, rooms] of Object.entries(parsedRoomData)){
|
|
2790
|
+
const numberOfParties = Number(partiesStr);
|
|
2791
|
+
const validRooms = rooms.filter((room)=>room.expiresAt > now);
|
|
2792
|
+
if (validRooms.length > 0) {
|
|
2793
|
+
restoredRooms[numberOfParties] = validRooms;
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
// Restore all rooms to the static property
|
|
2797
|
+
DynamicWalletClient.rooms = restoredRooms;
|
|
2798
|
+
return restoredRooms;
|
|
2799
|
+
}
|
|
2800
|
+
async getRooms(roomType, thresholdSignatureScheme) {
|
|
2801
|
+
if (roomType && thresholdSignatureScheme) {
|
|
2802
|
+
const numberOfParties = this.getNumberOfParties(roomType, thresholdSignatureScheme);
|
|
2803
|
+
return DynamicWalletClient.rooms[numberOfParties] || [];
|
|
2804
|
+
}
|
|
2805
|
+
return DynamicWalletClient.rooms;
|
|
2806
|
+
}
|
|
2807
|
+
async setRooms(numberOfParties, rooms) {
|
|
2808
|
+
DynamicWalletClient.rooms[numberOfParties] = rooms;
|
|
2809
|
+
await this.storage.setItem(`${this.storageKey}-rooms`, JSON.stringify(DynamicWalletClient.rooms));
|
|
2810
|
+
}
|
|
2811
|
+
getNumberOfParties(roomType, thresholdSignatureScheme) {
|
|
2812
|
+
const MPC_SCHEME_CONFIG = core.MPC_CONFIG[thresholdSignatureScheme];
|
|
2813
|
+
return roomType === sdkApiCore.RoomTypeEnum.Threshold ? MPC_SCHEME_CONFIG.threshold : MPC_SCHEME_CONFIG.numberOfParties;
|
|
2814
|
+
}
|
|
2815
|
+
async getRoom(roomType, thresholdSignatureScheme) {
|
|
2816
|
+
const numberOfParties = this.getNumberOfParties(roomType, thresholdSignatureScheme);
|
|
2817
|
+
const now = Date.now();
|
|
2818
|
+
const schemeRooms = DynamicWalletClient.rooms[numberOfParties] || [];
|
|
2819
|
+
// Filter out expired rooms
|
|
2820
|
+
const filteredRooms = schemeRooms.filter((room)=>room.expiresAt > now);
|
|
2821
|
+
await this.setRooms(numberOfParties, filteredRooms);
|
|
2822
|
+
const room = filteredRooms.shift();
|
|
2823
|
+
if (room) {
|
|
2824
|
+
await this.setRooms(numberOfParties, filteredRooms);
|
|
2825
|
+
}
|
|
2826
|
+
// If less than or only 1 room left after removing one, trigger async creation for more rooms
|
|
2827
|
+
// Check the length after removing the room
|
|
2828
|
+
const remainingRooms = DynamicWalletClient.rooms[numberOfParties] || [];
|
|
2829
|
+
if (remainingRooms.length <= 1) {
|
|
2830
|
+
this.createRooms({
|
|
2831
|
+
roomType,
|
|
2832
|
+
thresholdSignatureScheme,
|
|
2833
|
+
roomCount: ROOM_CACHE_COUNT
|
|
2834
|
+
});
|
|
2835
|
+
}
|
|
2836
|
+
return room;
|
|
2837
|
+
}
|
|
2838
|
+
/**
|
|
2839
|
+
* Helper method to instrument with automatic properties inclusion
|
|
2840
|
+
*/ instrument(message, context) {
|
|
2841
|
+
const defaultContext = {
|
|
2842
|
+
environmentId: context.environmentId || this.environmentId
|
|
2843
|
+
};
|
|
2844
|
+
this.logger.debug(message, _extends({}, defaultContext, context));
|
|
2845
|
+
this.logger.instrument(message, _extends({}, defaultContext, context));
|
|
2846
|
+
}
|
|
2847
|
+
getTraceContext(traceContext) {
|
|
2848
|
+
const now = Date.now();
|
|
2849
|
+
return _extends({
|
|
2850
|
+
now,
|
|
2851
|
+
time: (traceContext == null ? void 0 : traceContext.startTime) ? now - traceContext.startTime : 0
|
|
2852
|
+
}, traceContext);
|
|
2853
|
+
}
|
|
2494
2854
|
constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, storageKey, debug, featureFlags, authMode = core.AuthMode.HEADER, authToken = undefined, // Represents the version of the client SDK used by developer
|
|
2495
|
-
sdkVersion }){
|
|
2855
|
+
sdkVersion, forwardMPCClient, baseClientKeysharesRelayApiUrl }){
|
|
2496
2856
|
this.userId = undefined;
|
|
2497
2857
|
this.sessionId = undefined;
|
|
2498
|
-
this.delegatedAccessEndpoint = undefined;
|
|
2499
2858
|
this.initializePromise = null;
|
|
2500
2859
|
this.logger = logger;
|
|
2501
2860
|
this.walletMap = {} // todo: store in session storage
|
|
2502
2861
|
;
|
|
2503
2862
|
this.memoryStorage = null;
|
|
2504
2863
|
this.iframe = null;
|
|
2864
|
+
this.forwardMPCEnabled = false;
|
|
2505
2865
|
this.featureFlags = {};
|
|
2506
2866
|
this.environmentId = environmentId;
|
|
2507
2867
|
this.storageKey = `${STORAGE_KEY}-${storageKey != null ? storageKey : environmentId}`;
|
|
2508
2868
|
this.baseMPCRelayApiUrl = baseMPCRelayApiUrl;
|
|
2509
2869
|
this.authMode = authMode;
|
|
2510
2870
|
this.sdkVersion = sdkVersion;
|
|
2871
|
+
this.baseClientKeysharesRelayApiUrl = baseClientKeysharesRelayApiUrl;
|
|
2511
2872
|
this.apiClient = new core.DynamicApiClient({
|
|
2512
2873
|
environmentId,
|
|
2513
2874
|
authToken,
|
|
2514
2875
|
baseApiUrl,
|
|
2515
2876
|
authMode,
|
|
2516
|
-
sdkVersion
|
|
2877
|
+
sdkVersion,
|
|
2878
|
+
forwardMPCClient,
|
|
2879
|
+
baseClientKeysharesRelayApiUrl
|
|
2517
2880
|
});
|
|
2518
2881
|
this.debug = Boolean(debug);
|
|
2519
2882
|
this.logger.setLogLevel(this.debug ? logger$1.LogLevel.DEBUG : DEFAULT_LOG_LEVEL);
|
|
@@ -2533,8 +2896,15 @@ class DynamicWalletClient {
|
|
|
2533
2896
|
if (authMode === core.AuthMode.HEADER && authToken) {
|
|
2534
2897
|
this.initLoggerContext(authToken);
|
|
2535
2898
|
}
|
|
2899
|
+
this.forwardMPCEnabled = this.featureFlags && this.featureFlags[core.FEATURE_FLAGS.ENABLE_FORWARD_MPC_CLIENT_FLAG] === true;
|
|
2900
|
+
// if forwardMPCEnabled is true and forwardMPCClient is not provided, initialize the forwardMPCClient
|
|
2901
|
+
if (this.forwardMPCEnabled && !forwardMPCClient) {
|
|
2902
|
+
this.initializeForwardMPCClient();
|
|
2903
|
+
}
|
|
2536
2904
|
}
|
|
2537
2905
|
}
|
|
2906
|
+
DynamicWalletClient.rooms = {};
|
|
2907
|
+
DynamicWalletClient.roomsInitializing = {};
|
|
2538
2908
|
|
|
2539
2909
|
const ERROR_KEYGEN_FAILED = '[DynamicWaasWalletClient]: Error with keygen';
|
|
2540
2910
|
const ERROR_CREATE_WALLET_ACCOUNT = '[DynamicWaasWalletClient]: Error creating wallet account';
|
|
@@ -2608,7 +2978,13 @@ exports.ERROR_SIGN_MESSAGE = ERROR_SIGN_MESSAGE;
|
|
|
2608
2978
|
exports.ERROR_SIGN_TYPED_DATA = ERROR_SIGN_TYPED_DATA;
|
|
2609
2979
|
exports.ERROR_VERIFY_MESSAGE_SIGNATURE = ERROR_VERIFY_MESSAGE_SIGNATURE;
|
|
2610
2980
|
exports.ERROR_VERIFY_TRANSACTION_SIGNATURE = ERROR_VERIFY_TRANSACTION_SIGNATURE;
|
|
2981
|
+
exports.createAddGoogleDriveToExistingDelegationDistribution = createAddGoogleDriveToExistingDelegationDistribution;
|
|
2611
2982
|
exports.createBackupData = createBackupData;
|
|
2983
|
+
exports.createDelegationOnlyDistribution = createDelegationOnlyDistribution;
|
|
2984
|
+
exports.createDelegationWithGoogleDriveDistribution = createDelegationWithGoogleDriveDistribution;
|
|
2985
|
+
exports.createDynamicOnlyDistribution = createDynamicOnlyDistribution;
|
|
2986
|
+
exports.createGoogleDriveOnlyDistribution = createGoogleDriveOnlyDistribution;
|
|
2987
|
+
exports.downloadStringAsFile = downloadStringAsFile;
|
|
2612
2988
|
exports.formatEvmMessage = formatEvmMessage;
|
|
2613
2989
|
exports.formatMessage = formatMessage;
|
|
2614
2990
|
exports.getClientKeyShareBackupInfo = getClientKeyShareBackupInfo;
|
|
@@ -2616,6 +2992,8 @@ exports.getClientKeyShareExportFileName = getClientKeyShareExportFileName;
|
|
|
2616
2992
|
exports.getGoogleOAuthAccountId = getGoogleOAuthAccountId;
|
|
2617
2993
|
exports.getMPCSignatureScheme = getMPCSignatureScheme;
|
|
2618
2994
|
exports.getMPCSigner = getMPCSigner;
|
|
2995
|
+
exports.hasDelegatedBackup = hasDelegatedBackup;
|
|
2996
|
+
exports.hasGoogleDriveBackup = hasGoogleDriveBackup;
|
|
2619
2997
|
exports.isBrowser = isBrowser;
|
|
2620
2998
|
exports.isHexString = isHexString;
|
|
2621
2999
|
exports.mergeUniqueKeyShares = mergeUniqueKeyShares;
|