@dynamic-labs-wallet/node 0.0.0-beta.146.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 (47) hide show
  1. package/index.cjs.d.ts +1 -0
  2. package/index.cjs.js +1151 -0
  3. package/index.esm.d.ts +1 -0
  4. package/index.esm.js +1087 -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/index.d.ts +6 -0
  14. package/internal/core/index.js +1 -0
  15. package/internal/core/native.d.ts +103 -0
  16. package/internal/core/native.js +1 -0
  17. package/internal/core/types.d.ts +58 -0
  18. package/internal/core/types.js +1 -0
  19. package/internal/node/index.d.ts +11 -0
  20. package/internal/node/index.js +1 -0
  21. package/internal/node/native/libmpc_executor_linux_arm64_nodejs.node +0 -0
  22. package/internal/node/native/libmpc_executor_linux_x86_64_nodejs.node +0 -0
  23. package/internal/node/native/libmpc_executor_macos_arm64_nodejs.node +0 -0
  24. package/internal/node/native/libmpc_executor_macos_x86_64_nodejs.node +0 -0
  25. package/internal/node/native.d.ts +2 -0
  26. package/internal/node/native.js +1 -0
  27. package/package.json +34 -0
  28. package/src/backup/encryption.d.ts +22 -0
  29. package/src/backup/encryption.d.ts.map +1 -0
  30. package/src/client.d.ts +249 -0
  31. package/src/client.d.ts.map +1 -0
  32. package/src/constants.d.ts +2 -0
  33. package/src/constants.d.ts.map +1 -0
  34. package/src/index.d.ts +6 -0
  35. package/src/index.d.ts.map +1 -0
  36. package/src/mpc/index.d.ts +3 -0
  37. package/src/mpc/index.d.ts.map +1 -0
  38. package/src/mpc/mpc.d.ts +12 -0
  39. package/src/mpc/mpc.d.ts.map +1 -0
  40. package/src/mpc/types.d.ts +6 -0
  41. package/src/mpc/types.d.ts.map +1 -0
  42. package/src/services/logger.d.ts +3 -0
  43. package/src/services/logger.d.ts.map +1 -0
  44. package/src/types.d.ts +12 -0
  45. package/src/types.d.ts.map +1 -0
  46. package/src/utils.d.ts +34 -0
  47. package/src/utils.d.ts.map +1 -0
