@dynamic-labs-wallet/node 0.0.0-beta-191.1

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.
Files changed (51) hide show
  1. package/index.cjs.d.ts +1 -0
  2. package/index.cjs.js +1176 -0
  3. package/index.esm.d.ts +1 -0
  4. package/index.esm.js +1112 -0
  5. package/internal/core/bip340.d.ts +22 -0
  6. package/internal/core/bip340.js +1 -0
  7. package/internal/core/common.d.ts +1 -0
  8. package/internal/core/common.js +1 -0
  9. package/internal/core/ecdsa.d.ts +23 -0
  10. package/internal/core/ecdsa.js +1 -0
  11. package/internal/core/ed25519.d.ts +22 -0
  12. package/internal/core/ed25519.js +1 -0
  13. package/internal/core/ed25519_exportable.d.ts +21 -0
  14. package/internal/core/ed25519_exportable.js +1 -0
  15. package/internal/core/index.d.ts +8 -0
  16. package/internal/core/index.js +1 -0
  17. package/internal/core/native.d.ts +168 -0
  18. package/internal/core/native.js +1 -0
  19. package/internal/core/sr25519.d.ts +22 -0
  20. package/internal/core/sr25519.js +1 -0
  21. package/internal/core/types.d.ts +78 -0
  22. package/internal/core/types.js +1 -0
  23. package/internal/node/index.d.ts +17 -0
  24. package/internal/node/index.js +1 -0
  25. package/internal/node/native/libmpc_executor_linux_arm64_nodejs.node +0 -0
  26. package/internal/node/native/libmpc_executor_linux_x86_64_nodejs.node +0 -0
  27. package/internal/node/native/libmpc_executor_macos_arm64_nodejs.node +0 -0
  28. package/internal/node/native/libmpc_executor_macos_x86_64_nodejs.node +0 -0
  29. package/internal/node/native.d.ts +2 -0
  30. package/internal/node/native.js +1 -0
  31. package/package.json +34 -0
  32. package/src/backup/encryption.d.ts +22 -0
  33. package/src/backup/encryption.d.ts.map +1 -0
  34. package/src/client.d.ts +261 -0
  35. package/src/client.d.ts.map +1 -0
  36. package/src/constants.d.ts +2 -0
  37. package/src/constants.d.ts.map +1 -0
  38. package/src/index.d.ts +6 -0
  39. package/src/index.d.ts.map +1 -0
  40. package/src/mpc/index.d.ts +3 -0
  41. package/src/mpc/index.d.ts.map +1 -0
  42. package/src/mpc/mpc.d.ts +12 -0
  43. package/src/mpc/mpc.d.ts.map +1 -0
  44. package/src/mpc/types.d.ts +6 -0
  45. package/src/mpc/types.d.ts.map +1 -0
  46. package/src/services/logger.d.ts +3 -0
  47. package/src/services/logger.d.ts.map +1 -0
  48. package/src/types.d.ts +12 -0
  49. package/src/types.d.ts.map +1 -0
  50. package/src/utils.d.ts +34 -0
  51. package/src/utils.d.ts.map +1 -0
