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