package/index.cjs.js ADDED
@@ -0,0 +1,1151 @@
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 }) {
439
+ await this.verifyPassword({
440
+ accountAddress,
441
+ password,
442
+ walletOperation: core.WalletOperation.SIGN_MESSAGE
443
+ });
444
+ const wallet = await this.getWallet({
445
+ accountAddress,
446
+ walletOperation: core.WalletOperation.SIGN_MESSAGE,
447
+ password
448
+ });
449
+ // Perform the dynamic server sign
450
+ const data = await this.dynamicServerSign({
451
+ walletId: wallet.walletId,
452
+ message
453
+ });
454
+ const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
455
+ // Perform the external server sign and return the signature
456
+ const signature = await this.externalServerSign({
457
+ chainName,
458
+ message,
459
+ roomId: data.roomId,
460
+ keyShare: wallet.externalServerKeyShares[0],
461
+ derivationPath
462
+ });
463
+ return signature;
464
+ }
465
+ async refreshWalletAccountShares({ accountAddress, chainName, password = undefined }) {
466
+ this.ensureApiClientAuthenticated();
467
+ await this.verifyPassword({
468
+ accountAddress,
469
+ password,
470
+ walletOperation: core.WalletOperation.REFRESH
471
+ });
472
+ const wallet = await this.getWallet({
473
+ accountAddress,
474
+ walletOperation: core.WalletOperation.REFRESH,
475
+ password
476
+ });
477
+ const mpcSigner = getMPCSigner({
478
+ chainName,
479
+ baseRelayUrl: this.baseMPCRelayApiUrl
480
+ });
481
+ // Create the room and refresh the shares
482
+ const data = await this.apiClient.refreshWalletAccountShares({
483
+ walletId: wallet.walletId
484
+ });
485
+ const roomId = data.roomId;
486
+ const refreshResults = await Promise.all(wallet.externalServerKeyShares.map((serverKeyShare)=>mpcSigner.refresh(roomId, serverKeyShare)));
487
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
488
+ externalServerKeyShares: refreshResults,
489
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
490
+ });
491
+ await this.storeEncryptedBackupByWallet({
492
+ accountAddress,
493
+ password: password != null ? password : this.environmentId
494
+ });
495
+ return refreshResults;
496
+ }
497
+ async getExportId({ chainName, serverKeyShare }) {
498
+ const mpcSigner = getMPCSigner({
499
+ chainName,
500
+ baseRelayUrl: this.baseMPCRelayApiUrl
501
+ });
502
+ const exportId = await mpcSigner.exportID(serverKeyShare);
503
+ return exportId;
504
+ }
505
+ /**
506
+ * Helper function to create client shares required to complete a reshare ceremony.
507
+ * @param {string} chainName - The chain to create shares for
508
+ * @param {WalletProperties} wallet - The wallet to reshare
509
+ * @param {ThresholdSignatureScheme} oldThresholdSignatureScheme - The current threshold signature scheme
510
+ * @param {ThresholdSignatureScheme} newThresholdSignatureScheme - The target threshold signature scheme
511
+ * @returns {Promise<{
512
+ * newClientInitKeygenResults: ClientInitKeygenResult[],
513
+ * newClientKeygenIds: string[],
514
+ * existingClientKeygenIds: string[],
515
+ * existingClientKeyShares: ClientKeyShare[]
516
+ * }>} Object containing new and existing client keygen results, IDs and shares
517
+ * @todo Support higher to lower reshare strategies
518
+ */ async reshareStrategy({ chainName, wallet, oldThresholdSignatureScheme, newThresholdSignatureScheme }) {
519
+ const mpcSigner = getMPCSigner({
520
+ chainName,
521
+ baseRelayUrl: this.baseMPCRelayApiUrl
522
+ });
523
+ // Determine share counts based on threshold signature schemes
524
+ const { newExternalServerShareCount, existingExternalServerShareCount } = core.getServerWalletReshareConfig({
525
+ oldThresholdSignatureScheme,
526
+ newThresholdSignatureScheme
527
+ });
528
+ // Create new client shares
529
+ const newExternalServerInitKeygenResults = await Promise.all(Array.from({
530
+ length: newExternalServerShareCount
531
+ }, ()=>mpcSigner.initKeygen()));
532
+ const newExternalServerKeygenIds = newExternalServerInitKeygenResults.map((result)=>result.keygenId);
533
+ // Get existing client shares
534
+ const existingExternalServerKeyShares = wallet.externalServerKeyShares.slice(0, existingExternalServerShareCount);
535
+ const existingExternalServerKeygenIds = await Promise.all(existingExternalServerKeyShares.map(async (keyShare)=>await this.getExportId({
536
+ chainName,
537
+ serverKeyShare: keyShare
538
+ })));
539
+ return {
540
+ newExternalServerInitKeygenResults,
541
+ newExternalServerKeygenIds,
542
+ existingExternalServerKeygenIds,
543
+ existingExternalServerKeyShares
544
+ };
545
+ }
546
+ async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined }) {
547
+ this.ensureApiClientAuthenticated();
548
+ await this.verifyPassword({
549
+ accountAddress,
550
+ password,
551
+ walletOperation: core.WalletOperation.RESHARE
552
+ });
553
+ const { existingExternalServerShareCount } = core.getServerWalletReshareConfig({
554
+ oldThresholdSignatureScheme,
555
+ newThresholdSignatureScheme
556
+ });
557
+ const wallet = await this.getWallet({
558
+ accountAddress,
559
+ walletOperation: core.WalletOperation.RESHARE,
560
+ shareCount: existingExternalServerShareCount,
561
+ password
562
+ });
563
+ const { newExternalServerInitKeygenResults, newExternalServerKeygenIds, existingExternalServerKeygenIds, existingExternalServerKeyShares } = await this.reshareStrategy({
564
+ chainName,
565
+ wallet,
566
+ oldThresholdSignatureScheme,
567
+ newThresholdSignatureScheme
568
+ });
569
+ const externalServerKeygenIds = [
570
+ ...newExternalServerKeygenIds,
571
+ ...existingExternalServerKeygenIds
572
+ ];
573
+ // Server to create the room and complete the server reshare logics
574
+ const data = await this.apiClient.reshare({
575
+ walletId: wallet.walletId,
576
+ clientKeygenIds: externalServerKeygenIds,
577
+ oldThresholdSignatureScheme,
578
+ newThresholdSignatureScheme
579
+ });
580
+ const { roomId, serverKeygenIds: dynamicServerKeygenIds, newServerKeygenIds: newDynamicServerKeygenIds = [] } = data;
581
+ // Get the MPC config for the threshold signature scheme
582
+ const oldMpcConfig = core.MPC_CONFIG[oldThresholdSignatureScheme];
583
+ const newMpcConfig = core.MPC_CONFIG[newThresholdSignatureScheme];
584
+ const allPartyKeygenIds = [
585
+ ...externalServerKeygenIds,
586
+ ...dynamicServerKeygenIds,
587
+ ...newDynamicServerKeygenIds
588
+ ];
589
+ const mpcSigner = getMPCSigner({
590
+ chainName,
591
+ baseRelayUrl: this.baseMPCRelayApiUrl
592
+ });
593
+ const reshareResults = await Promise.all([
594
+ ...newExternalServerInitKeygenResults.map((keygenResult)=>mpcSigner.reshareNewParty(roomId, oldMpcConfig.threshold, newMpcConfig.threshold, keygenResult, allPartyKeygenIds)),
595
+ ...existingExternalServerKeyShares.map((keyShare)=>mpcSigner.reshareRemainingParty(roomId, newMpcConfig.threshold, keyShare, allPartyKeygenIds))
596
+ ]);
597
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
598
+ externalServerKeyShares: reshareResults,
599
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
600
+ });
601
+ await this.storeEncryptedBackupByWallet({
602
+ accountAddress,
603
+ password
604
+ });
605
+ return reshareResults;
606
+ }
607
+ async exportKey({ accountAddress, chainName, password = undefined }) {
608
+ this.ensureApiClientAuthenticated();
609
+ await this.verifyPassword({
610
+ accountAddress,
611
+ password,
612
+ walletOperation: core.WalletOperation.EXPORT_PRIVATE_KEY
613
+ });
614
+ const wallet = await this.getWallet({
615
+ accountAddress,
616
+ password,
617
+ walletOperation: core.WalletOperation.EXPORT_PRIVATE_KEY
618
+ });
619
+ const mpcSigner = getMPCSigner({
620
+ chainName,
621
+ baseRelayUrl: this.baseMPCRelayApiUrl
622
+ });
623
+ const exportId = await this.getExportId({
624
+ chainName,
625
+ serverKeyShare: wallet.externalServerKeyShares[0]
626
+ });
627
+ const data = await this.apiClient.exportKey({
628
+ walletId: wallet.walletId,
629
+ exportId
630
+ });
631
+ const keyExportRaw = await mpcSigner.exportFullPrivateKey(data.roomId, wallet.externalServerKeyShares[0], exportId);
632
+ if (!keyExportRaw) {
633
+ throw new Error('Error exporting private key');
634
+ }
635
+ const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
636
+ let derivedPrivateKey;
637
+ if (mpcSigner instanceof node.Ecdsa) {
638
+ derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, derivationPath);
639
+ } else if (mpcSigner instanceof node.Ed25519) {
640
+ derivedPrivateKey = keyExportRaw;
641
+ } else if (mpcSigner instanceof node.BIP340) {
642
+ derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, derivationPath);
643
+ }
644
+ return {
645
+ derivedPrivateKey
646
+ };
647
+ }
648
+ async offlineExportKey({ chainName, keyShares, derivationPath }) {
649
+ try {
650
+ if (!keyShares || keyShares.length < 2) {
651
+ throw new Error(`Must provide at least min threshold of key shares`);
652
+ }
653
+ const mpcSigner = getMPCSigner({
654
+ chainName,
655
+ baseRelayUrl: this.baseMPCRelayApiUrl
656
+ });
657
+ const walletKeyShares = keyShares.map((keyShare)=>{
658
+ 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);
659
+ });
660
+ const keyExportRaw = await mpcSigner.offlineExportFullPrivateKey(walletKeyShares);
661
+ if (!keyExportRaw) {
662
+ throw new Error('Error exporting private key: Export returned null');
663
+ }
664
+ const chainConfig = core.getMPCChainConfig(chainName);
665
+ const walletDerivationPath = !derivationPath ? undefined : new Uint32Array(chainConfig.derivationPath);
666
+ let derivedPrivateKey;
667
+ if (mpcSigner instanceof node.Ecdsa) {
668
+ derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
669
+ } else if (mpcSigner instanceof node.Ed25519) {
670
+ derivedPrivateKey = keyExportRaw;
671
+ } else if (mpcSigner instanceof node.BIP340) {
672
+ derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
673
+ }
674
+ return {
675
+ derivedPrivateKey
676
+ };
677
+ } catch (error) {
678
+ this.logger.error('Error in offlineExportKey:', error);
679
+ throw error;
680
+ }
681
+ }
682
+ async encryptKeyShare({ keyShare, password }) {
683
+ const serializedKeyShare = JSON.stringify(keyShare);
684
+ const encryptedKeyShare = await encryptData({
685
+ data: serializedKeyShare,
686
+ password: password != null ? password : this.environmentId
687
+ });
688
+ // stringify the encrypted key share, convert to base64, and store it
689
+ const serializedEncryptedKeyShare = Buffer.from(JSON.stringify(encryptedKeyShare)).toString('base64');
690
+ return serializedEncryptedKeyShare;
691
+ }
692
+ async ensureCeremonyCompletionBeforeBackup({ accountAddress }) {
693
+ let retries = 0;
694
+ const maxRetries = 3;
695
+ while((!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) && retries < maxRetries){
696
+ await new Promise((resolve)=>setTimeout(resolve, 1000)); // Wait 1 second
697
+ retries++;
698
+ }
699
+ if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
700
+ throw new Error('Ceremony completion timeout');
701
+ }
702
+ }
703
+ async storeEncryptedBackupByWallet({ accountAddress, externalServerKeyShares = undefined, password = undefined }) {
704
+ this.ensureApiClientAuthenticated();
705
+ //add retry logic for ceremony completion to prevent race condition
706
+ await this.ensureCeremonyCompletionBeforeBackup({
707
+ accountAddress
708
+ });
709
+ try {
710
+ const keySharesToBackup = externalServerKeyShares != null ? externalServerKeyShares : await this.getExternalServerKeyShares({
711
+ accountAddress
712
+ });
713
+ if (!keySharesToBackup || keySharesToBackup.length === 0) {
714
+ throw new Error(`Key shares not found for accountAddress: ${accountAddress}`);
715
+ }
716
+ const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
717
+ keyShare,
718
+ password
719
+ })));
720
+ if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
721
+ throw new Error(`WalletId not found for accountAddress: ${accountAddress}`);
722
+ }
723
+ const data = await this.apiClient.storeEncryptedBackupByWallet({
724
+ walletId: this.walletMap[accountAddress].walletId,
725
+ encryptedKeyShares,
726
+ passwordEncrypted: Boolean(password) && password !== this.environmentId
727
+ });
728
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
729
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
730
+ walletProperties: {
731
+ derivationPath: this.walletMap[accountAddress].derivationPath,
732
+ keyShares: data.keyShares,
733
+ thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme
734
+ }
735
+ })
736
+ });
737
+ return data;
738
+ } catch (error) {
739
+ this.logger.error('Error in storeEncryptedBackupByWallet:', error);
740
+ throw error;
741
+ }
742
+ }
743
+ async storeEncryptedBackupByWalletWithRetry({ accountAddress, externalServerKeyShares, password }) {
744
+ await retryPromise(()=>this.storeEncryptedBackupByWallet({
745
+ accountAddress,
746
+ externalServerKeyShares,
747
+ password
748
+ }), {
749
+ operationName: 'store encrypted backup',
750
+ logContext: {
751
+ walletAddress: accountAddress,
752
+ keyShares: externalServerKeyShares == null ? void 0 : externalServerKeyShares.map((keyShare)=>this.encryptKeyShare({
753
+ keyShare,
754
+ password
755
+ }))
756
+ }
757
+ });
758
+ }
759
+ async getExternalServerKeyShares({ accountAddress, password }) {
760
+ const wallet = await this.getWallet({
761
+ accountAddress,
762
+ password,
763
+ walletOperation: core.WalletOperation.REACH_THRESHOLD
764
+ });
765
+ return wallet.externalServerKeyShares;
766
+ }
767
+ async updatePassword({ accountAddress, existingPassword, newPassword }) {
768
+ await this.getWallet({
769
+ accountAddress,
770
+ password: existingPassword,
771
+ walletOperation: core.WalletOperation.REACH_ALL_PARTIES
772
+ });
773
+ await this.storeEncryptedBackupByWallet({
774
+ accountAddress,
775
+ password: newPassword
776
+ });
777
+ }
778
+ async decryptKeyShare({ keyShare, password }) {
779
+ const decodedKeyShare = JSON.parse(Buffer.from(keyShare, 'base64').toString());
780
+ const decryptedKeyShare = await decryptData({
781
+ data: decodedKeyShare,
782
+ password: password != null ? password : this.environmentId
783
+ });
784
+ const deserializedKeyShare = JSON.parse(decryptedKeyShare);
785
+ return deserializedKeyShare;
786
+ }
787
+ /**
788
+ * Helper function to determine keyshare recovery strategy for dynamic shares.
789
+ * For REFRESH operations, retrieves enough shares to meet the client threshold.
790
+ * For all other operations, retrieves just 1 share.
791
+ *
792
+ * @param clientKeyShareBackupInfo - Information about backed up key shares
793
+ * @param thresholdSignatureScheme - The signature scheme being used (2-of-2, 2-of-3, etc)
794
+ * @param walletOperation - The operation being performed (REFRESH, SIGN_MESSAGE, etc)
795
+ * @param shareCount - The number of shares to recover if specified for reshare operations
796
+ * @returns @shares: Object mapping backup locations to arrays of share IDs to recover
797
+ * @returns @requiredShareCount: The number of shares required to recover
798
+ */ recoverStrategy({ externalServerKeySharesBackupInfo, thresholdSignatureScheme, walletOperation, shareCount = undefined }) {
799
+ const { backups } = externalServerKeySharesBackupInfo;
800
+ const { clientThreshold } = core.MPC_CONFIG[thresholdSignatureScheme];
801
+ let requiredShareCount = walletOperation === core.WalletOperation.REFRESH || walletOperation === core.WalletOperation.REACH_ALL_PARTIES || walletOperation === core.WalletOperation.RESHARE ? clientThreshold : 1;
802
+ // Override requiredShareCount if shareCount is provided
803
+ if (shareCount !== undefined) {
804
+ requiredShareCount = shareCount;
805
+ }
806
+ const dynamicShares = backups[core.BackupLocation.DYNAMIC].slice(0, requiredShareCount);
807
+ return {
808
+ shares: {
809
+ [core.BackupLocation.DYNAMIC]: dynamicShares
810
+ },
811
+ requiredShareCount
812
+ };
813
+ }
814
+ async recoverEncryptedBackupByWallet({ accountAddress, password, walletOperation, shareCount = undefined, storeRecoveredShares = true }) {
815
+ this.ensureApiClientAuthenticated();
816
+ const wallet = this.walletMap[accountAddress];
817
+ this.logger.debug(`recoverEncryptedBackupByWallet wallet: ${walletOperation}`, wallet);
818
+ const { shares } = this.recoverStrategy({
819
+ externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
820
+ thresholdSignatureScheme: wallet.thresholdSignatureScheme,
821
+ walletOperation,
822
+ shareCount
823
+ });
824
+ const { dynamic: dynamicKeyShareIds } = shares;
825
+ const data = await this.apiClient.recoverEncryptedBackupByWallet({
826
+ walletId: wallet.walletId,
827
+ keyShareIds: dynamicKeyShareIds
828
+ });
829
+ const dynamicKeyShares = data.keyShares.filter((keyShare)=>keyShare.encryptedAccountCredential !== null && keyShare.backupLocation === core.BackupLocation.DYNAMIC);
830
+ const decryptedKeyShares = await Promise.all(dynamicKeyShares.map((keyShare)=>this.decryptKeyShare({
831
+ keyShare: keyShare.encryptedAccountCredential,
832
+ password: password != null ? password : this.environmentId
833
+ })));
834
+ if (storeRecoveredShares) {
835
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
836
+ externalServerKeyShares: mergeUniqueKeyShares(this.walletMap[accountAddress].externalServerKeyShares || [], decryptedKeyShares)
837
+ });
838
+ }
839
+ return decryptedKeyShares;
840
+ }
841
+ async exportExternalServerKeyShares({ accountAddress, password }) {
842
+ await this.verifyPassword({
843
+ accountAddress,
844
+ password,
845
+ walletOperation: core.WalletOperation.REACH_ALL_PARTIES
846
+ });
847
+ const externalServerKeyShares = await this.getExternalServerKeyShares({
848
+ accountAddress,
849
+ password
850
+ });
851
+ return externalServerKeyShares;
852
+ }
853
+ /**
854
+ * Helper function to check if the required wallet fields are present and valid
855
+ * @param accountAddress - The account address of the wallet to check
856
+ * @param walletOperation - The wallet operation that determines required fields
857
+ * @returns boolean indicating if wallet needs to be re-fetched and restored from server
858
+ */ async checkWalletFields({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD, shareCount }) {
859
+ let keyshareCheck = false;
860
+ let walletCheck = false;
861
+ let thresholdSignatureSchemeCheck = false;
862
+ let derivationPathCheck = false;
863
+ // check if wallet exists
864
+ const existingWallet = this.walletMap[accountAddress];
865
+ if (existingWallet) {
866
+ walletCheck = true;
867
+ }
868
+ // check if threshold signature scheme exists
869
+ if (existingWallet == null ? void 0 : existingWallet.thresholdSignatureScheme) {
870
+ thresholdSignatureSchemeCheck = true;
871
+ }
872
+ // check if derivation path exists
873
+ if ((existingWallet == null ? void 0 : existingWallet.derivationPath) || (existingWallet == null ? void 0 : existingWallet.derivationPath) === '') {
874
+ derivationPathCheck = true;
875
+ }
876
+ // check if wallet already exists with sufficient keyshares
877
+ if (existingWallet) {
878
+ var _existingWallet_externalServerKeyShares;
879
+ const { shares } = this.recoverStrategy({
880
+ externalServerKeySharesBackupInfo: existingWallet.externalServerKeySharesBackupInfo || {
881
+ backups: getExternalServerKeyShareBackupInfo()
882
+ },
883
+ thresholdSignatureScheme: existingWallet.thresholdSignatureScheme,
884
+ walletOperation,
885
+ shareCount
886
+ });
887
+ const { dynamic: requiredDynamicKeyShareIds = [] } = shares;
888
+ if (requiredDynamicKeyShareIds.length <= (((_existingWallet_externalServerKeyShares = existingWallet.externalServerKeyShares) == null ? void 0 : _existingWallet_externalServerKeyShares.length) || 0)) {
889
+ keyshareCheck = true;
890
+ }
891
+ }
892
+ return walletCheck && thresholdSignatureSchemeCheck && keyshareCheck && derivationPathCheck;
893
+ }
894
+ /**
895
+ * verifyPassword attempts to recover and decrypt a single client key share using the provided password.
896
+ * If successful, the key share is encrypted with the new password. This method solely performs the recovery
897
+ * and decryption without storing the restored key shares. If unsuccessful, it throws an error.
898
+ */ async verifyPassword({ accountAddress, password = undefined, walletOperation = core.WalletOperation.NO_OPERATION }) {
899
+ await this.getWallet({
900
+ accountAddress,
901
+ password,
902
+ walletOperation
903
+ });
904
+ if (await this.requiresPasswordForOperation({
905
+ accountAddress,
906
+ walletOperation
907
+ }) && !password) {
908
+ throw new Error('Password is required for operation but not provided');
909
+ }
910
+ // silent return if no password is provided and operation does not require a password
911
+ if (!password) {
912
+ return;
913
+ }
914
+ const { backups } = await this.getWalletExternalServerKeyShareBackupInfo({
915
+ accountAddress
916
+ });
917
+ const { dynamic: dynamicKeyShareIds = [] } = backups;
918
+ if (!dynamicKeyShareIds || dynamicKeyShareIds.length === 0) {
919
+ throw new Error('No dynamic key shares found');
920
+ }
921
+ try {
922
+ await this.recoverEncryptedBackupByWallet({
923
+ accountAddress,
924
+ password,
925
+ walletOperation,
926
+ shareCount: 1,
927
+ storeRecoveredShares: false
928
+ });
929
+ } catch (error) {
930
+ this.logger.error('Error in verifying password', error);
931
+ throw new Error('Incorrect password');
932
+ }
933
+ }
934
+ async isPasswordEncrypted({ accountAddress }) {
935
+ const externalServerKeySharesBackupInfo = await this.getWalletExternalServerKeyShareBackupInfo({
936
+ accountAddress
937
+ });
938
+ return externalServerKeySharesBackupInfo == null ? void 0 : externalServerKeySharesBackupInfo.passwordEncrypted;
939
+ }
940
+ /**
941
+ * check if the operation requires a password
942
+ */ async requiresPasswordForOperation({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD }) {
943
+ const isEncrypted = await this.isPasswordEncrypted({
944
+ accountAddress
945
+ });
946
+ if (!isEncrypted) {
947
+ return false;
948
+ }
949
+ return this.requiresRestoreBackupSharesForOperation({
950
+ accountAddress,
951
+ walletOperation
952
+ });
953
+ }
954
+ /**
955
+ * check if the operation requires restoring backup shares
956
+ */ async requiresRestoreBackupSharesForOperation({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD }) {
957
+ const externalServerKeySharesBackupInfo = await this.getWalletExternalServerKeyShareBackupInfo({
958
+ accountAddress
959
+ });
960
+ const externalServerKeyShares = this.walletMap[accountAddress].externalServerKeyShares || [];
961
+ if (walletOperation === core.WalletOperation.REACH_ALL_PARTIES || walletOperation === core.WalletOperation.REFRESH || walletOperation === core.WalletOperation.RESHARE) {
962
+ return true;
963
+ }
964
+ const { requiredShareCount } = this.recoverStrategy({
965
+ externalServerKeySharesBackupInfo,
966
+ thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme,
967
+ walletOperation
968
+ });
969
+ if (externalServerKeyShares.length >= requiredShareCount) {
970
+ return false;
971
+ }
972
+ return true;
973
+ }
974
+ async getWalletExternalServerKeyShareBackupInfo({ accountAddress }) {
975
+ var _this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC, _this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups, _this_walletMap_accountAddress_externalServerKeySharesBackupInfo, _this_walletMap_accountAddress, _user_verifiedCredentials;
976
+ this.ensureApiClientAuthenticated();
977
+ // Return existing backup info if it exists
978
+ 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) {
979
+ return this.walletMap[accountAddress].externalServerKeySharesBackupInfo;
980
+ }
981
+ // Get backup info from server
982
+ const user = await this.apiClient.getUser();
983
+ const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
984
+ return getExternalServerKeyShareBackupInfo({
985
+ walletProperties: wallet == null ? void 0 : wallet.walletProperties
986
+ });
987
+ }
988
+ async getWallet({ accountAddress, walletOperation = core.WalletOperation.NO_OPERATION, shareCount = undefined, password = undefined }) {
989
+ var _user_verifiedCredentials;
990
+ this.ensureApiClientAuthenticated();
991
+ const existingWalletCheck = await this.checkWalletFields({
992
+ accountAddress,
993
+ walletOperation,
994
+ shareCount
995
+ });
996
+ if (existingWalletCheck) {
997
+ this.logger.debug(`Wallet ${accountAddress} already exists`);
998
+ return this.walletMap[accountAddress];
999
+ }
1000
+ //todo: Question - why don't we just call getWallets here? so then all are preloaded
1001
+ // Fetch and restore wallet from server
1002
+ const user = await this.apiClient.getUser();
1003
+ const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
1004
+ this.logger.debug('Restoring wallet', wallet);
1005
+ const walletProperties = wallet.walletProperties;
1006
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
1007
+ walletId: wallet.id,
1008
+ chainName: wallet.chainName,
1009
+ accountAddress,
1010
+ thresholdSignatureScheme: walletProperties.thresholdSignatureScheme,
1011
+ derivationPath: walletProperties.derivationPath,
1012
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
1013
+ walletProperties
1014
+ })
1015
+ });
1016
+ if (walletOperation !== core.WalletOperation.NO_OPERATION && await this.requiresRestoreBackupSharesForOperation({
1017
+ accountAddress,
1018
+ walletOperation
1019
+ })) {
1020
+ const decryptedKeyShares = await this.recoverEncryptedBackupByWallet({
1021
+ accountAddress,
1022
+ password: password != null ? password : this.environmentId,
1023
+ walletOperation: walletOperation,
1024
+ shareCount
1025
+ });
1026
+ this.logger.debug('Recovered backup', decryptedKeyShares);
1027
+ }
1028
+ const walletCount = Object.keys(this.walletMap).length;
1029
+ if (walletCount === 0) {
1030
+ throw new Error('No wallets found');
1031
+ }
1032
+ // Return the only wallet if there's just one
1033
+ if (walletCount === 1) {
1034
+ return Object.values(this.walletMap)[0];
1035
+ }
1036
+ return this.walletMap[accountAddress];
1037
+ }
1038
+ async getWallets() {
1039
+ var _user_verifiedCredentials;
1040
+ this.ensureApiClientAuthenticated();
1041
+ const user = await this.apiClient.getUser();
1042
+ const waasWallets = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.filter((vc)=>vc.walletName === 'dynamicwaas');
1043
+ const wallets = waasWallets.map((vc)=>{
1044
+ var _this_walletMap_vc_address, _this_walletMap_vc_address1, _vc_walletProperties;
1045
+ var _this_walletMap_vc_address_derivationPath;
1046
+ return {
1047
+ walletId: vc.id,
1048
+ chainName: vc.chain,
1049
+ accountAddress: vc.address,
1050
+ serverKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
1051
+ walletProperties: vc.walletProperties || {}
1052
+ }),
1053
+ externalServerKeyShares: ((_this_walletMap_vc_address = this.walletMap[vc.address]) == null ? void 0 : _this_walletMap_vc_address.externalServerKeyShares) || [],
1054
+ 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,
1055
+ thresholdSignatureScheme: (_vc_walletProperties = vc.walletProperties) == null ? void 0 : _vc_walletProperties.thresholdSignatureScheme
1056
+ };
1057
+ });
1058
+ this.walletMap = wallets.reduce((acc, wallet)=>{
1059
+ var _acc_accountAddress;
1060
+ const accountAddress = wallet.accountAddress;
1061
+ acc[wallet.accountAddress] = {
1062
+ walletId: wallet.walletId,
1063
+ chainName: wallet.chainName,
1064
+ accountAddress: wallet.accountAddress,
1065
+ externalServerKeyShares: wallet.externalServerKeyShares || [],
1066
+ externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
1067
+ derivationPath: ((_acc_accountAddress = acc[accountAddress]) == null ? void 0 : _acc_accountAddress.derivationPath) || undefined,
1068
+ thresholdSignatureScheme: wallet.thresholdSignatureScheme
1069
+ };
1070
+ return acc;
1071
+ }, {});
1072
+ return wallets;
1073
+ }
1074
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug }){
1075
+ this.logger = logger;
1076
+ this.walletMap = {} // todo: store in session storage
1077
+ ;
1078
+ this.isApiClientAuthenticated = false;
1079
+ this.environmentId = environmentId;
1080
+ this.baseMPCRelayApiUrl = baseMPCRelayApiUrl;
1081
+ this.baseApiUrl = baseApiUrl;
1082
+ this.debug = Boolean(debug);
1083
+ this.logger.setLogLevel(this.debug ? 'DEBUG' : DEFAULT_LOG_LEVEL);
1084
+ }
1085
+ }
1086
+
1087
+ Object.defineProperty(exports, "BIP340", {
1088
+ enumerable: true,
1089
+ get: function () { return node.BIP340; }
1090
+ });
1091
+ Object.defineProperty(exports, "BIP340InitKeygenResult", {
1092
+ enumerable: true,
1093
+ get: function () { return node.BIP340InitKeygenResult; }
1094
+ });
1095
+ Object.defineProperty(exports, "BIP340KeygenResult", {
1096
+ enumerable: true,
1097
+ get: function () { return node.BIP340KeygenResult; }
1098
+ });
1099
+ Object.defineProperty(exports, "Ecdsa", {
1100
+ enumerable: true,
1101
+ get: function () { return node.Ecdsa; }
1102
+ });
1103
+ Object.defineProperty(exports, "EcdsaInitKeygenResult", {
1104
+ enumerable: true,
1105
+ get: function () { return node.EcdsaInitKeygenResult; }
1106
+ });
1107
+ Object.defineProperty(exports, "EcdsaKeygenResult", {
1108
+ enumerable: true,
1109
+ get: function () { return node.EcdsaKeygenResult; }
1110
+ });
1111
+ Object.defineProperty(exports, "EcdsaPublicKey", {
1112
+ enumerable: true,
1113
+ get: function () { return node.EcdsaPublicKey; }
1114
+ });
1115
+ Object.defineProperty(exports, "EcdsaSignature", {
1116
+ enumerable: true,
1117
+ get: function () { return node.EcdsaSignature; }
1118
+ });
1119
+ Object.defineProperty(exports, "Ed25519", {
1120
+ enumerable: true,
1121
+ get: function () { return node.Ed25519; }
1122
+ });
1123
+ Object.defineProperty(exports, "Ed25519InitKeygenResult", {
1124
+ enumerable: true,
1125
+ get: function () { return node.Ed25519InitKeygenResult; }
1126
+ });
1127
+ Object.defineProperty(exports, "Ed25519KeygenResult", {
1128
+ enumerable: true,
1129
+ get: function () { return node.Ed25519KeygenResult; }
1130
+ });
1131
+ Object.defineProperty(exports, "MessageHash", {
1132
+ enumerable: true,
1133
+ get: function () { return node.MessageHash; }
1134
+ });
1135
+ exports.DynamicWalletClient = DynamicWalletClient;
1136
+ exports.base64ToBytes = base64ToBytes;
1137
+ exports.bytesToBase64 = bytesToBase64;
1138
+ exports.ensureBase64Padding = ensureBase64Padding;
1139
+ exports.getExternalServerKeyShareBackupInfo = getExternalServerKeyShareBackupInfo;
1140
+ exports.getMPCSignatureScheme = getMPCSignatureScheme;
1141
+ exports.getMPCSigner = getMPCSigner;
1142
+ exports.isHexString = isHexString;
1143
+ exports.mergeUniqueKeyShares = mergeUniqueKeyShares;
1144
+ exports.retryPromise = retryPromise;
1145
+ exports.stringToBytes = stringToBytes;
1146
+ Object.keys(core).forEach(function (k) {
1147
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1148
+ enumerable: true,
1149
+ get: function () { return core[k]; }
1150
+ });
1151
+ });