package/index.cjs.js ADDED
@@ -0,0 +1,1176 @@
1
+ 'use strict';
2
+
3
+ var core = require('@dynamic-labs-wallet/core');
4
+ var node = require('./internal/node');
5
+ var logger$1 = require('@dynamic-labs/logger');
6
+ var crypto = require('crypto');
7
+
8
+ const getMPCSignatureScheme = ({ signingAlgorithm, baseRelayUrl = core.MPC_RELAY_PROD_API_URL })=>{
9
+ switch(signingAlgorithm){
10
+ case core.SigningAlgorithm.ECDSA:
11
+ return new node.Ecdsa(baseRelayUrl);
12
+ case core.SigningAlgorithm.ED25519:
13
+ return new node.Ed25519(baseRelayUrl);
14
+ case core.SigningAlgorithm.BIP340:
15
+ return new node.BIP340(baseRelayUrl);
16
+ default:
17
+ throw new Error(`Unsupported signing algorithm: ${signingAlgorithm}`);
18
+ }
19
+ };
20
+ const getMPCSigner = ({ chainName, baseRelayUrl })=>{
21
+ const chainConfig = core.getMPCChainConfig(chainName);
22
+ const signatureScheme = getMPCSignatureScheme({
23
+ signingAlgorithm: chainConfig.signingAlgorithm,
24
+ baseRelayUrl
25
+ });
26
+ return signatureScheme;
27
+ };
28
+
29
+ function _extends() {
30
+ _extends = Object.assign || function assign(target) {
31
+ for(var i = 1; i < arguments.length; i++){
32
+ var source = arguments[i];
33
+ for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
34
+ }
35
+ return target;
36
+ };
37
+ return _extends.apply(this, arguments);
38
+ }
39
+
40
+ const logger = new logger$1.Logger('DynamicWaasWalletClient');
41
+
42
+ const bytesToBase64 = (arr)=>{
43
+ return btoa(Array.from(arr, (b)=>String.fromCharCode(b)).join(''));
44
+ };
45
+ const stringToBytes = (str)=>{
46
+ return new TextEncoder().encode(str);
47
+ };
48
+ const base64ToBytes = (base64)=>{
49
+ return new Uint8Array(Buffer.from(base64, 'base64'));
50
+ };
51
+ // Helper function to ensure proper base64 padding
52
+ const ensureBase64Padding = (str)=>{
53
+ return str.padEnd(Math.ceil(str.length / 4) * 4, '=');
54
+ };
55
+ const isHexString = (str)=>{
56
+ // Remove 0x prefix if present
57
+ const hex = str.startsWith('0x') ? str.slice(2) : str;
58
+ // Check if string contains only hex characters
59
+ return /^[0-9A-Fa-f]+$/.test(hex);
60
+ };
61
+ const getExternalServerKeyShareBackupInfo = (params)=>{
62
+ var _params_walletProperties, _params_walletProperties_keyShares_;
63
+ const backups = {
64
+ [core.BackupLocation.DYNAMIC]: [],
65
+ [core.BackupLocation.GOOGLE_DRIVE]: [],
66
+ [core.BackupLocation.ICLOUD]: [],
67
+ [core.BackupLocation.USER]: [],
68
+ [core.BackupLocation.EXTERNAL]: []
69
+ };
70
+ if (!(params == null ? void 0 : (_params_walletProperties = params.walletProperties) == null ? void 0 : _params_walletProperties.keyShares)) {
71
+ return {
72
+ backups,
73
+ passwordEncrypted: false
74
+ };
75
+ }
76
+ params.walletProperties.keyShares.forEach((keyShare)=>{
77
+ if (backups[keyShare.backupLocation]) {
78
+ backups[keyShare.backupLocation].push(keyShare.id);
79
+ }
80
+ });
81
+ const passwordEncrypted = Boolean((_params_walletProperties_keyShares_ = params.walletProperties.keyShares[0]) == null ? void 0 : _params_walletProperties_keyShares_.passwordEncrypted);
82
+ return {
83
+ backups,
84
+ passwordEncrypted
85
+ };
86
+ };
87
+ /**
88
+ * Helper function to merge keyshares and remove duplicates based on pubkey and secretShare
89
+ * @param existingKeyShares - Array of existing keyshares
90
+ * @param newKeyShares - Array of new keyshares to merge
91
+ * @returns Array of merged unique keyshares
92
+ */ const mergeUniqueKeyShares = (existingKeyShares, newKeyShares)=>{
93
+ const uniqueKeyShares = newKeyShares.filter((newShare)=>!existingKeyShares.some((existingShare)=>{
94
+ if (!(newShare == null ? void 0 : newShare.pubkey) || !(existingShare == null ? void 0 : existingShare.pubkey)) return false;
95
+ return newShare.pubkey.toString() === existingShare.pubkey.toString() && newShare.secretShare === existingShare.secretShare;
96
+ }));
97
+ return [
98
+ ...existingKeyShares,
99
+ ...uniqueKeyShares
100
+ ];
101
+ };
102
+ /**
103
+ * Generic helper function to retry a promise-based operations
104
+ *
105
+ * @param operation - The async operation to retry
106
+ * @param config - Configuration options for retry behavior
107
+ * @returns Promise with the operation result
108
+ * @throws Last error encountered after all retries are exhausted
109
+ */ async function retryPromise(operation, { maxAttempts = 5, retryInterval = 500, operationName = 'operation', logContext = {} } = {}) {
110
+ let attempts = 0;
111
+ while(attempts < maxAttempts){
112
+ try {
113
+ return await operation();
114
+ } catch (error) {
115
+ attempts++;
116
+ if (attempts === maxAttempts) {
117
+ logger.error(`Failed to execute ${operationName} after ${maxAttempts} attempts`, _extends({}, logContext, {
118
+ error
119
+ }));
120
+ throw error;
121
+ }
122
+ await new Promise((resolve)=>setTimeout(resolve, retryInterval));
123
+ }
124
+ }
125
+ // TypeScript needs this even though it's unreachable
126
+ throw new Error('Unreachable code');
127
+ }
128
+
129
+ const PBKDF2_ALGORITHM = 'PBKDF2';
130
+ const PBKDF2_ITERATIONS = 100000;
131
+ const PBKDF2_HASH_ALGORITHM = 'SHA-256';
132
+ const AES_GCM_ALGORITHM = 'AES-GCM';
133
+ const AES_GCM_LENGTH = 256;
134
+ const getKey = async ({ password, salt })=>{
135
+ const passwordBytes = stringToBytes(password);
136
+ const initialKey = await crypto.subtle.importKey('raw', passwordBytes, {
137
+ name: 'PBKDF2'
138
+ }, false, [
139
+ 'deriveKey'
140
+ ]);
141
+ return crypto.subtle.deriveKey({
142
+ name: PBKDF2_ALGORITHM,
143
+ salt,
144
+ iterations: PBKDF2_ITERATIONS,
145
+ hash: PBKDF2_HASH_ALGORITHM
146
+ }, initialKey, {
147
+ name: AES_GCM_ALGORITHM,
148
+ length: AES_GCM_LENGTH
149
+ }, false, [
150
+ 'encrypt',
151
+ 'decrypt'
152
+ ]);
153
+ };
154
+ const encryptData = async ({ data, password })=>{
155
+ try {
156
+ // Generate a random salt and IV
157
+ const salt = crypto.getRandomValues(new Uint8Array(16));
158
+ const iv = crypto.getRandomValues(new Uint8Array(12)); // AES-GCM requires 12 bytes
159
+ const key = await getKey({
160
+ password,
161
+ salt
162
+ });
163
+ // Convert the input string to bytes
164
+ const dataBytes = new TextEncoder().encode(data);
165
+ // Encrypt the data
166
+ const encryptedData = await crypto.subtle.encrypt({
167
+ name: AES_GCM_ALGORITHM,
168
+ iv
169
+ }, key, dataBytes);
170
+ // Convert to base64 strings, ensure proper padding
171
+ return {
172
+ salt: bytesToBase64(salt),
173
+ iv: bytesToBase64(iv),
174
+ cipher: bytesToBase64(new Uint8Array(encryptedData))
175
+ };
176
+ } catch (error) {
177
+ throw new Error('Error encrypting data');
178
+ }
179
+ };
180
+ const decryptData = async ({ data, password })=>{
181
+ try {
182
+ const { salt, iv, cipher } = data;
183
+ // Ensure proper base64 padding for all values
184
+ const paddedSalt = ensureBase64Padding(salt);
185
+ const paddedIv = ensureBase64Padding(iv);
186
+ const paddedCipher = ensureBase64Padding(cipher);
187
+ const saltBytes = base64ToBytes(paddedSalt);
188
+ const ivBytes = base64ToBytes(paddedIv);
189
+ const cipherBytes = base64ToBytes(paddedCipher);
190
+ const key = await getKey({
191
+ password,
192
+ salt: saltBytes
193
+ });
194
+ const decryptedData = await crypto.subtle.decrypt({
195
+ name: AES_GCM_ALGORITHM,
196
+ iv: ivBytes
197
+ }, key, cipherBytes);
198
+ return new TextDecoder().decode(decryptedData);
199
+ } catch (error) {
200
+ throw new Error('Decryption failed');
201
+ }
202
+ };
203
+
204
+ const DEFAULT_LOG_LEVEL = 'INFO';
205
+
206
+ class DynamicWalletClient {
207
+ ensureApiClientAuthenticated() {
208
+ if (!this.isApiClientAuthenticated) {
209
+ throw new Error('Client must be authenticated before making API calls. Call authenticateApiToken first.');
210
+ }
211
+ }
212
+ async authenticateApiToken(authToken) {
213
+ const tmpClient = new core.DynamicApiClient({
214
+ environmentId: this.environmentId,
215
+ authToken,
216
+ baseApiUrl: this.baseApiUrl
217
+ });
218
+ const response = await tmpClient.authenticateApiToken({
219
+ environmentId: this.environmentId
220
+ });
221
+ const jwtTokenAuth = response.data.encodedJwts.minifiedJwt;
222
+ this.baseJWTAuthToken = jwtTokenAuth;
223
+ this.apiClient = new core.DynamicApiClient({
224
+ environmentId: this.environmentId,
225
+ authToken: jwtTokenAuth,
226
+ baseApiUrl: this.baseApiUrl
227
+ });
228
+ this.isApiClientAuthenticated = true;
229
+ }
230
+ async dynamicServerInitializeKeyGen({ chainName, externalServerKeygenIds, thresholdSignatureScheme, onError, onCeremonyComplete }) {
231
+ this.ensureApiClientAuthenticated();
232
+ try {
233
+ const data = await this.apiClient.createWalletAccount({
234
+ chainName,
235
+ clientKeygenIds: externalServerKeygenIds,
236
+ thresholdSignatureScheme,
237
+ onError,
238
+ onCeremonyComplete
239
+ });
240
+ return data;
241
+ } catch (error) {
242
+ this.logger.error('Error in dynamicServerInitializeKeyGen', error);
243
+ throw new Error('Error creating wallet account in dynamicServerInitializeKeyGen');
244
+ }
245
+ }
246
+ async externalServerInitializeKeyGen({ chainName, thresholdSignatureScheme }) {
247
+ try {
248
+ // Get the mpc signer
249
+ const mpcSigner = getMPCSigner({
250
+ chainName,
251
+ baseRelayUrl: this.baseMPCRelayApiUrl
252
+ });
253
+ const clientThreshold = core.getClientThreshold(thresholdSignatureScheme);
254
+ const keygenInitResults = await Promise.all(Array(clientThreshold).fill(null).map(()=>mpcSigner.initKeygen()));
255
+ return keygenInitResults;
256
+ } catch (error) {
257
+ this.logger.error('Error in externalServerInitializeKeyGen', error);
258
+ throw new Error('Error initializing keygen in externalServerInitializeKeyGen');
259
+ }
260
+ }
261
+ async derivePublicKey({ chainName, keyShare, derivationPath }) {
262
+ try {
263
+ const mpcSigner = getMPCSigner({
264
+ chainName,
265
+ baseRelayUrl: this.baseMPCRelayApiUrl
266
+ });
267
+ let publicKey;
268
+ if (mpcSigner instanceof node.Ecdsa) {
269
+ publicKey = await mpcSigner.derivePubkey(keyShare, derivationPath);
270
+ } else if (mpcSigner instanceof node.Ed25519) {
271
+ publicKey = await mpcSigner.derivePubkey(keyShare, derivationPath);
272
+ }
273
+ return publicKey;
274
+ } catch (error) {
275
+ this.logger.error('Error in derivePublicKey', error);
276
+ throw new Error('Error deriving public key in derivePublicKey');
277
+ }
278
+ }
279
+ async externalServerKeyGen({ chainName, roomId, dynamicServerKeygenIds, externalServerInitKeygenResults, thresholdSignatureScheme }) {
280
+ try {
281
+ // Get the chain config and the mpc signer
282
+ const mpcSigner = getMPCSigner({
283
+ chainName,
284
+ baseRelayUrl: this.baseMPCRelayApiUrl
285
+ });
286
+ // Get the MPC config for the threshold signature scheme
287
+ const mpcConfig = core.MPC_CONFIG[thresholdSignatureScheme];
288
+ // For each client keygen init result, create an array of other parties' keygenIds
289
+ const serverKeygenResults = await Promise.all(externalServerInitKeygenResults.map((currentInit)=>{
290
+ // Get all other client keygenIds (excluding current one)
291
+ const otherExternalServerKeygenIds = externalServerInitKeygenResults.filter((init)=>init.keygenId !== currentInit.keygenId).map((init)=>init.keygenId);
292
+ // Combine server keygenIds with other client keygenIds
293
+ const allOtherKeygenIds = [
294
+ ...dynamicServerKeygenIds,
295
+ ...otherExternalServerKeygenIds
296
+ ];
297
+ return mpcSigner.keygen(roomId, mpcConfig.numberOfParties, mpcConfig.threshold, currentInit, allOtherKeygenIds);
298
+ }));
299
+ // only need one client keygen result to derive the public key
300
+ const [serverKeygenResult] = serverKeygenResults;
301
+ const chainConfig = core.getMPCChainConfig(chainName);
302
+ const derivationPath = new Uint32Array(chainConfig.derivationPath);
303
+ const rawPublicKey = await this.derivePublicKey({
304
+ chainName,
305
+ keyShare: serverKeygenResult,
306
+ derivationPath
307
+ });
308
+ return {
309
+ rawPublicKey,
310
+ externalServerKeyGenResults: serverKeygenResults
311
+ };
312
+ } catch (error) {
313
+ this.logger.error('Error in externalServerKeyGen', error);
314
+ throw new Error('Error deriving public key in externalServerKeyGen');
315
+ }
316
+ }
317
+ async keyGen({ chainName, thresholdSignatureScheme, onError, onCeremonyComplete }) {
318
+ try {
319
+ const externalServerInitKeygenResults = await this.externalServerInitializeKeyGen({
320
+ chainName,
321
+ thresholdSignatureScheme
322
+ });
323
+ const externalServerKeygenIds = externalServerInitKeygenResults.map((result)=>result.keygenId);
324
+ const { roomId, serverKeygenIds: dynamicServerKeygenIds } = await this.dynamicServerInitializeKeyGen({
325
+ chainName,
326
+ externalServerKeygenIds,
327
+ thresholdSignatureScheme,
328
+ onCeremonyComplete
329
+ });
330
+ const { rawPublicKey, externalServerKeyGenResults } = await this.externalServerKeyGen({
331
+ chainName,
332
+ roomId,
333
+ dynamicServerKeygenIds,
334
+ externalServerInitKeygenResults,
335
+ thresholdSignatureScheme
336
+ });
337
+ return {
338
+ rawPublicKey,
339
+ externalServerKeyShares: externalServerKeyGenResults
340
+ };
341
+ } catch (error) {
342
+ this.logger.error('Error in keyGen', error);
343
+ throw new Error('Error creating wallet account in keyGen');
344
+ }
345
+ }
346
+ async importRawPrivateKey({ chainName, privateKey, thresholdSignatureScheme, onError, onCeremonyComplete }) {
347
+ this.ensureApiClientAuthenticated();
348
+ const mpcSigner = getMPCSigner({
349
+ chainName,
350
+ baseRelayUrl: this.baseMPCRelayApiUrl
351
+ });
352
+ const externalServerKeygenInitResults = await this.externalServerInitializeKeyGen({
353
+ chainName,
354
+ thresholdSignatureScheme
355
+ });
356
+ const externalServerKeygenIds = externalServerKeygenInitResults.map((result)=>result.keygenId);
357
+ const { roomId, serverKeygenIds: dynamicServerKeygenIds } = await this.apiClient.importPrivateKey({
358
+ chainName,
359
+ clientKeygenIds: externalServerKeygenIds,
360
+ thresholdSignatureScheme,
361
+ onError,
362
+ onCeremonyComplete
363
+ });
364
+ const { threshold } = core.getTSSConfig(thresholdSignatureScheme);
365
+ const externalServerKeygenResults = await Promise.all(externalServerKeygenInitResults.map(async (currentInit, index)=>{
366
+ const otherExternalServerKeygenIds = externalServerKeygenInitResults.filter((init)=>init.keygenId !== currentInit.keygenId).map((init)=>init.keygenId);
367
+ if (index === 0) {
368
+ const otherKeyGenIds = [
369
+ ...dynamicServerKeygenIds,
370
+ ...otherExternalServerKeygenIds
371
+ ];
372
+ const importerKeygenResult = await mpcSigner.importPrivateKeyImporter(roomId, threshold, privateKey, currentInit, otherKeyGenIds);
373
+ return importerKeygenResult;
374
+ } else {
375
+ const recipientKeygenResult = await mpcSigner.importPrivateKeyRecipient(roomId, threshold, currentInit, [
376
+ ...dynamicServerKeygenIds,
377
+ ...otherExternalServerKeygenIds
378
+ ]);
379
+ return recipientKeygenResult;
380
+ }
381
+ }));
382
+ const [externalServerKeygenResult] = externalServerKeygenResults;
383
+ const rawPublicKey = await this.derivePublicKey({
384
+ chainName,
385
+ keyShare: externalServerKeygenResult,
386
+ derivationPath: undefined
387
+ });
388
+ return {
389
+ rawPublicKey,
390
+ externalServerKeyShares: externalServerKeygenResults
391
+ };
392
+ }
393
+ async dynamicServerSign({ walletId, message }) {
394
+ this.ensureApiClientAuthenticated();
395
+ // Create the room and sign the message
396
+ if (typeof message !== 'string') {
397
+ message = '0x' + Buffer.from(message).toString('hex');
398
+ }
399
+ const data = await this.apiClient.signMessage({
400
+ walletId,
401
+ message
402
+ });
403
+ return data;
404
+ }
405
+ async externalServerSign({ chainName, message, roomId, keyShare, derivationPath }) {
406
+ try {
407
+ const mpcSigner = getMPCSigner({
408
+ chainName,
409
+ baseRelayUrl: this.baseMPCRelayApiUrl
410
+ });
411
+ let formattedMessage;
412
+ //note: Ecdsa can also be used by bitcoin, but only keccak256 is used by ethereum
413
+ if (mpcSigner instanceof node.Ecdsa) {
414
+ formattedMessage = node.MessageHash.keccak256(message);
415
+ } else if (mpcSigner instanceof node.Ed25519) {
416
+ if (typeof message === 'string') {
417
+ if (!isHexString(message)) {
418
+ formattedMessage = Buffer.from(message).toString('hex');
419
+ } else {
420
+ formattedMessage = Buffer.from(message, 'hex');
421
+ }
422
+ } else {
423
+ formattedMessage = message;
424
+ }
425
+ } else if (mpcSigner instanceof node.BIP340 && typeof message === 'string') {
426
+ formattedMessage = new TextEncoder().encode(message);
427
+ } else {
428
+ throw new Error('Unsupported signer type');
429
+ }
430
+ const signature = await mpcSigner.sign(roomId, keyShare, formattedMessage, derivationPath);
431
+ return signature;
432
+ } catch (error) {
433
+ this.logger.error('Error in externalServerSign', error);
434
+ throw error;
435
+ }
436
+ }
437
+ //todo: need to modify with imported flag
438
+ async sign({ accountAddress, message, chainName, password = undefined, signedSessionId }) {
439
+ await this.verifyPassword({
440
+ accountAddress,
441
+ password,
442
+ walletOperation: core.WalletOperation.SIGN_MESSAGE,
443
+ signedSessionId
444
+ });
445
+ const wallet = await this.getWallet({
446
+ accountAddress,
447
+ walletOperation: core.WalletOperation.SIGN_MESSAGE,
448
+ password,
449
+ signedSessionId
450
+ });
451
+ // Perform the dynamic server sign
452
+ const data = await this.dynamicServerSign({
453
+ walletId: wallet.walletId,
454
+ message
455
+ });
456
+ const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
457
+ // Perform the external server sign and return the signature
458
+ const signature = await this.externalServerSign({
459
+ chainName,
460
+ message,
461
+ roomId: data.roomId,
462
+ keyShare: wallet.externalServerKeyShares[0],
463
+ derivationPath
464
+ });
465
+ return signature;
466
+ }
467
+ async refreshWalletAccountShares({ accountAddress, chainName, password = undefined, signedSessionId }) {
468
+ this.ensureApiClientAuthenticated();
469
+ await this.verifyPassword({
470
+ accountAddress,
471
+ password,
472
+ walletOperation: core.WalletOperation.REFRESH,
473
+ signedSessionId
474
+ });
475
+ const wallet = await this.getWallet({
476
+ accountAddress,
477
+ walletOperation: core.WalletOperation.REFRESH,
478
+ password,
479
+ signedSessionId
480
+ });
481
+ const mpcSigner = getMPCSigner({
482
+ chainName,
483
+ baseRelayUrl: this.baseMPCRelayApiUrl
484
+ });
485
+ // Create the room and refresh the shares
486
+ const data = await this.apiClient.refreshWalletAccountShares({
487
+ walletId: wallet.walletId
488
+ });
489
+ const roomId = data.roomId;
490
+ const refreshResults = await Promise.all(wallet.externalServerKeyShares.map((serverKeyShare)=>mpcSigner.refresh(roomId, serverKeyShare)));
491
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
492
+ externalServerKeyShares: refreshResults,
493
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
494
+ });
495
+ await this.storeEncryptedBackupByWallet({
496
+ accountAddress,
497
+ password: password != null ? password : this.environmentId,
498
+ signedSessionId
499
+ });
500
+ return refreshResults;
501
+ }
502
+ async getExportId({ chainName, serverKeyShare }) {
503
+ const mpcSigner = getMPCSigner({
504
+ chainName,
505
+ baseRelayUrl: this.baseMPCRelayApiUrl
506
+ });
507
+ const exportId = await mpcSigner.exportID(serverKeyShare);
508
+ return exportId;
509
+ }
510
+ /**
511
+ * Helper function to create client shares required to complete a reshare ceremony.
512
+ * @param {string} chainName - The chain to create shares for
513
+ * @param {WalletProperties} wallet - The wallet to reshare
514
+ * @param {ThresholdSignatureScheme} oldThresholdSignatureScheme - The current threshold signature scheme
515
+ * @param {ThresholdSignatureScheme} newThresholdSignatureScheme - The target threshold signature scheme
516
+ * @returns {Promise<{
517
+ * newClientInitKeygenResults: ClientInitKeygenResult[],
518
+ * newClientKeygenIds: string[],
519
+ * existingClientKeygenIds: string[],
520
+ * existingClientKeyShares: ClientKeyShare[]
521
+ * }>} Object containing new and existing client keygen results, IDs and shares
522
+ * @todo Support higher to lower reshare strategies
523
+ */ async reshareStrategy({ chainName, wallet, oldThresholdSignatureScheme, newThresholdSignatureScheme }) {
524
+ const mpcSigner = getMPCSigner({
525
+ chainName,
526
+ baseRelayUrl: this.baseMPCRelayApiUrl
527
+ });
528
+ // Determine share counts based on threshold signature schemes
529
+ const { newExternalServerShareCount, existingExternalServerShareCount } = core.getServerWalletReshareConfig({
530
+ oldThresholdSignatureScheme,
531
+ newThresholdSignatureScheme
532
+ });
533
+ // Create new client shares
534
+ const newExternalServerInitKeygenResults = await Promise.all(Array.from({
535
+ length: newExternalServerShareCount
536
+ }, ()=>mpcSigner.initKeygen()));
537
+ const newExternalServerKeygenIds = newExternalServerInitKeygenResults.map((result)=>result.keygenId);
538
+ // Get existing client shares
539
+ const existingExternalServerKeyShares = wallet.externalServerKeyShares.slice(0, existingExternalServerShareCount);
540
+ const existingExternalServerKeygenIds = await Promise.all(existingExternalServerKeyShares.map(async (keyShare)=>await this.getExportId({
541
+ chainName,
542
+ serverKeyShare: keyShare
543
+ })));
544
+ return {
545
+ newExternalServerInitKeygenResults,
546
+ newExternalServerKeygenIds,
547
+ existingExternalServerKeygenIds,
548
+ existingExternalServerKeyShares
549
+ };
550
+ }
551
+ async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId }) {
552
+ this.ensureApiClientAuthenticated();
553
+ await this.verifyPassword({
554
+ accountAddress,
555
+ password,
556
+ walletOperation: core.WalletOperation.RESHARE,
557
+ signedSessionId
558
+ });
559
+ const { existingExternalServerShareCount } = core.getServerWalletReshareConfig({
560
+ oldThresholdSignatureScheme,
561
+ newThresholdSignatureScheme
562
+ });
563
+ const wallet = await this.getWallet({
564
+ accountAddress,
565
+ walletOperation: core.WalletOperation.RESHARE,
566
+ shareCount: existingExternalServerShareCount,
567
+ password,
568
+ signedSessionId
569
+ });
570
+ const { newExternalServerInitKeygenResults, newExternalServerKeygenIds, existingExternalServerKeygenIds, existingExternalServerKeyShares } = await this.reshareStrategy({
571
+ chainName,
572
+ wallet,
573
+ oldThresholdSignatureScheme,
574
+ newThresholdSignatureScheme
575
+ });
576
+ const externalServerKeygenIds = [
577
+ ...newExternalServerKeygenIds,
578
+ ...existingExternalServerKeygenIds
579
+ ];
580
+ // Server to create the room and complete the server reshare logics
581
+ const data = await this.apiClient.reshare({
582
+ walletId: wallet.walletId,
583
+ clientKeygenIds: externalServerKeygenIds,
584
+ oldThresholdSignatureScheme,
585
+ newThresholdSignatureScheme
586
+ });
587
+ const { roomId, serverKeygenIds: dynamicServerKeygenIds, newServerKeygenIds: newDynamicServerKeygenIds = [] } = data;
588
+ // Get the MPC config for the threshold signature scheme
589
+ const oldMpcConfig = core.MPC_CONFIG[oldThresholdSignatureScheme];
590
+ const newMpcConfig = core.MPC_CONFIG[newThresholdSignatureScheme];
591
+ const allPartyKeygenIds = [
592
+ ...externalServerKeygenIds,
593
+ ...dynamicServerKeygenIds,
594
+ ...newDynamicServerKeygenIds
595
+ ];
596
+ const mpcSigner = getMPCSigner({
597
+ chainName,
598
+ baseRelayUrl: this.baseMPCRelayApiUrl
599
+ });
600
+ const reshareResults = await Promise.all([
601
+ ...newExternalServerInitKeygenResults.map((keygenResult)=>mpcSigner.reshareNewParty(roomId, oldMpcConfig.threshold, newMpcConfig.threshold, keygenResult, allPartyKeygenIds)),
602
+ ...existingExternalServerKeyShares.map((keyShare)=>mpcSigner.reshareRemainingParty(roomId, newMpcConfig.threshold, keyShare, allPartyKeygenIds))
603
+ ]);
604
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
605
+ externalServerKeyShares: reshareResults,
606
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
607
+ });
608
+ await this.storeEncryptedBackupByWallet({
609
+ accountAddress,
610
+ password,
611
+ signedSessionId
612
+ });
613
+ return reshareResults;
614
+ }
615
+ async exportKey({ accountAddress, chainName, password = undefined, signedSessionId }) {
616
+ this.ensureApiClientAuthenticated();
617
+ await this.verifyPassword({
618
+ accountAddress,
619
+ password,
620
+ walletOperation: core.WalletOperation.EXPORT_PRIVATE_KEY,
621
+ signedSessionId
622
+ });
623
+ const wallet = await this.getWallet({
624
+ accountAddress,
625
+ password,
626
+ walletOperation: core.WalletOperation.EXPORT_PRIVATE_KEY,
627
+ signedSessionId
628
+ });
629
+ const mpcSigner = getMPCSigner({
630
+ chainName,
631
+ baseRelayUrl: this.baseMPCRelayApiUrl
632
+ });
633
+ const exportId = await this.getExportId({
634
+ chainName,
635
+ serverKeyShare: wallet.externalServerKeyShares[0]
636
+ });
637
+ const data = await this.apiClient.exportKey({
638
+ walletId: wallet.walletId,
639
+ exportId
640
+ });
641
+ const keyExportRaw = await mpcSigner.exportFullPrivateKey(data.roomId, wallet.externalServerKeyShares[0], exportId);
642
+ if (!keyExportRaw) {
643
+ throw new Error('Error exporting private key');
644
+ }
645
+ const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
646
+ let derivedPrivateKey;
647
+ if (mpcSigner instanceof node.Ecdsa) {
648
+ derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, derivationPath);
649
+ } else if (mpcSigner instanceof node.Ed25519) {
650
+ derivedPrivateKey = keyExportRaw;
651
+ } else if (mpcSigner instanceof node.BIP340) {
652
+ derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, derivationPath);
653
+ }
654
+ return {
655
+ derivedPrivateKey
656
+ };
657
+ }
658
+ async offlineExportKey({ chainName, keyShares, derivationPath }) {
659
+ try {
660
+ if (!keyShares || keyShares.length < 2) {
661
+ throw new Error(`Must provide at least min threshold of key shares`);
662
+ }
663
+ const mpcSigner = getMPCSigner({
664
+ chainName,
665
+ baseRelayUrl: this.baseMPCRelayApiUrl
666
+ });
667
+ const walletKeyShares = keyShares.map((keyShare)=>{
668
+ return mpcSigner instanceof node.Ecdsa ? new node.EcdsaKeygenResult(keyShare.pubkey, keyShare.secretShare) : mpcSigner instanceof node.Ed25519 ? new node.Ed25519KeygenResult(keyShare.pubkey, keyShare.secretShare) : new node.BIP340KeygenResult(keyShare.pubkey, keyShare.secretShare);
669
+ });
670
+ const keyExportRaw = await mpcSigner.offlineExportFullPrivateKey(walletKeyShares);
671
+ if (!keyExportRaw) {
672
+ throw new Error('Error exporting private key: Export returned null');
673
+ }
674
+ const chainConfig = core.getMPCChainConfig(chainName);
675
+ const walletDerivationPath = !derivationPath ? undefined : new Uint32Array(chainConfig.derivationPath);
676
+ let derivedPrivateKey;
677
+ if (mpcSigner instanceof node.Ecdsa) {
678
+ derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
679
+ } else if (mpcSigner instanceof node.Ed25519) {
680
+ derivedPrivateKey = keyExportRaw;
681
+ } else if (mpcSigner instanceof node.BIP340) {
682
+ derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
683
+ }
684
+ return {
685
+ derivedPrivateKey
686
+ };
687
+ } catch (error) {
688
+ this.logger.error('Error in offlineExportKey:', error);
689
+ throw error;
690
+ }
691
+ }
692
+ async encryptKeyShare({ keyShare, password }) {
693
+ const serializedKeyShare = JSON.stringify(keyShare);
694
+ const encryptedKeyShare = await encryptData({
695
+ data: serializedKeyShare,
696
+ password: password != null ? password : this.environmentId
697
+ });
698
+ // stringify the encrypted key share, convert to base64, and store it
699
+ const serializedEncryptedKeyShare = Buffer.from(JSON.stringify(encryptedKeyShare)).toString('base64');
700
+ return serializedEncryptedKeyShare;
701
+ }
702
+ async ensureCeremonyCompletionBeforeBackup({ accountAddress }) {
703
+ let retries = 0;
704
+ const maxRetries = 3;
705
+ while((!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) && retries < maxRetries){
706
+ await new Promise((resolve)=>setTimeout(resolve, 1000)); // Wait 1 second
707
+ retries++;
708
+ }
709
+ if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
710
+ throw new Error('Ceremony completion timeout');
711
+ }
712
+ }
713
+ async storeEncryptedBackupByWallet({ accountAddress, externalServerKeyShares = undefined, password = undefined, signedSessionId }) {
714
+ this.ensureApiClientAuthenticated();
715
+ //add retry logic for ceremony completion to prevent race condition
716
+ await this.ensureCeremonyCompletionBeforeBackup({
717
+ accountAddress
718
+ });
719
+ try {
720
+ const keySharesToBackup = externalServerKeyShares != null ? externalServerKeyShares : await this.getExternalServerKeyShares({
721
+ accountAddress,
722
+ signedSessionId
723
+ });
724
+ if (!keySharesToBackup || keySharesToBackup.length === 0) {
725
+ throw new Error(`Key shares not found for accountAddress: ${accountAddress}`);
726
+ }
727
+ const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
728
+ keyShare,
729
+ password
730
+ })));
731
+ if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
732
+ throw new Error(`WalletId not found for accountAddress: ${accountAddress}`);
733
+ }
734
+ // TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
735
+ const data = await this.apiClient.storeEncryptedBackupByWallet({
736
+ walletId: this.walletMap[accountAddress].walletId,
737
+ encryptedKeyShares,
738
+ passwordEncrypted: Boolean(password) && password !== this.environmentId,
739
+ signedSessionId
740
+ });
741
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
742
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
743
+ walletProperties: {
744
+ derivationPath: this.walletMap[accountAddress].derivationPath,
745
+ keyShares: data.keyShares,
746
+ thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme
747
+ }
748
+ })
749
+ });
750
+ return data;
751
+ } catch (error) {
752
+ this.logger.error('Error in storeEncryptedBackupByWallet:', error);
753
+ throw error;
754
+ }
755
+ }
756
+ async storeEncryptedBackupByWalletWithRetry({ accountAddress, externalServerKeyShares, password, signedSessionId }) {
757
+ await retryPromise(()=>this.storeEncryptedBackupByWallet({
758
+ accountAddress,
759
+ externalServerKeyShares,
760
+ password,
761
+ signedSessionId
762
+ }), {
763
+ operationName: 'store encrypted backup',
764
+ logContext: {
765
+ walletAddress: accountAddress,
766
+ keyShares: externalServerKeyShares == null ? void 0 : externalServerKeyShares.map((keyShare)=>this.encryptKeyShare({
767
+ keyShare,
768
+ password
769
+ }))
770
+ }
771
+ });
772
+ }
773
+ async getExternalServerKeyShares({ accountAddress, password, signedSessionId }) {
774
+ const wallet = await this.getWallet({
775
+ accountAddress,
776
+ password,
777
+ walletOperation: core.WalletOperation.REACH_THRESHOLD,
778
+ signedSessionId
779
+ });
780
+ return wallet.externalServerKeyShares;
781
+ }
782
+ async updatePassword({ accountAddress, existingPassword, newPassword, signedSessionId }) {
783
+ await this.getWallet({
784
+ accountAddress,
785
+ password: existingPassword,
786
+ walletOperation: core.WalletOperation.REACH_ALL_PARTIES,
787
+ signedSessionId
788
+ });
789
+ await this.storeEncryptedBackupByWallet({
790
+ accountAddress,
791
+ password: newPassword,
792
+ signedSessionId
793
+ });
794
+ }
795
+ async decryptKeyShare({ keyShare, password }) {
796
+ const decodedKeyShare = JSON.parse(Buffer.from(keyShare, 'base64').toString());
797
+ const decryptedKeyShare = await decryptData({
798
+ data: decodedKeyShare,
799
+ password: password != null ? password : this.environmentId
800
+ });
801
+ const deserializedKeyShare = JSON.parse(decryptedKeyShare);
802
+ return deserializedKeyShare;
803
+ }
804
+ /**
805
+ * Helper function to determine keyshare recovery strategy for dynamic shares.
806
+ * For REFRESH operations, retrieves enough shares to meet the client threshold.
807
+ * For all other operations, retrieves just 1 share.
808
+ *
809
+ * @param clientKeyShareBackupInfo - Information about backed up key shares
810
+ * @param thresholdSignatureScheme - The signature scheme being used (2-of-2, 2-of-3, etc)
811
+ * @param walletOperation - The operation being performed (REFRESH, SIGN_MESSAGE, etc)
812
+ * @param shareCount - The number of shares to recover if specified for reshare operations
813
+ * @returns @shares: Object mapping backup locations to arrays of share IDs to recover
814
+ * @returns @requiredShareCount: The number of shares required to recover
815
+ */ recoverStrategy({ externalServerKeySharesBackupInfo, thresholdSignatureScheme, walletOperation, shareCount = undefined }) {
816
+ const { backups } = externalServerKeySharesBackupInfo;
817
+ const { clientThreshold } = core.MPC_CONFIG[thresholdSignatureScheme];
818
+ let requiredShareCount = walletOperation === core.WalletOperation.REFRESH || walletOperation === core.WalletOperation.REACH_ALL_PARTIES || walletOperation === core.WalletOperation.RESHARE ? clientThreshold : 1;
819
+ // Override requiredShareCount if shareCount is provided
820
+ if (shareCount !== undefined) {
821
+ requiredShareCount = shareCount;
822
+ }
823
+ const dynamicShares = backups[core.BackupLocation.DYNAMIC].slice(0, requiredShareCount);
824
+ return {
825
+ shares: {
826
+ [core.BackupLocation.DYNAMIC]: dynamicShares
827
+ },
828
+ requiredShareCount
829
+ };
830
+ }
831
+ async recoverEncryptedBackupByWallet({ accountAddress, password, walletOperation, signedSessionId, shareCount = undefined, storeRecoveredShares = true }) {
832
+ this.ensureApiClientAuthenticated();
833
+ const wallet = this.walletMap[accountAddress];
834
+ this.logger.debug(`recoverEncryptedBackupByWallet wallet: ${walletOperation}`, wallet);
835
+ const { shares } = this.recoverStrategy({
836
+ externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
837
+ thresholdSignatureScheme: wallet.thresholdSignatureScheme,
838
+ walletOperation,
839
+ shareCount
840
+ });
841
+ const { dynamic: dynamicKeyShareIds } = shares;
842
+ const data = await this.apiClient.recoverEncryptedBackupByWallet({
843
+ walletId: wallet.walletId,
844
+ keyShareIds: dynamicKeyShareIds,
845
+ signedSessionId
846
+ });
847
+ const dynamicKeyShares = data.keyShares.filter((keyShare)=>keyShare.encryptedAccountCredential !== null && keyShare.backupLocation === core.BackupLocation.DYNAMIC);
848
+ const decryptedKeyShares = await Promise.all(dynamicKeyShares.map((keyShare)=>this.decryptKeyShare({
849
+ keyShare: keyShare.encryptedAccountCredential,
850
+ password: password != null ? password : this.environmentId
851
+ })));
852
+ if (storeRecoveredShares) {
853
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
854
+ externalServerKeyShares: mergeUniqueKeyShares(this.walletMap[accountAddress].externalServerKeyShares || [], decryptedKeyShares)
855
+ });
856
+ }
857
+ return decryptedKeyShares;
858
+ }
859
+ async exportExternalServerKeyShares({ accountAddress, password, signedSessionId }) {
860
+ await this.verifyPassword({
861
+ accountAddress,
862
+ password,
863
+ walletOperation: core.WalletOperation.REACH_ALL_PARTIES,
864
+ signedSessionId
865
+ });
866
+ const externalServerKeyShares = await this.getExternalServerKeyShares({
867
+ accountAddress,
868
+ password,
869
+ signedSessionId
870
+ });
871
+ return externalServerKeyShares;
872
+ }
873
+ /**
874
+ * Helper function to check if the required wallet fields are present and valid
875
+ * @param accountAddress - The account address of the wallet to check
876
+ * @param walletOperation - The wallet operation that determines required fields
877
+ * @returns boolean indicating if wallet needs to be re-fetched and restored from server
878
+ */ async checkWalletFields({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD, shareCount }) {
879
+ let keyshareCheck = false;
880
+ let walletCheck = false;
881
+ let thresholdSignatureSchemeCheck = false;
882
+ let derivationPathCheck = false;
883
+ // check if wallet exists
884
+ const existingWallet = this.walletMap[accountAddress];
885
+ if (existingWallet) {
886
+ walletCheck = true;
887
+ }
888
+ // check if threshold signature scheme exists
889
+ if (existingWallet == null ? void 0 : existingWallet.thresholdSignatureScheme) {
890
+ thresholdSignatureSchemeCheck = true;
891
+ }
892
+ // check if derivation path exists
893
+ if ((existingWallet == null ? void 0 : existingWallet.derivationPath) || (existingWallet == null ? void 0 : existingWallet.derivationPath) === '') {
894
+ derivationPathCheck = true;
895
+ }
896
+ // check if wallet already exists with sufficient keyshares
897
+ if (existingWallet) {
898
+ var _existingWallet_externalServerKeyShares;
899
+ const { shares } = this.recoverStrategy({
900
+ externalServerKeySharesBackupInfo: existingWallet.externalServerKeySharesBackupInfo || {
901
+ backups: getExternalServerKeyShareBackupInfo()
902
+ },
903
+ thresholdSignatureScheme: existingWallet.thresholdSignatureScheme,
904
+ walletOperation,
905
+ shareCount
906
+ });
907
+ const { dynamic: requiredDynamicKeyShareIds = [] } = shares;
908
+ if (requiredDynamicKeyShareIds.length <= (((_existingWallet_externalServerKeyShares = existingWallet.externalServerKeyShares) == null ? void 0 : _existingWallet_externalServerKeyShares.length) || 0)) {
909
+ keyshareCheck = true;
910
+ }
911
+ }
912
+ return walletCheck && thresholdSignatureSchemeCheck && keyshareCheck && derivationPathCheck;
913
+ }
914
+ /**
915
+ * verifyPassword attempts to recover and decrypt a single client key share using the provided password.
916
+ * If successful, the key share is encrypted with the new password. This method solely performs the recovery
917
+ * and decryption without storing the restored key shares. If unsuccessful, it throws an error.
918
+ */ async verifyPassword({ accountAddress, password = undefined, walletOperation = core.WalletOperation.NO_OPERATION, signedSessionId }) {
919
+ await this.getWallet({
920
+ accountAddress,
921
+ password,
922
+ walletOperation,
923
+ signedSessionId
924
+ });
925
+ if (await this.requiresPasswordForOperation({
926
+ accountAddress,
927
+ walletOperation
928
+ }) && !password) {
929
+ throw new Error('Password is required for operation but not provided');
930
+ }
931
+ // silent return if no password is provided and operation does not require a password
932
+ if (!password) {
933
+ return;
934
+ }
935
+ const { backups } = await this.getWalletExternalServerKeyShareBackupInfo({
936
+ accountAddress
937
+ });
938
+ const { dynamic: dynamicKeyShareIds = [] } = backups;
939
+ if (!dynamicKeyShareIds || dynamicKeyShareIds.length === 0) {
940
+ throw new Error('No dynamic key shares found');
941
+ }
942
+ try {
943
+ // TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
944
+ await this.recoverEncryptedBackupByWallet({
945
+ accountAddress,
946
+ password,
947
+ walletOperation,
948
+ signedSessionId,
949
+ shareCount: 1,
950
+ storeRecoveredShares: false
951
+ });
952
+ } catch (error) {
953
+ this.logger.error('Error in verifying password', error);
954
+ throw new Error('Incorrect password');
955
+ }
956
+ }
957
+ async isPasswordEncrypted({ accountAddress }) {
958
+ const externalServerKeySharesBackupInfo = await this.getWalletExternalServerKeyShareBackupInfo({
959
+ accountAddress
960
+ });
961
+ return externalServerKeySharesBackupInfo == null ? void 0 : externalServerKeySharesBackupInfo.passwordEncrypted;
962
+ }
963
+ /**
964
+ * check if the operation requires a password
965
+ */ async requiresPasswordForOperation({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD }) {
966
+ const isEncrypted = await this.isPasswordEncrypted({
967
+ accountAddress
968
+ });
969
+ if (!isEncrypted) {
970
+ return false;
971
+ }
972
+ return this.requiresRestoreBackupSharesForOperation({
973
+ accountAddress,
974
+ walletOperation
975
+ });
976
+ }
977
+ /**
978
+ * check if the operation requires restoring backup shares
979
+ */ async requiresRestoreBackupSharesForOperation({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD }) {
980
+ const externalServerKeySharesBackupInfo = await this.getWalletExternalServerKeyShareBackupInfo({
981
+ accountAddress
982
+ });
983
+ const externalServerKeyShares = this.walletMap[accountAddress].externalServerKeyShares || [];
984
+ if (walletOperation === core.WalletOperation.REACH_ALL_PARTIES || walletOperation === core.WalletOperation.REFRESH || walletOperation === core.WalletOperation.RESHARE) {
985
+ return true;
986
+ }
987
+ const { requiredShareCount } = this.recoverStrategy({
988
+ externalServerKeySharesBackupInfo,
989
+ thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme,
990
+ walletOperation
991
+ });
992
+ if (externalServerKeyShares.length >= requiredShareCount) {
993
+ return false;
994
+ }
995
+ return true;
996
+ }
997
+ async getWalletExternalServerKeyShareBackupInfo({ accountAddress }) {
998
+ var _this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC, _this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups, _this_walletMap_accountAddress_externalServerKeySharesBackupInfo, _this_walletMap_accountAddress, _user_verifiedCredentials;
999
+ this.ensureApiClientAuthenticated();
1000
+ // Return existing backup info if it exists
1001
+ if (((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : (_this_walletMap_accountAddress_externalServerKeySharesBackupInfo = _this_walletMap_accountAddress.externalServerKeySharesBackupInfo) == null ? void 0 : (_this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups = _this_walletMap_accountAddress_externalServerKeySharesBackupInfo.backups) == null ? void 0 : (_this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC = _this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups[core.BackupLocation.DYNAMIC]) == null ? void 0 : _this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC.length) > 0) {
1002
+ return this.walletMap[accountAddress].externalServerKeySharesBackupInfo;
1003
+ }
1004
+ // Get backup info from server
1005
+ const user = await this.apiClient.getUser();
1006
+ const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
1007
+ return getExternalServerKeyShareBackupInfo({
1008
+ walletProperties: wallet == null ? void 0 : wallet.walletProperties
1009
+ });
1010
+ }
1011
+ async getWallet({ accountAddress, walletOperation = core.WalletOperation.NO_OPERATION, signedSessionId, shareCount = undefined, password = undefined }) {
1012
+ var _user_verifiedCredentials;
1013
+ this.ensureApiClientAuthenticated();
1014
+ const existingWalletCheck = await this.checkWalletFields({
1015
+ accountAddress,
1016
+ walletOperation,
1017
+ shareCount
1018
+ });
1019
+ if (existingWalletCheck) {
1020
+ this.logger.debug(`Wallet ${accountAddress} already exists`);
1021
+ return this.walletMap[accountAddress];
1022
+ }
1023
+ //todo: Question - why don't we just call getWallets here? so then all are preloaded
1024
+ // Fetch and restore wallet from server
1025
+ const user = await this.apiClient.getUser();
1026
+ const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
1027
+ this.logger.debug('Restoring wallet', wallet);
1028
+ const walletProperties = wallet.walletProperties;
1029
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
1030
+ walletId: wallet.id,
1031
+ chainName: wallet.chainName,
1032
+ accountAddress,
1033
+ thresholdSignatureScheme: walletProperties.thresholdSignatureScheme,
1034
+ derivationPath: walletProperties.derivationPath,
1035
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
1036
+ walletProperties
1037
+ })
1038
+ });
1039
+ if (walletOperation !== core.WalletOperation.NO_OPERATION && await this.requiresRestoreBackupSharesForOperation({
1040
+ accountAddress,
1041
+ walletOperation
1042
+ })) {
1043
+ // TODO(zfaizal2): throw error if signedSessionId is not provided after service deploy
1044
+ const decryptedKeyShares = await this.recoverEncryptedBackupByWallet({
1045
+ accountAddress,
1046
+ password: password != null ? password : this.environmentId,
1047
+ walletOperation: walletOperation,
1048
+ signedSessionId,
1049
+ shareCount
1050
+ });
1051
+ this.logger.debug('Recovered backup', decryptedKeyShares);
1052
+ }
1053
+ const walletCount = Object.keys(this.walletMap).length;
1054
+ if (walletCount === 0) {
1055
+ throw new Error('No wallets found');
1056
+ }
1057
+ // Return the only wallet if there's just one
1058
+ if (walletCount === 1) {
1059
+ return Object.values(this.walletMap)[0];
1060
+ }
1061
+ return this.walletMap[accountAddress];
1062
+ }
1063
+ async getWallets() {
1064
+ var _user_verifiedCredentials;
1065
+ this.ensureApiClientAuthenticated();
1066
+ const user = await this.apiClient.getUser();
1067
+ const waasWallets = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.filter((vc)=>vc.walletName === 'dynamicwaas');
1068
+ const wallets = waasWallets.map((vc)=>{
1069
+ var _this_walletMap_vc_address, _this_walletMap_vc_address1, _vc_walletProperties;
1070
+ var _this_walletMap_vc_address_derivationPath;
1071
+ return {
1072
+ walletId: vc.id,
1073
+ chainName: vc.chain,
1074
+ accountAddress: vc.address,
1075
+ serverKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
1076
+ walletProperties: vc.walletProperties || {}
1077
+ }),
1078
+ externalServerKeyShares: ((_this_walletMap_vc_address = this.walletMap[vc.address]) == null ? void 0 : _this_walletMap_vc_address.externalServerKeyShares) || [],
1079
+ derivationPath: (_this_walletMap_vc_address_derivationPath = (_this_walletMap_vc_address1 = this.walletMap[vc.address]) == null ? void 0 : _this_walletMap_vc_address1.derivationPath) != null ? _this_walletMap_vc_address_derivationPath : undefined,
1080
+ thresholdSignatureScheme: (_vc_walletProperties = vc.walletProperties) == null ? void 0 : _vc_walletProperties.thresholdSignatureScheme
1081
+ };
1082
+ });
1083
+ this.walletMap = wallets.reduce((acc, wallet)=>{
1084
+ var _acc_accountAddress;
1085
+ const accountAddress = wallet.accountAddress;
1086
+ acc[wallet.accountAddress] = {
1087
+ walletId: wallet.walletId,
1088
+ chainName: wallet.chainName,
1089
+ accountAddress: wallet.accountAddress,
1090
+ externalServerKeyShares: wallet.externalServerKeyShares || [],
1091
+ externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
1092
+ derivationPath: ((_acc_accountAddress = acc[accountAddress]) == null ? void 0 : _acc_accountAddress.derivationPath) || undefined,
1093
+ thresholdSignatureScheme: wallet.thresholdSignatureScheme
1094
+ };
1095
+ return acc;
1096
+ }, {});
1097
+ return wallets;
1098
+ }
1099
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug }){
1100
+ this.logger = logger;
1101
+ this.walletMap = {} // todo: store in session storage
1102
+ ;
1103
+ this.isApiClientAuthenticated = false;
1104
+ this.environmentId = environmentId;
1105
+ this.baseMPCRelayApiUrl = baseMPCRelayApiUrl;
1106
+ this.baseApiUrl = baseApiUrl;
1107
+ this.debug = Boolean(debug);
1108
+ this.logger.setLogLevel(this.debug ? 'DEBUG' : DEFAULT_LOG_LEVEL);
1109
+ }
1110
+ }
1111
+
1112
+ Object.defineProperty(exports, "BIP340", {
1113
+ enumerable: true,
1114
+ get: function () { return node.BIP340; }
1115
+ });
1116
+ Object.defineProperty(exports, "BIP340InitKeygenResult", {
1117
+ enumerable: true,
1118
+ get: function () { return node.BIP340InitKeygenResult; }
1119
+ });
1120
+ Object.defineProperty(exports, "BIP340KeygenResult", {
1121
+ enumerable: true,
1122
+ get: function () { return node.BIP340KeygenResult; }
1123
+ });
1124
+ Object.defineProperty(exports, "Ecdsa", {
1125
+ enumerable: true,
1126
+ get: function () { return node.Ecdsa; }
1127
+ });
1128
+ Object.defineProperty(exports, "EcdsaInitKeygenResult", {
1129
+ enumerable: true,
1130
+ get: function () { return node.EcdsaInitKeygenResult; }
1131
+ });
1132
+ Object.defineProperty(exports, "EcdsaKeygenResult", {
1133
+ enumerable: true,
1134
+ get: function () { return node.EcdsaKeygenResult; }
1135
+ });
1136
+ Object.defineProperty(exports, "EcdsaPublicKey", {
1137
+ enumerable: true,
1138
+ get: function () { return node.EcdsaPublicKey; }
1139
+ });
1140
+ Object.defineProperty(exports, "EcdsaSignature", {
1141
+ enumerable: true,
1142
+ get: function () { return node.EcdsaSignature; }
1143
+ });
1144
+ Object.defineProperty(exports, "Ed25519", {
1145
+ enumerable: true,
1146
+ get: function () { return node.Ed25519; }
1147
+ });
1148
+ Object.defineProperty(exports, "Ed25519InitKeygenResult", {
1149
+ enumerable: true,
1150
+ get: function () { return node.Ed25519InitKeygenResult; }
1151
+ });
1152
+ Object.defineProperty(exports, "Ed25519KeygenResult", {
1153
+ enumerable: true,
1154
+ get: function () { return node.Ed25519KeygenResult; }
1155
+ });
1156
+ Object.defineProperty(exports, "MessageHash", {
1157
+ enumerable: true,
1158
+ get: function () { return node.MessageHash; }
1159
+ });
1160
+ exports.DynamicWalletClient = DynamicWalletClient;
1161
+ exports.base64ToBytes = base64ToBytes;
1162
+ exports.bytesToBase64 = bytesToBase64;
1163
+ exports.ensureBase64Padding = ensureBase64Padding;
1164
+ exports.getExternalServerKeyShareBackupInfo = getExternalServerKeyShareBackupInfo;
1165
+ exports.getMPCSignatureScheme = getMPCSignatureScheme;
1166
+ exports.getMPCSigner = getMPCSigner;
1167
+ exports.isHexString = isHexString;
1168
+ exports.mergeUniqueKeyShares = mergeUniqueKeyShares;
1169
+ exports.retryPromise = retryPromise;
1170
+ exports.stringToBytes = stringToBytes;
1171
+ Object.keys(core).forEach(function (k) {
1172
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1173
+ enumerable: true,
1174
+ get: function () { return core[k]; }
1175
+ });
1176
+ });