@dynamic-labs-wallet/node 0.0.0-preview.114.4 → 0.0.1-paolo-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 (66) hide show
  1. package/index.cjs.js +790 -233
  2. package/index.esm.js +778 -195
  3. package/internal/core/bip340.cjs +1 -0
  4. package/internal/core/common.cjs +1 -0
  5. package/internal/core/ecdsa.cjs +1 -0
  6. package/internal/core/ecdsa.d.ts +1 -1
  7. package/internal/core/ed25519.cjs +1 -0
  8. package/internal/core/ed25519_exportable.cjs +1 -0
  9. package/internal/core/ed25519_exportable.d.ts +21 -0
  10. package/internal/core/index.cjs +1 -0
  11. package/internal/core/index.d.ts +4 -2
  12. package/internal/core/native.d.ts +65 -0
  13. package/internal/core/sr25519.cjs +1 -0
  14. package/internal/core/sr25519.d.ts +22 -0
  15. package/internal/core/types.cjs +1 -0
  16. package/internal/core/types.d.ts +20 -0
  17. package/internal/node/index.cjs +1 -0
  18. package/internal/node/index.d.ts +8 -2
  19. package/internal/node/native/libmpc_executor_linux_arm64_nodejs.node +0 -0
  20. package/internal/node/native/libmpc_executor_linux_x86_64_nodejs.node +0 -0
  21. package/internal/node/native/libmpc_executor_macos_arm64_nodejs.node +0 -0
  22. package/internal/node/native/libmpc_executor_macos_x86_64_nodejs.node +0 -0
  23. package/internal/node/native.cjs +1 -0
  24. package/internal/node/native.d.ts +1 -1
  25. package/package.json +13 -8
  26. package/src/backup/encryption.d.ts +42 -2
  27. package/src/backup/encryption.d.ts.map +1 -1
  28. package/src/backup/utils.d.ts +4 -0
  29. package/src/backup/utils.d.ts.map +1 -0
  30. package/src/client.d.ts +85 -30
  31. package/src/client.d.ts.map +1 -1
  32. package/src/core/createCore.d.ts +25 -0
  33. package/src/core/createCore.d.ts.map +1 -0
  34. package/src/core/types.d.ts +7 -0
  35. package/src/core/types.d.ts.map +1 -0
  36. package/src/delegatedClient/createDelegatedClient.d.ts +23 -0
  37. package/src/delegatedClient/createDelegatedClient.d.ts.map +1 -0
  38. package/src/delegatedClient/index.d.ts +7 -0
  39. package/src/delegatedClient/index.d.ts.map +1 -0
  40. package/src/delegatedClient/modules/decryptWebhookData.d.ts +18 -0
  41. package/src/delegatedClient/modules/decryptWebhookData.d.ts.map +1 -0
  42. package/src/delegatedClient/modules/revokeDelegation.d.ts +3 -0
  43. package/src/delegatedClient/modules/revokeDelegation.d.ts.map +1 -0
  44. package/src/delegatedClient/modules/sign.d.ts +31 -0
  45. package/src/delegatedClient/modules/sign.d.ts.map +1 -0
  46. package/src/index.d.ts +11 -5
  47. package/src/index.d.ts.map +1 -1
  48. package/src/mpc/index.d.ts +2 -2
  49. package/src/mpc/index.d.ts.map +1 -1
  50. package/src/mpc/mpc.d.ts +3 -4
  51. package/src/mpc/mpc.d.ts.map +1 -1
  52. package/src/mpc/types.d.ts +1 -2
  53. package/src/mpc/types.d.ts.map +1 -1
  54. package/src/types.d.ts +11 -2
  55. package/src/types.d.ts.map +1 -1
  56. package/src/utils.d.ts +5 -2
  57. package/src/utils.d.ts.map +1 -1
  58. package/internal/core/bip340.js +0 -1
  59. package/internal/core/common.js +0 -1
  60. package/internal/core/ecdsa.js +0 -1
  61. package/internal/core/ed25519.js +0 -1
  62. package/internal/core/index.js +0 -1
  63. package/internal/core/types.js +0 -1
  64. package/internal/node/index.js +0 -1
  65. package/internal/node/native.js +0 -1
  66. /package/internal/core/{native.js → native.cjs} +0 -0
package/index.cjs.js CHANGED
@@ -1,16 +1,20 @@
1
1
  'use strict';
2
2
 
3
+ var core$1 = require('#internal/core');
3
4
  var core = require('@dynamic-labs-wallet/core');
4
- var node = require('./internal/node');
5
- var logger$1 = require('@dynamic-labs/logger');
5
+ var node = require('#internal/node');
6
+ var uuid = require('uuid');
6
7
  var crypto = require('crypto');
8
+ var logger$1 = require('@dynamic-labs/logger');
9
+ require('node:crypto');
7
10
 
11
+ // Removed duplicate exports - these are already exported from #internal/core
8
12
  const getMPCSignatureScheme = ({ signingAlgorithm, baseRelayUrl = core.MPC_RELAY_PROD_API_URL })=>{
9
13
  switch(signingAlgorithm){
10
14
  case core.SigningAlgorithm.ECDSA:
11
15
  return new node.Ecdsa(baseRelayUrl);
12
16
  case core.SigningAlgorithm.ED25519:
13
- return new node.Ed25519(baseRelayUrl);
17
+ return new node.ExportableEd25519(baseRelayUrl);
14
18
  case core.SigningAlgorithm.BIP340:
15
19
  return new node.BIP340(baseRelayUrl);
16
20
  default:
@@ -65,7 +69,8 @@ const getExternalServerKeyShareBackupInfo = (params)=>{
65
69
  [core.BackupLocation.GOOGLE_DRIVE]: [],
66
70
  [core.BackupLocation.ICLOUD]: [],
67
71
  [core.BackupLocation.USER]: [],
68
- [core.BackupLocation.EXTERNAL]: []
72
+ [core.BackupLocation.EXTERNAL]: [],
73
+ [core.BackupLocation.DELEGATED]: []
69
74
  };
70
75
  if (!(params == null ? void 0 : (_params_walletProperties = params.walletProperties) == null ? void 0 : _params_walletProperties.keyShares)) {
71
76
  return {
@@ -75,7 +80,11 @@ const getExternalServerKeyShareBackupInfo = (params)=>{
75
80
  }
76
81
  params.walletProperties.keyShares.forEach((keyShare)=>{
77
82
  if (backups[keyShare.backupLocation]) {
78
- backups[keyShare.backupLocation].push(keyShare.id);
83
+ backups[keyShare.backupLocation].push({
84
+ location: keyShare.backupLocation,
85
+ keyShareId: keyShare.id,
86
+ passwordEncrypted: keyShare.passwordEncrypted
87
+ });
79
88
  }
80
89
  });
81
90
  const passwordEncrypted = Boolean((_params_walletProperties_keyShares_ = params.walletProperties.keyShares[0]) == null ? void 0 : _params_walletProperties_keyShares_.passwordEncrypted);
@@ -125,13 +134,64 @@ const getExternalServerKeyShareBackupInfo = (params)=>{
125
134
  // TypeScript needs this even though it's unreachable
126
135
  throw new Error('Unreachable code');
127
136
  }
137
+ const formatEvmMessage = (message)=>{
138
+ if (typeof message === 'string' && message.startsWith('0x')) {
139
+ const serializedTxBytes = Uint8Array.from(Buffer.from(message.slice(2), 'hex'));
140
+ return node.MessageHash.keccak256(serializedTxBytes);
141
+ }
142
+ return node.MessageHash.keccak256(message);
143
+ };
144
+ const formatSolanaMessage = (message)=>{
145
+ if (typeof message === 'string') {
146
+ if (!isHexString(message)) {
147
+ return Buffer.from(message).toString('hex');
148
+ } else {
149
+ return new Uint8Array(Buffer.from(message, 'hex'));
150
+ }
151
+ } else {
152
+ return message;
153
+ }
154
+ };
155
+ const formatMessage = (chainName, message)=>{
156
+ switch(chainName){
157
+ case 'EVM':
158
+ return formatEvmMessage(message);
159
+ case 'SVM':
160
+ return formatSolanaMessage(message);
161
+ case 'SUI':
162
+ return message;
163
+ default:
164
+ throw new Error('Unsupported chain name');
165
+ }
166
+ };
128
167
 
168
+ const ENCRYPTION_VERSION_LEGACY = 'v1';
169
+ const ENCRYPTION_VERSION_CURRENT = 'v2';
129
170
  const PBKDF2_ALGORITHM = 'PBKDF2';
130
- const PBKDF2_ITERATIONS = 100000;
131
171
  const PBKDF2_HASH_ALGORITHM = 'SHA-256';
132
172
  const AES_GCM_ALGORITHM = 'AES-GCM';
133
173
  const AES_GCM_LENGTH = 256;
134
- const getKey = async ({ password, salt })=>{
174
+ const ENCRYPTION_VERSIONS = {
175
+ [ENCRYPTION_VERSION_LEGACY]: {
176
+ version: ENCRYPTION_VERSION_LEGACY,
177
+ algorithm: AES_GCM_ALGORITHM,
178
+ keyDerivation: PBKDF2_ALGORITHM,
179
+ iterations: 100000,
180
+ hashAlgorithm: PBKDF2_HASH_ALGORITHM,
181
+ algorithmLength: AES_GCM_LENGTH
182
+ },
183
+ [ENCRYPTION_VERSION_CURRENT]: {
184
+ version: ENCRYPTION_VERSION_CURRENT,
185
+ algorithm: AES_GCM_ALGORITHM,
186
+ keyDerivation: PBKDF2_ALGORITHM,
187
+ iterations: 1000000,
188
+ hashAlgorithm: PBKDF2_HASH_ALGORITHM,
189
+ algorithmLength: AES_GCM_LENGTH
190
+ }
191
+ };
192
+ ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_CURRENT].iterations;
193
+ ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_LEGACY].iterations;
194
+ const getKey = async ({ password, salt, encryptionConfig })=>{
135
195
  const passwordBytes = stringToBytes(password);
136
196
  const initialKey = await crypto.subtle.importKey('raw', passwordBytes, {
137
197
  name: 'PBKDF2'
@@ -139,26 +199,34 @@ const getKey = async ({ password, salt })=>{
139
199
  'deriveKey'
140
200
  ]);
141
201
  return crypto.subtle.deriveKey({
142
- name: PBKDF2_ALGORITHM,
143
- salt,
144
- iterations: PBKDF2_ITERATIONS,
145
- hash: PBKDF2_HASH_ALGORITHM
202
+ name: encryptionConfig.keyDerivation,
203
+ salt: salt,
204
+ iterations: encryptionConfig.iterations,
205
+ hash: encryptionConfig.hashAlgorithm
146
206
  }, initialKey, {
147
- name: AES_GCM_ALGORITHM,
148
- length: AES_GCM_LENGTH
207
+ name: encryptionConfig.algorithm,
208
+ length: encryptionConfig.algorithmLength
149
209
  }, false, [
150
210
  'encrypt',
151
211
  'decrypt'
152
212
  ]);
153
213
  };
154
- const encryptData = async ({ data, password })=>{
214
+ /**
215
+ * Encrypts data using the specified encryption version.
216
+ * Always uses the latest encryption configuration for new encryptions by default.
217
+ */ const encryptData = async ({ data, password, version = ENCRYPTION_VERSION_CURRENT })=>{
218
+ const encryptionConfig = ENCRYPTION_VERSIONS[version];
219
+ if (!encryptionConfig) {
220
+ throw new Error(`Unsupported encryption version: ${version}`);
221
+ }
155
222
  try {
156
223
  // Generate a random salt and IV
157
224
  const salt = crypto.getRandomValues(new Uint8Array(16));
158
225
  const iv = crypto.getRandomValues(new Uint8Array(12)); // AES-GCM requires 12 bytes
159
226
  const key = await getKey({
160
227
  password,
161
- salt
228
+ salt,
229
+ encryptionConfig
162
230
  });
163
231
  // Convert the input string to bytes
164
232
  const dataBytes = new TextEncoder().encode(data);
@@ -171,25 +239,39 @@ const encryptData = async ({ data, password })=>{
171
239
  return {
172
240
  salt: bytesToBase64(salt),
173
241
  iv: bytesToBase64(iv),
174
- cipher: bytesToBase64(new Uint8Array(encryptedData))
242
+ cipher: bytesToBase64(new Uint8Array(encryptedData)),
243
+ version
175
244
  };
176
- } catch (error) {
245
+ } catch (e) {
177
246
  throw new Error('Error encrypting data');
178
247
  }
179
248
  };
180
- const decryptData = async ({ data, password })=>{
249
+ /**
250
+ * Decrypts data with version-based configuration.
251
+ * Uses the version field from the data to determine encryption parameters.
252
+ * Falls back to legacy version for backward compatibility if no version is specified.
253
+ */ const decryptData = async ({ data, password })=>{
254
+ const { salt, iv, cipher, version } = data;
255
+ // Ensure proper base64 padding for all values
256
+ const paddedSalt = ensureBase64Padding(salt);
257
+ const paddedIv = ensureBase64Padding(iv);
258
+ const paddedCipher = ensureBase64Padding(cipher);
259
+ const saltBytes = base64ToBytes(paddedSalt);
260
+ const ivBytes = base64ToBytes(paddedIv);
261
+ const cipherBytes = base64ToBytes(paddedCipher);
262
+ let encryptionConfig;
263
+ // Use version-based configuration if available, otherwise fallback to legacy
264
+ if (version && ENCRYPTION_VERSIONS[version]) {
265
+ encryptionConfig = ENCRYPTION_VERSIONS[version];
266
+ } else {
267
+ // Fallback to legacy version for backward compatibility
268
+ encryptionConfig = ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_LEGACY];
269
+ }
181
270
  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
271
  const key = await getKey({
191
272
  password,
192
- salt: saltBytes
273
+ salt: saltBytes,
274
+ encryptionConfig
193
275
  });
194
276
  const decryptedData = await crypto.subtle.decrypt({
195
277
  name: AES_GCM_ALGORITHM,
@@ -197,13 +279,23 @@ const decryptData = async ({ data, password })=>{
197
279
  }, key, cipherBytes);
198
280
  return new TextDecoder().decode(decryptedData);
199
281
  } catch (error) {
200
- throw new Error('Decryption failed');
282
+ throw new Error('Decryption failed: ' + error);
201
283
  }
202
284
  };
203
285
 
204
286
  const DEFAULT_LOG_LEVEL = 'INFO';
205
287
 
206
288
  class DynamicWalletClient {
289
+ async initializeForwardMPCClient() {
290
+ try {
291
+ await this.apiClient.forwardMPCClient.ensureWsConnection();
292
+ } catch (error) {
293
+ this.logger.error('Error connecting to ForwardMPC enclave websocket. Environment: ' + this.environmentId, {
294
+ error,
295
+ environmentId: this.environmentId
296
+ });
297
+ }
298
+ }
207
299
  ensureApiClientAuthenticated() {
208
300
  if (!this.isApiClientAuthenticated) {
209
301
  throw new Error('Client must be authenticated before making API calls. Call authenticateApiToken first.');
@@ -227,13 +319,15 @@ class DynamicWalletClient {
227
319
  });
228
320
  this.isApiClientAuthenticated = true;
229
321
  }
230
- async dynamicServerInitializeKeyGen({ chainName, externalServerKeygenIds, thresholdSignatureScheme, onError, onCeremonyComplete }) {
322
+ async dynamicServerInitializeKeyGen({ chainName, externalServerKeygenIds, thresholdSignatureScheme, dynamicRequestId, skipLock, onError, onCeremonyComplete }) {
231
323
  this.ensureApiClientAuthenticated();
232
324
  try {
233
325
  const data = await this.apiClient.createWalletAccount({
234
326
  chainName,
235
327
  clientKeygenIds: externalServerKeygenIds,
236
328
  thresholdSignatureScheme,
329
+ dynamicRequestId,
330
+ skipLock,
237
331
  onError,
238
332
  onCeremonyComplete
239
333
  });
@@ -267,8 +361,8 @@ class DynamicWalletClient {
267
361
  let publicKey;
268
362
  if (mpcSigner instanceof node.Ecdsa) {
269
363
  publicKey = await mpcSigner.derivePubkey(keyShare, derivationPath);
270
- } else if (mpcSigner instanceof node.Ed25519) {
271
- publicKey = await mpcSigner.derivePubkey(keyShare, derivationPath);
364
+ } else if (mpcSigner instanceof node.ExportableEd25519) {
365
+ publicKey = await mpcSigner.getPubkey(keyShare);
272
366
  }
273
367
  return publicKey;
274
368
  } catch (error) {
@@ -294,7 +388,13 @@ class DynamicWalletClient {
294
388
  ...dynamicServerKeygenIds,
295
389
  ...otherExternalServerKeygenIds
296
390
  ];
297
- return mpcSigner.keygen(roomId, mpcConfig.numberOfParties, mpcConfig.threshold, currentInit, allOtherKeygenIds);
391
+ if (!(mpcSigner instanceof node.ExportableEd25519)) {
392
+ return mpcSigner.keygen(roomId, mpcConfig.numberOfParties, mpcConfig.threshold, currentInit, allOtherKeygenIds);
393
+ } else {
394
+ // One party joins the keygen room using acting as the sampler: (wallet-service)
395
+ // The remaining parties join the key sampling ceremony using: (browser)
396
+ return mpcSigner.receiveKey(roomId, mpcConfig.numberOfParties, mpcConfig.threshold, currentInit, allOtherKeygenIds);
397
+ }
298
398
  }));
299
399
  // only need one client keygen result to derive the public key
300
400
  const [serverKeygenResult] = serverKeygenResults;
@@ -314,7 +414,8 @@ class DynamicWalletClient {
314
414
  throw new Error('Error deriving public key in externalServerKeyGen');
315
415
  }
316
416
  }
317
- async keyGen({ chainName, thresholdSignatureScheme, onError, onCeremonyComplete }) {
417
+ async keyGen({ chainName, thresholdSignatureScheme, skipLock, onError, onCeremonyComplete }) {
418
+ const dynamicRequestId = uuid.v4();
318
419
  try {
319
420
  const externalServerInitKeygenResults = await this.externalServerInitializeKeyGen({
320
421
  chainName,
@@ -324,7 +425,9 @@ class DynamicWalletClient {
324
425
  const { roomId, serverKeygenIds: dynamicServerKeygenIds } = await this.dynamicServerInitializeKeyGen({
325
426
  chainName,
326
427
  externalServerKeygenIds,
428
+ dynamicRequestId,
327
429
  thresholdSignatureScheme,
430
+ skipLock,
328
431
  onCeremonyComplete
329
432
  });
330
433
  const { rawPublicKey, externalServerKeyGenResults } = await this.externalServerKeyGen({
@@ -345,6 +448,7 @@ class DynamicWalletClient {
345
448
  }
346
449
  async importRawPrivateKey({ chainName, privateKey, thresholdSignatureScheme, onError, onCeremonyComplete }) {
347
450
  this.ensureApiClientAuthenticated();
451
+ const dynamicRequestId = uuid.v4();
348
452
  const mpcSigner = getMPCSigner({
349
453
  chainName,
350
454
  baseRelayUrl: this.baseMPCRelayApiUrl
@@ -358,6 +462,7 @@ class DynamicWalletClient {
358
462
  chainName,
359
463
  clientKeygenIds: externalServerKeygenIds,
360
464
  thresholdSignatureScheme,
465
+ dynamicRequestId,
361
466
  onError,
362
467
  onCeremonyComplete
363
468
  });
@@ -390,7 +495,8 @@ class DynamicWalletClient {
390
495
  externalServerKeyShares: externalServerKeygenResults
391
496
  };
392
497
  }
393
- async dynamicServerSign({ walletId, message }) {
498
+ async dynamicServerSign({ walletId, message, isFormatted, context, onError }) {
499
+ const dynamicRequestId = uuid.v4();
394
500
  this.ensureApiClientAuthenticated();
395
501
  // Create the room and sign the message
396
502
  if (typeof message !== 'string') {
@@ -398,35 +504,22 @@ class DynamicWalletClient {
398
504
  }
399
505
  const data = await this.apiClient.signMessage({
400
506
  walletId,
401
- message
507
+ message,
508
+ isFormatted,
509
+ dynamicRequestId,
510
+ context: context ? JSON.parse(JSON.stringify(context, (_key, value)=>typeof value === 'bigint' ? value.toString() : value)) : undefined,
511
+ onError,
512
+ forwardMPCClientEnabled: this.forwardMPCEnabled
402
513
  });
403
514
  return data;
404
515
  }
405
- async externalServerSign({ chainName, message, roomId, keyShare, derivationPath }) {
516
+ async externalServerSign({ chainName, message, roomId, keyShare, derivationPath, isFormatted }) {
406
517
  try {
407
518
  const mpcSigner = getMPCSigner({
408
519
  chainName,
409
520
  baseRelayUrl: this.baseMPCRelayApiUrl
410
521
  });
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
- }
522
+ const formattedMessage = isFormatted ? new node.MessageHash(message) : formatMessage(chainName, message);
430
523
  const signature = await mpcSigner.sign(roomId, keyShare, formattedMessage, derivationPath);
431
524
  return signature;
432
525
  } catch (error) {
@@ -434,35 +527,104 @@ class DynamicWalletClient {
434
527
  throw error;
435
528
  }
436
529
  }
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;
530
+ async forwardMPCClientSign({ chainName, message, roomId, keyShare, derivationPath, formattedMessage, dynamicRequestId, isFormatted }) {
531
+ try {
532
+ if (!this.apiClient.forwardMPCClient.connected) {
533
+ await this.initializeForwardMPCClient();
534
+ }
535
+ const messageForForwardMPC = core.serializeMessageForForwardMPC({
536
+ message,
537
+ isFormatted,
538
+ chainName
539
+ });
540
+ this.logger.info('Forward MPC enabled, signing message with forward MPC');
541
+ const environment = core.getEnvironmentFromUrl(this.baseApiUrl);
542
+ const defaultRelayUrl = core.MPC_RELAY_URL_MAP[environment];
543
+ const signature = await this.apiClient.forwardMPCClient.signMessage({
544
+ keyshare: keyShare,
545
+ message: chainName === 'SVM' ? formattedMessage : messageForForwardMPC,
546
+ relayDomain: this.baseMPCRelayApiUrl || defaultRelayUrl,
547
+ signingAlgo: chainName === 'EVM' ? 'ECDSA' : 'ED25519',
548
+ hashAlgo: chainName === 'EVM' && !isFormatted ? 'keccak256' : undefined,
549
+ derivationPath: derivationPath,
550
+ roomUuid: roomId
551
+ });
552
+ const signatureBytes = signature.data.signature;
553
+ if (!(signatureBytes instanceof Uint8Array)) {
554
+ throw new TypeError(`Invalid signature format: expected Uint8Array, got ${typeof signatureBytes}`);
555
+ }
556
+ // Convert to EcdsaSignature
557
+ if (chainName === 'EVM') {
558
+ const ecdsaSignature = node.EcdsaSignature.fromBuffer(signatureBytes);
559
+ return ecdsaSignature;
560
+ } else {
561
+ return signatureBytes;
562
+ }
563
+ } catch (error) {
564
+ this.logger.error('Error signing message with forward MPC client', {
565
+ error,
566
+ environmentId: this.environmentId,
567
+ dynamicRequestId
568
+ });
569
+ throw error;
570
+ }
571
+ }
572
+ async sign({ accountAddress, externalServerKeyShares, message, chainName, password = undefined, isFormatted = false, context, onError }) {
573
+ try {
574
+ await this.verifyPassword({
575
+ accountAddress,
576
+ password,
577
+ walletOperation: core.WalletOperation.SIGN_MESSAGE
578
+ });
579
+ const wallet = await this.getWallet({
580
+ accountAddress,
581
+ walletOperation: core.WalletOperation.SIGN_MESSAGE,
582
+ password
583
+ });
584
+ externalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : wallet.externalServerKeyShares;
585
+ if (!externalServerKeyShares) {
586
+ throw new Error('External server key shares are required to sign a message');
587
+ }
588
+ // Perform the dynamic server sign
589
+ const data = await this.dynamicServerSign({
590
+ walletId: wallet.walletId,
591
+ message,
592
+ isFormatted,
593
+ context,
594
+ onError
595
+ });
596
+ const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
597
+ // Perform the external server sign and return the signature
598
+ if (this.forwardMPCEnabled) {
599
+ const formattedMessage = isFormatted ? new node.MessageHash(message) : formatMessage(chainName, message);
600
+ const signature = await this.forwardMPCClientSign({
601
+ chainName,
602
+ message,
603
+ roomId: data.roomId,
604
+ keyShare: externalServerKeyShares[0],
605
+ derivationPath,
606
+ formattedMessage,
607
+ dynamicRequestId: uuid.v4(),
608
+ isFormatted
609
+ });
610
+ return signature;
611
+ } else {
612
+ const signature = await this.externalServerSign({
613
+ chainName,
614
+ message,
615
+ roomId: data.roomId,
616
+ keyShare: externalServerKeyShares[0],
617
+ derivationPath,
618
+ isFormatted
619
+ });
620
+ return signature;
621
+ }
622
+ } catch (error) {
623
+ this.logger.error('Error in sign', error);
624
+ throw error;
625
+ }
464
626
  }
465
- async refreshWalletAccountShares({ accountAddress, chainName, password = undefined }) {
627
+ async refreshWalletAccountShares({ accountAddress, chainName, password = undefined, externalServerKeyShares, backUpToClientShareService = false }) {
466
628
  this.ensureApiClientAuthenticated();
467
629
  await this.verifyPassword({
468
630
  accountAddress,
@@ -483,14 +645,19 @@ class DynamicWalletClient {
483
645
  walletId: wallet.walletId
484
646
  });
485
647
  const roomId = data.roomId;
486
- const refreshResults = await Promise.all(wallet.externalServerKeyShares.map((serverKeyShare)=>mpcSigner.refresh(roomId, serverKeyShare)));
648
+ externalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : wallet.externalServerKeyShares;
649
+ if (!externalServerKeyShares) {
650
+ throw new Error('External server key shares are required to refresh');
651
+ }
652
+ const refreshResults = await Promise.all(externalServerKeyShares.map((serverKeyShare)=>mpcSigner.refresh(roomId, serverKeyShare)));
487
653
  this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
488
654
  externalServerKeyShares: refreshResults,
489
655
  externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
490
656
  });
491
657
  await this.storeEncryptedBackupByWallet({
492
658
  accountAddress,
493
- password: password != null ? password : this.environmentId
659
+ password: password != null ? password : this.environmentId,
660
+ backUpToClientShareService
494
661
  });
495
662
  return refreshResults;
496
663
  }
@@ -543,7 +710,7 @@ class DynamicWalletClient {
543
710
  existingExternalServerKeyShares
544
711
  };
545
712
  }
546
- async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined }) {
713
+ async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, externalServerKeyShares, backUpToClientShareService = false }) {
547
714
  this.ensureApiClientAuthenticated();
548
715
  await this.verifyPassword({
549
716
  accountAddress,
@@ -560,9 +727,15 @@ class DynamicWalletClient {
560
727
  shareCount: existingExternalServerShareCount,
561
728
  password
562
729
  });
730
+ externalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : wallet.externalServerKeyShares;
731
+ if (!externalServerKeyShares) {
732
+ throw new Error('External server key shares are required to reshare');
733
+ }
563
734
  const { newExternalServerInitKeygenResults, newExternalServerKeygenIds, existingExternalServerKeygenIds, existingExternalServerKeyShares } = await this.reshareStrategy({
564
735
  chainName,
565
- wallet,
736
+ wallet: _extends({}, wallet, {
737
+ externalServerKeyShares
738
+ }),
566
739
  oldThresholdSignatureScheme,
567
740
  newThresholdSignatureScheme
568
741
  });
@@ -600,11 +773,12 @@ class DynamicWalletClient {
600
773
  });
601
774
  await this.storeEncryptedBackupByWallet({
602
775
  accountAddress,
603
- password
776
+ password,
777
+ backUpToClientShareService
604
778
  });
605
779
  return reshareResults;
606
780
  }
607
- async exportKey({ accountAddress, chainName, password = undefined }) {
781
+ async exportKey({ accountAddress, chainName, password = undefined, externalServerKeyShares }) {
608
782
  this.ensureApiClientAuthenticated();
609
783
  await this.verifyPassword({
610
784
  accountAddress,
@@ -616,19 +790,23 @@ class DynamicWalletClient {
616
790
  password,
617
791
  walletOperation: core.WalletOperation.EXPORT_PRIVATE_KEY
618
792
  });
793
+ externalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : wallet.externalServerKeyShares;
794
+ if (!externalServerKeyShares) {
795
+ throw new Error('External server key shares are required to export a private key');
796
+ }
619
797
  const mpcSigner = getMPCSigner({
620
798
  chainName,
621
799
  baseRelayUrl: this.baseMPCRelayApiUrl
622
800
  });
623
801
  const exportId = await this.getExportId({
624
802
  chainName,
625
- serverKeyShare: wallet.externalServerKeyShares[0]
803
+ serverKeyShare: externalServerKeyShares[0]
626
804
  });
627
805
  const data = await this.apiClient.exportKey({
628
806
  walletId: wallet.walletId,
629
807
  exportId
630
808
  });
631
- const keyExportRaw = await mpcSigner.exportFullPrivateKey(data.roomId, wallet.externalServerKeyShares[0], exportId);
809
+ const keyExportRaw = await mpcSigner.exportFullPrivateKey(data.roomId, externalServerKeyShares[0], exportId);
632
810
  if (!keyExportRaw) {
633
811
  throw new Error('Error exporting private key');
634
812
  }
@@ -636,7 +814,7 @@ class DynamicWalletClient {
636
814
  let derivedPrivateKey;
637
815
  if (mpcSigner instanceof node.Ecdsa) {
638
816
  derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, derivationPath);
639
- } else if (mpcSigner instanceof node.Ed25519) {
817
+ } else if (mpcSigner instanceof node.ExportableEd25519) {
640
818
  derivedPrivateKey = keyExportRaw;
641
819
  } else if (mpcSigner instanceof node.BIP340) {
642
820
  derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, derivationPath);
@@ -655,7 +833,7 @@ class DynamicWalletClient {
655
833
  baseRelayUrl: this.baseMPCRelayApiUrl
656
834
  });
657
835
  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);
836
+ return mpcSigner instanceof node.Ecdsa ? new node.EcdsaKeygenResult(keyShare.pubkey, keyShare.secretShare) : mpcSigner instanceof node.ExportableEd25519 ? new node.ExportableEd25519KeygenResult(keyShare.pubkey, keyShare.secretShare) : new node.BIP340KeygenResult(keyShare.pubkey, keyShare.secretShare);
659
837
  });
660
838
  const keyExportRaw = await mpcSigner.offlineExportFullPrivateKey(walletKeyShares);
661
839
  if (!keyExportRaw) {
@@ -666,7 +844,7 @@ class DynamicWalletClient {
666
844
  let derivedPrivateKey;
667
845
  if (mpcSigner instanceof node.Ecdsa) {
668
846
  derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
669
- } else if (mpcSigner instanceof node.Ed25519) {
847
+ } else if (mpcSigner instanceof node.ExportableEd25519) {
670
848
  derivedPrivateKey = keyExportRaw;
671
849
  } else if (mpcSigner instanceof node.BIP340) {
672
850
  derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
@@ -689,11 +867,28 @@ class DynamicWalletClient {
689
867
  const serializedEncryptedKeyShare = Buffer.from(JSON.stringify(encryptedKeyShare)).toString('base64');
690
868
  return serializedEncryptedKeyShare;
691
869
  }
692
- async storeEncryptedBackupByWallet({ accountAddress, externalServerKeyShares = undefined, password = undefined }) {
870
+ async ensureCeremonyCompletionBeforeBackup({ accountAddress }) {
871
+ let retries = 0;
872
+ const maxRetries = 3;
873
+ while((!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) && retries < maxRetries){
874
+ await new Promise((resolve)=>setTimeout(resolve, 1000)); // Wait 1 second
875
+ retries++;
876
+ }
877
+ if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
878
+ throw new Error('Ceremony completion timeout');
879
+ }
880
+ }
881
+ async storeEncryptedBackupByWallet({ accountAddress, externalServerKeyShares = undefined, password = undefined, backUpToClientShareService }) {
693
882
  this.ensureApiClientAuthenticated();
883
+ //add retry logic for ceremony completion to prevent race condition
884
+ await this.ensureCeremonyCompletionBeforeBackup({
885
+ accountAddress
886
+ });
887
+ const dynamicRequestId = uuid.v4();
694
888
  try {
695
889
  const keySharesToBackup = externalServerKeyShares != null ? externalServerKeyShares : await this.getExternalServerKeyShares({
696
- accountAddress
890
+ accountAddress,
891
+ password
697
892
  });
698
893
  if (!keySharesToBackup || keySharesToBackup.length === 0) {
699
894
  throw new Error(`Key shares not found for accountAddress: ${accountAddress}`);
@@ -705,51 +900,92 @@ class DynamicWalletClient {
705
900
  if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
706
901
  throw new Error(`WalletId not found for accountAddress: ${accountAddress}`);
707
902
  }
708
- const data = await this.apiClient.storeEncryptedBackupByWallet({
903
+ const passwordEncryptedFlag = Boolean(password) && password !== this.environmentId;
904
+ const locations = [];
905
+ if (backUpToClientShareService) {
906
+ const data = await this.apiClient.storeEncryptedBackupByWallet({
907
+ walletId: this.walletMap[accountAddress].walletId,
908
+ encryptedKeyShares: encryptedKeyShares,
909
+ passwordEncrypted: passwordEncryptedFlag,
910
+ encryptionVersion: ENCRYPTION_VERSION_CURRENT,
911
+ requiresSignedSessionId: false,
912
+ dynamicRequestId
913
+ });
914
+ locations.push({
915
+ location: core.BackupLocation.DYNAMIC,
916
+ externalKeyShareId: data.keyShareIds[0],
917
+ passwordEncrypted: passwordEncryptedFlag
918
+ });
919
+ } else {
920
+ locations.push({
921
+ location: core.BackupLocation.EXTERNAL
922
+ });
923
+ }
924
+ const backupData = await this.apiClient.markKeySharesAsBackedUp({
709
925
  walletId: this.walletMap[accountAddress].walletId,
710
- encryptedKeyShares,
711
- passwordEncrypted: Boolean(password) && password !== this.environmentId
926
+ locations,
927
+ dynamicRequestId
928
+ });
929
+ const updatedBackupInfo = getExternalServerKeyShareBackupInfo({
930
+ walletProperties: {
931
+ derivationPath: this.walletMap[accountAddress].derivationPath,
932
+ keyShares: backupData.locationsWithKeyShares.map((ks)=>({
933
+ id: ks.keyShareId,
934
+ backupLocation: ks.location,
935
+ externalKeyShareId: ks.externalKeyShareId,
936
+ passwordEncrypted: passwordEncryptedFlag
937
+ })),
938
+ thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme
939
+ }
712
940
  });
713
941
  this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
714
- externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
715
- walletProperties: {
716
- derivationPath: this.walletMap[accountAddress].derivationPath,
717
- keyShares: data.keyShares,
718
- thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme
719
- }
720
- })
942
+ externalServerKeySharesBackupInfo: updatedBackupInfo
721
943
  });
722
- return data;
944
+ return encryptedKeyShares;
723
945
  } catch (error) {
724
- this.logger.error('Error in storeEncryptedBackupByWallet:', error);
946
+ this.logger.error('Error in storeEncryptedBackupByWallet:', {
947
+ accountAddress,
948
+ error,
949
+ dynamicRequestId
950
+ });
725
951
  throw error;
726
952
  }
727
953
  }
728
- async storeEncryptedBackupByWalletWithRetry({ accountAddress, externalServerKeyShares, password }) {
954
+ async storeEncryptedBackupByWalletWithRetry({ accountAddress, externalServerKeyShares, password, backUpToClientShareService }) {
729
955
  await retryPromise(()=>this.storeEncryptedBackupByWallet({
730
956
  accountAddress,
731
957
  externalServerKeyShares,
732
- password
958
+ password,
959
+ backUpToClientShareService
733
960
  }), {
734
961
  operationName: 'store encrypted backup',
735
962
  logContext: {
736
- walletAddress: accountAddress,
737
- keyShares: externalServerKeyShares == null ? void 0 : externalServerKeyShares.map((keyShare)=>this.encryptKeyShare({
738
- keyShare,
739
- password
740
- }))
963
+ walletAddress: accountAddress
741
964
  }
742
965
  });
743
966
  }
744
967
  async getExternalServerKeyShares({ accountAddress, password }) {
968
+ var _wallet_externalServerKeySharesBackupInfo_backups, _wallet_externalServerKeySharesBackupInfo;
745
969
  const wallet = await this.getWallet({
746
970
  accountAddress,
747
971
  password,
748
972
  walletOperation: core.WalletOperation.REACH_THRESHOLD
749
973
  });
750
- return wallet.externalServerKeyShares;
974
+ // Check if the wallet has a dynamic backup and derive password encryption status from the first dynamic share
975
+ const dynamicBackups = (wallet == null ? void 0 : (_wallet_externalServerKeySharesBackupInfo = wallet.externalServerKeySharesBackupInfo) == null ? void 0 : (_wallet_externalServerKeySharesBackupInfo_backups = _wallet_externalServerKeySharesBackupInfo.backups) == null ? void 0 : _wallet_externalServerKeySharesBackupInfo_backups.dynamic) || [];
976
+ const passwordEncrypted = dynamicBackups.length > 0 ? Boolean(dynamicBackups[0].passwordEncrypted) : false;
977
+ if (passwordEncrypted && !password) {
978
+ throw new Error('Password is required for decryption but not provided. This backup was encrypted with a password.');
979
+ }
980
+ // recover the shares
981
+ const recoveredShares = await this.recoverEncryptedBackupByWallet({
982
+ accountAddress,
983
+ password,
984
+ walletOperation: core.WalletOperation.REACH_THRESHOLD
985
+ });
986
+ return recoveredShares;
751
987
  }
752
- async updatePassword({ accountAddress, existingPassword, newPassword }) {
988
+ async updatePassword({ accountAddress, existingPassword, newPassword, backUpToClientShareService }) {
753
989
  await this.getWallet({
754
990
  accountAddress,
755
991
  password: existingPassword,
@@ -757,7 +993,8 @@ class DynamicWalletClient {
757
993
  });
758
994
  await this.storeEncryptedBackupByWallet({
759
995
  accountAddress,
760
- password: newPassword
996
+ password: newPassword,
997
+ backUpToClientShareService
761
998
  });
762
999
  }
763
1000
  async decryptKeyShare({ keyShare, password }) {
@@ -788,17 +1025,57 @@ class DynamicWalletClient {
788
1025
  if (shareCount !== undefined) {
789
1026
  requiredShareCount = shareCount;
790
1027
  }
791
- const dynamicShares = backups[core.BackupLocation.DYNAMIC].slice(0, requiredShareCount);
1028
+ const dynamicShares = (backups[core.BackupLocation.DYNAMIC] || []).slice(0, requiredShareCount);
1029
+ const externalShares = (backups[core.BackupLocation.EXTERNAL] || []).slice(0, requiredShareCount);
1030
+ // If we have DYNAMIC shares, use those; otherwise use EXTERNAL shares
1031
+ const sharesToUse = dynamicShares.length > 0 ? dynamicShares : externalShares;
1032
+ const backupLocation = dynamicShares.length > 0 ? core.BackupLocation.DYNAMIC : core.BackupLocation.EXTERNAL;
792
1033
  return {
793
1034
  shares: {
794
- [core.BackupLocation.DYNAMIC]: dynamicShares
1035
+ [backupLocation]: sharesToUse.map((ks)=>{
1036
+ var _ks_externalKeyShareId, _ref;
1037
+ return (_ref = (_ks_externalKeyShareId = ks.externalKeyShareId) != null ? _ks_externalKeyShareId : ks.keyShareId) != null ? _ref : '';
1038
+ })
795
1039
  },
796
1040
  requiredShareCount
797
1041
  };
798
1042
  }
1043
+ /**
1044
+ * Attempts to recover key shares from backup if they are not provided.
1045
+ * The recovered shares will be stored in the wallet map for use in signing operations.
1046
+ * @param accountAddress - The account address to recover shares for
1047
+ * @param password - The password to decrypt the shares
1048
+ * @param walletOperation - The wallet operation being performed
1049
+ * @param externalServerKeyShares - The provided key shares (if any)
1050
+ * @param errorMessage - The error message to throw if recovery fails
1051
+ * @throws Error if recovery is needed but fails
1052
+ */ async ensureKeySharesRecovered({ accountAddress, password, walletOperation, externalServerKeyShares, errorMessage }) {
1053
+ if (!externalServerKeyShares || externalServerKeyShares.length === 0) {
1054
+ // attempt to recover dynamic keyshares if no key shares are provided
1055
+ // the shares will be used for signing in the node SDK if successful
1056
+ const recoveredShares = await this.recoverEncryptedBackupByWallet({
1057
+ accountAddress,
1058
+ password,
1059
+ walletOperation,
1060
+ storeRecoveredShares: true
1061
+ });
1062
+ // If recovery returned empty and no shares were provided, throw error
1063
+ if (!recoveredShares || recoveredShares.length === 0) {
1064
+ throw new Error(errorMessage);
1065
+ }
1066
+ }
1067
+ }
799
1068
  async recoverEncryptedBackupByWallet({ accountAddress, password, walletOperation, shareCount = undefined, storeRecoveredShares = true }) {
1069
+ var _wallet_externalServerKeySharesBackupInfo;
800
1070
  this.ensureApiClientAuthenticated();
801
- const wallet = this.walletMap[accountAddress];
1071
+ let wallet = this.walletMap[accountAddress];
1072
+ if (!wallet) {
1073
+ const fetchedWallet = await this.getWalletByAddress(accountAddress);
1074
+ if (!fetchedWallet) {
1075
+ throw new Error(`Wallet not found for address 1: ${accountAddress}`);
1076
+ }
1077
+ wallet = fetchedWallet;
1078
+ }
802
1079
  this.logger.debug(`recoverEncryptedBackupByWallet wallet: ${walletOperation}`, wallet);
803
1080
  const { shares } = this.recoverStrategy({
804
1081
  externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
@@ -806,12 +1083,30 @@ class DynamicWalletClient {
806
1083
  walletOperation,
807
1084
  shareCount
808
1085
  });
809
- const { dynamic: dynamicKeyShareIds } = shares;
810
- const data = await this.apiClient.recoverEncryptedBackupByWallet({
811
- walletId: wallet.walletId,
812
- keyShareIds: dynamicKeyShareIds
813
- });
1086
+ // Get the key share IDs from whichever backup location has shares
1087
+ const dynamicKeyShareIds = shares[core.BackupLocation.DYNAMIC] || [];
1088
+ const externalKeyShareIds = shares[core.BackupLocation.EXTERNAL] || [];
1089
+ // Only attempt recovery if we have DYNAMIC shares (the API doesn't support EXTERNAL shares)
1090
+ let data;
1091
+ if (dynamicKeyShareIds.length > 0) {
1092
+ data = await this.apiClient.recoverEncryptedBackupByWallet({
1093
+ walletId: wallet.walletId,
1094
+ keyShareIds: dynamicKeyShareIds,
1095
+ requiresSignedSessionId: false
1096
+ });
1097
+ } else if (externalKeyShareIds.length > 0) {
1098
+ this.logger.debug('Skipping recovery - only EXTERNAL shares available (backUpToClientShareService: false)');
1099
+ return []; // Return empty array since we can't recover EXTERNAL shares via API
1100
+ } else {
1101
+ this.logger.debug('No shares available for recovery');
1102
+ return []; // Return empty array if no shares are available
1103
+ }
814
1104
  const dynamicKeyShares = data.keyShares.filter((keyShare)=>keyShare.encryptedAccountCredential !== null && keyShare.backupLocation === core.BackupLocation.DYNAMIC);
1105
+ var _wallet_externalServerKeySharesBackupInfo_passwordEncrypted;
1106
+ const isPasswordEncrypted = (_wallet_externalServerKeySharesBackupInfo_passwordEncrypted = (_wallet_externalServerKeySharesBackupInfo = wallet.externalServerKeySharesBackupInfo) == null ? void 0 : _wallet_externalServerKeySharesBackupInfo.passwordEncrypted) != null ? _wallet_externalServerKeySharesBackupInfo_passwordEncrypted : false;
1107
+ if (isPasswordEncrypted && !password) {
1108
+ throw new Error('Password is required for decryption but not provided. This backup was encrypted with a password.');
1109
+ }
815
1110
  const decryptedKeyShares = await Promise.all(dynamicKeyShares.map((keyShare)=>this.decryptKeyShare({
816
1111
  keyShare: keyShare.encryptedAccountCredential,
817
1112
  password: password != null ? password : this.environmentId
@@ -841,6 +1136,7 @@ class DynamicWalletClient {
841
1136
  * @param walletOperation - The wallet operation that determines required fields
842
1137
  * @returns boolean indicating if wallet needs to be re-fetched and restored from server
843
1138
  */ async checkWalletFields({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD, shareCount }) {
1139
+ var _existingWallet_externalServerKeyShares;
844
1140
  let keyshareCheck = false;
845
1141
  let walletCheck = false;
846
1142
  let thresholdSignatureSchemeCheck = false;
@@ -860,7 +1156,7 @@ class DynamicWalletClient {
860
1156
  }
861
1157
  // check if wallet already exists with sufficient keyshares
862
1158
  if (existingWallet) {
863
- var _existingWallet_externalServerKeyShares;
1159
+ var _existingWallet_externalServerKeyShares1;
864
1160
  const { shares } = this.recoverStrategy({
865
1161
  externalServerKeySharesBackupInfo: existingWallet.externalServerKeySharesBackupInfo || {
866
1162
  backups: getExternalServerKeyShareBackupInfo()
@@ -870,11 +1166,35 @@ class DynamicWalletClient {
870
1166
  shareCount
871
1167
  });
872
1168
  const { dynamic: requiredDynamicKeyShareIds = [] } = shares;
873
- if (requiredDynamicKeyShareIds.length <= (((_existingWallet_externalServerKeyShares = existingWallet.externalServerKeyShares) == null ? void 0 : _existingWallet_externalServerKeyShares.length) || 0)) {
1169
+ const { external: requiredExternalKeyShareIds = [] } = shares;
1170
+ // Check if we have enough shares from any backup location
1171
+ const totalRequiredShares = requiredDynamicKeyShareIds.length + requiredExternalKeyShareIds.length;
1172
+ // Check if we have the required shares either loaded OR available in backup
1173
+ const hasLoadedShares = totalRequiredShares <= (((_existingWallet_externalServerKeyShares1 = existingWallet.externalServerKeyShares) == null ? void 0 : _existingWallet_externalServerKeyShares1.length) || 0);
1174
+ // Check if backup contains the specific required share IDs
1175
+ const hasBackupShares = existingWallet.externalServerKeySharesBackupInfo && (()=>{
1176
+ const backupShares = existingWallet.externalServerKeySharesBackupInfo.backups.dynamic;
1177
+ const allRequiredIds = [
1178
+ ...requiredDynamicKeyShareIds,
1179
+ ...requiredExternalKeyShareIds
1180
+ ];
1181
+ return allRequiredIds.every((requiredId)=>backupShares.some((backupShare)=>backupShare.externalKeyShareId === requiredId || backupShare.keyShareId === requiredId));
1182
+ })();
1183
+ if (hasLoadedShares || hasBackupShares) {
874
1184
  keyshareCheck = true;
875
1185
  }
876
1186
  }
877
- return walletCheck && thresholdSignatureSchemeCheck && keyshareCheck && derivationPathCheck;
1187
+ const result = walletCheck && thresholdSignatureSchemeCheck && keyshareCheck && derivationPathCheck;
1188
+ this.logger.debug('Wallet checks:', {
1189
+ walletCheck,
1190
+ thresholdSignatureSchemeCheck,
1191
+ keyshareCheck,
1192
+ derivationPathCheck,
1193
+ existingWallet: !!existingWallet,
1194
+ keySharesLength: existingWallet == null ? void 0 : (_existingWallet_externalServerKeyShares = existingWallet.externalServerKeyShares) == null ? void 0 : _existingWallet_externalServerKeyShares.length,
1195
+ result
1196
+ });
1197
+ return result;
878
1198
  }
879
1199
  /**
880
1200
  * verifyPassword attempts to recover and decrypt a single client key share using the provided password.
@@ -900,8 +1220,10 @@ class DynamicWalletClient {
900
1220
  accountAddress
901
1221
  });
902
1222
  const { dynamic: dynamicKeyShareIds = [] } = backups;
903
- if (!dynamicKeyShareIds || dynamicKeyShareIds.length === 0) {
904
- throw new Error('No dynamic key shares found');
1223
+ const { external: externalKeyShareIds = [] } = backups;
1224
+ // Check if we have any shares available (DYNAMIC or EXTERNAL)
1225
+ if (dynamicKeyShareIds.length === 0 && externalKeyShareIds.length === 0) {
1226
+ throw new Error('No key shares found');
905
1227
  }
906
1228
  try {
907
1229
  await this.recoverEncryptedBackupByWallet({
@@ -946,88 +1268,164 @@ class DynamicWalletClient {
946
1268
  if (walletOperation === core.WalletOperation.REACH_ALL_PARTIES || walletOperation === core.WalletOperation.REFRESH || walletOperation === core.WalletOperation.RESHARE) {
947
1269
  return true;
948
1270
  }
949
- const { requiredShareCount } = this.recoverStrategy({
1271
+ const { shares, requiredShareCount } = this.recoverStrategy({
950
1272
  externalServerKeySharesBackupInfo,
951
1273
  thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme,
952
1274
  walletOperation
953
1275
  });
954
- if (externalServerKeyShares.length >= requiredShareCount) {
1276
+ const dynamicKeyShareIds = shares[core.BackupLocation.DYNAMIC] || [];
1277
+ const externalKeyShareIds = shares[core.BackupLocation.EXTERNAL] || [];
1278
+ // Check if we have enough shares from either location
1279
+ const totalAvailableShares = externalServerKeyShares.length + dynamicKeyShareIds.length + externalKeyShareIds.length;
1280
+ if (totalAvailableShares >= requiredShareCount) {
955
1281
  return false;
956
1282
  }
957
1283
  return true;
958
1284
  }
959
1285
  async getWalletExternalServerKeyShareBackupInfo({ accountAddress }) {
960
- var _this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC, _this_walletMap_accountAddress_externalServerKeySharesBackupInfo_backups, _this_walletMap_accountAddress_externalServerKeySharesBackupInfo, _this_walletMap_accountAddress, _user_verifiedCredentials;
1286
+ var _wallet_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC, _wallet_externalServerKeySharesBackupInfo_backups, _wallet_externalServerKeySharesBackupInfo, _user_verifiedCredentials;
961
1287
  this.ensureApiClientAuthenticated();
1288
+ let wallet = this.walletMap[accountAddress];
1289
+ if (!wallet) {
1290
+ const fetchedWallet = await this.getWalletByAddress(accountAddress);
1291
+ if (!fetchedWallet) {
1292
+ throw new Error(`Wallet not found for address 2: ${accountAddress}`);
1293
+ }
1294
+ wallet = fetchedWallet;
1295
+ }
962
1296
  // Return existing backup info if it exists
963
- 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) {
964
- return this.walletMap[accountAddress].externalServerKeySharesBackupInfo;
1297
+ if (((_wallet_externalServerKeySharesBackupInfo = wallet.externalServerKeySharesBackupInfo) == null ? void 0 : (_wallet_externalServerKeySharesBackupInfo_backups = _wallet_externalServerKeySharesBackupInfo.backups) == null ? void 0 : (_wallet_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC = _wallet_externalServerKeySharesBackupInfo_backups[core.BackupLocation.DYNAMIC]) == null ? void 0 : _wallet_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC.length) > 0) {
1298
+ return wallet.externalServerKeySharesBackupInfo;
965
1299
  }
966
1300
  // Get backup info from server
967
- const user = await this.apiClient.getUser();
968
- const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
1301
+ const user = await this.apiClient.getUser(uuid.v4());
1302
+ const walletData = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
969
1303
  return getExternalServerKeyShareBackupInfo({
970
- walletProperties: wallet == null ? void 0 : wallet.walletProperties
1304
+ walletProperties: walletData == null ? void 0 : walletData.walletProperties
971
1305
  });
972
1306
  }
973
1307
  async getWallet({ accountAddress, walletOperation = core.WalletOperation.NO_OPERATION, shareCount = undefined, password = undefined }) {
974
- var _user_verifiedCredentials;
975
- this.ensureApiClientAuthenticated();
976
- const existingWalletCheck = await this.checkWalletFields({
977
- accountAddress,
978
- walletOperation,
979
- shareCount
980
- });
981
- if (existingWalletCheck) {
982
- this.logger.debug(`Wallet ${accountAddress} already exists`);
983
- return this.walletMap[accountAddress];
984
- }
985
- //todo: Question - why don't we just call getWallets here? so then all are preloaded
986
- // Fetch and restore wallet from server
987
- const user = await this.apiClient.getUser();
988
- const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
989
- this.logger.debug('Restoring wallet', wallet);
990
- const walletProperties = wallet.walletProperties;
991
- this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
992
- walletId: wallet.id,
993
- chainName: wallet.chainName,
994
- accountAddress,
995
- thresholdSignatureScheme: walletProperties.thresholdSignatureScheme,
996
- derivationPath: walletProperties.derivationPath,
997
- externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
998
- walletProperties
999
- })
1000
- });
1001
- if (walletOperation !== core.WalletOperation.NO_OPERATION && await this.requiresRestoreBackupSharesForOperation({
1002
- accountAddress,
1003
- walletOperation
1004
- })) {
1005
- const decryptedKeyShares = await this.recoverEncryptedBackupByWallet({
1308
+ try {
1309
+ this.ensureApiClientAuthenticated();
1310
+ const existingWalletCheck = await this.checkWalletFields({
1006
1311
  accountAddress,
1007
- password: password != null ? password : this.environmentId,
1008
- walletOperation: walletOperation,
1312
+ walletOperation,
1009
1313
  shareCount
1010
1314
  });
1011
- this.logger.debug('Recovered backup', decryptedKeyShares);
1315
+ if (existingWalletCheck) {
1316
+ this.logger.debug(`Wallet ${accountAddress} already exists`);
1317
+ return this.walletMap[accountAddress];
1318
+ }
1319
+ const wallet = await this.getWalletByAddress(accountAddress);
1320
+ if (!wallet) {
1321
+ throw new Error(`Wallet not found for address 3: ${accountAddress}`);
1322
+ }
1323
+ this.logger.debug('Restoring wallet', wallet);
1324
+ // The wallet is already processed, so we can use it directly
1325
+ this.walletMap[accountAddress] = wallet;
1326
+ if (walletOperation !== core.WalletOperation.NO_OPERATION && await this.requiresRestoreBackupSharesForOperation({
1327
+ accountAddress,
1328
+ walletOperation
1329
+ })) {
1330
+ const decryptedKeyShares = await this.recoverEncryptedBackupByWallet({
1331
+ accountAddress,
1332
+ password: password != null ? password : this.environmentId,
1333
+ walletOperation: walletOperation,
1334
+ shareCount
1335
+ });
1336
+ this.logger.debug('[DynamicWaasWalletClient] Recovered backup', decryptedKeyShares);
1337
+ }
1338
+ // externalServerKeyShares
1339
+ const walletCount = Object.keys(this.walletMap).length;
1340
+ if (walletCount === 0) {
1341
+ throw new Error('No wallets found');
1342
+ }
1343
+ // Return the only wallet if there's just one
1344
+ if (walletCount === 1) {
1345
+ return Object.values(this.walletMap)[0];
1346
+ }
1347
+ return this.walletMap[accountAddress];
1348
+ } catch (error) {
1349
+ this.logger.error('Error in getWallet', error);
1350
+ throw error;
1012
1351
  }
1013
- const walletCount = Object.keys(this.walletMap).length;
1014
- if (walletCount === 0) {
1015
- throw new Error('No wallets found');
1352
+ }
1353
+ /**
1354
+ * Get a single wallet by address
1355
+ * First tries the efficient getWaasWalletByAddress endpoint, falls back to getUser() if not available
1356
+ */ async getWalletByAddress(accountAddress) {
1357
+ // Return cached wallet if available
1358
+ if (this.walletMap[accountAddress]) {
1359
+ return this.walletMap[accountAddress];
1016
1360
  }
1017
- // Return the only wallet if there's just one
1018
- if (walletCount === 1) {
1019
- return Object.values(this.walletMap)[0];
1361
+ this.ensureApiClientAuthenticated();
1362
+ // Try getting single wallet by address first
1363
+ try {
1364
+ var _walletResponse_wallet;
1365
+ const walletResponse = await this.apiClient.getWaasWalletByAddress({
1366
+ walletAddress: accountAddress
1367
+ });
1368
+ const walletProperties = {
1369
+ walletId: walletResponse.wallet.walletId,
1370
+ chainName: walletResponse.wallet.chainName,
1371
+ accountAddress: walletResponse.wallet.accountAddress,
1372
+ externalServerKeyShares: [],
1373
+ derivationPath: walletResponse.wallet.derivationPath,
1374
+ thresholdSignatureScheme: walletResponse.wallet.thresholdSignatureScheme,
1375
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
1376
+ walletProperties: {
1377
+ // @ts-expect-error TODO: update response to get key shares
1378
+ keyShares: ((_walletResponse_wallet = walletResponse.wallet) == null ? void 0 : _walletResponse_wallet.keyShares) || [],
1379
+ thresholdSignatureScheme: walletResponse.wallet.thresholdSignatureScheme,
1380
+ derivationPath: walletResponse.wallet.derivationPath
1381
+ }
1382
+ })
1383
+ };
1384
+ // Cache the wallet
1385
+ this.walletMap[accountAddress] = walletProperties;
1386
+ return walletProperties;
1387
+ } catch (error) {
1388
+ var _error_response;
1389
+ // If the new endpoint doesn't exist (404 or not implemented), fall back to getUser()
1390
+ if ((error == null ? void 0 : (_error_response = error.response) == null ? void 0 : _error_response.status) === 404 || (error == null ? void 0 : error.code) === 'ERR_BAD_REQUEST') {
1391
+ var _user_verifiedCredentials, _wallet_walletProperties, _wallet_walletProperties1;
1392
+ this.logger.debug('getWaasWalletByAddress endpoint not available, falling back to getUser()');
1393
+ // Fallback to getUser() approach
1394
+ const user = await this.apiClient.getUser(uuid.v4());
1395
+ const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.walletName === 'dynamicwaas' && vc.address.toLowerCase() === accountAddress.toLowerCase());
1396
+ if (!wallet) {
1397
+ return null;
1398
+ }
1399
+ var _wallet_walletProperties_derivationPath;
1400
+ const walletProperties = {
1401
+ walletId: wallet.id,
1402
+ chainName: wallet.chain,
1403
+ accountAddress: wallet.address,
1404
+ externalServerKeyShares: [],
1405
+ derivationPath: (_wallet_walletProperties_derivationPath = (_wallet_walletProperties = wallet.walletProperties) == null ? void 0 : _wallet_walletProperties.derivationPath) != null ? _wallet_walletProperties_derivationPath : undefined,
1406
+ thresholdSignatureScheme: (_wallet_walletProperties1 = wallet.walletProperties) == null ? void 0 : _wallet_walletProperties1.thresholdSignatureScheme,
1407
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
1408
+ walletProperties: wallet.walletProperties || {}
1409
+ })
1410
+ };
1411
+ // Cache the wallet
1412
+ this.walletMap[accountAddress] = walletProperties;
1413
+ return walletProperties;
1414
+ }
1415
+ throw error;
1020
1416
  }
1021
- return this.walletMap[accountAddress];
1022
1417
  }
1023
- async getWallets() {
1418
+ /**
1419
+ * Get all wallets (kept for backward compatibility but now uses lazy loading)
1420
+ * @deprecated Consider using getWalletByAddress for better performance with large wallet counts
1421
+ */ async getWallets() {
1024
1422
  var _user_verifiedCredentials;
1025
1423
  this.ensureApiClientAuthenticated();
1026
- const user = await this.apiClient.getUser();
1424
+ const user = await this.apiClient.getUser(uuid.v4());
1027
1425
  const waasWallets = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.filter((vc)=>vc.walletName === 'dynamicwaas');
1028
1426
  const wallets = waasWallets.map((vc)=>{
1029
- var _this_walletMap_vc_address, _this_walletMap_vc_address1, _vc_walletProperties;
1030
- var _this_walletMap_vc_address_derivationPath;
1427
+ var _this_walletMap_vc_address, _vc_walletProperties, _vc_walletProperties1;
1428
+ var _vc_walletProperties_derivationPath;
1031
1429
  return {
1032
1430
  walletId: vc.id,
1033
1431
  chainName: vc.chain,
@@ -1036,101 +1434,260 @@ class DynamicWalletClient {
1036
1434
  walletProperties: vc.walletProperties || {}
1037
1435
  }),
1038
1436
  externalServerKeyShares: ((_this_walletMap_vc_address = this.walletMap[vc.address]) == null ? void 0 : _this_walletMap_vc_address.externalServerKeyShares) || [],
1039
- 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,
1040
- thresholdSignatureScheme: (_vc_walletProperties = vc.walletProperties) == null ? void 0 : _vc_walletProperties.thresholdSignatureScheme
1437
+ derivationPath: (_vc_walletProperties_derivationPath = (_vc_walletProperties = vc.walletProperties) == null ? void 0 : _vc_walletProperties.derivationPath) != null ? _vc_walletProperties_derivationPath : undefined,
1438
+ thresholdSignatureScheme: (_vc_walletProperties1 = vc.walletProperties) == null ? void 0 : _vc_walletProperties1.thresholdSignatureScheme
1041
1439
  };
1042
1440
  });
1043
1441
  this.walletMap = wallets.reduce((acc, wallet)=>{
1044
- var _acc_accountAddress;
1045
- const accountAddress = wallet.accountAddress;
1046
1442
  acc[wallet.accountAddress] = {
1047
1443
  walletId: wallet.walletId,
1048
1444
  chainName: wallet.chainName,
1049
1445
  accountAddress: wallet.accountAddress,
1050
1446
  externalServerKeyShares: wallet.externalServerKeyShares || [],
1051
1447
  externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
1052
- derivationPath: ((_acc_accountAddress = acc[accountAddress]) == null ? void 0 : _acc_accountAddress.derivationPath) || undefined,
1448
+ derivationPath: wallet.derivationPath,
1053
1449
  thresholdSignatureScheme: wallet.thresholdSignatureScheme
1054
1450
  };
1055
1451
  return acc;
1056
1452
  }, {});
1057
1453
  return wallets;
1058
1454
  }
1059
- constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug }){
1455
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug, forwardMPCClient, enableMPCAccelerator = false }){
1060
1456
  this.logger = logger;
1061
1457
  this.walletMap = {} // todo: store in session storage
1062
1458
  ;
1063
1459
  this.isApiClientAuthenticated = false;
1460
+ this.forwardMPCEnabled = false;
1064
1461
  this.environmentId = environmentId;
1065
1462
  this.baseMPCRelayApiUrl = baseMPCRelayApiUrl;
1066
1463
  this.baseApiUrl = baseApiUrl;
1067
1464
  this.debug = Boolean(debug);
1068
1465
  this.logger.setLogLevel(this.debug ? 'DEBUG' : DEFAULT_LOG_LEVEL);
1466
+ this.forwardMPCEnabled = enableMPCAccelerator || Boolean(forwardMPCClient);
1467
+ // Initialize API client with forwardMPCClient
1468
+ this.apiClient = new core.DynamicApiClient({
1469
+ environmentId,
1470
+ baseApiUrl,
1471
+ forwardMPCClient
1472
+ });
1473
+ if (this.forwardMPCEnabled) {
1474
+ this.logger.info('Initializing ForwardMPC enclave websocket in node client. Environment: ' + this.environmentId);
1475
+ this.initializeForwardMPCClient();
1476
+ }
1069
1477
  }
1070
1478
  }
1071
1479
 
1072
- Object.defineProperty(exports, "BIP340", {
1073
- enumerable: true,
1074
- get: function () { return node.BIP340; }
1075
- });
1076
- Object.defineProperty(exports, "BIP340InitKeygenResult", {
1077
- enumerable: true,
1078
- get: function () { return node.BIP340InitKeygenResult; }
1079
- });
1080
- Object.defineProperty(exports, "BIP340KeygenResult", {
1081
- enumerable: true,
1082
- get: function () { return node.BIP340KeygenResult; }
1083
- });
1084
- Object.defineProperty(exports, "Ecdsa", {
1085
- enumerable: true,
1086
- get: function () { return node.Ecdsa; }
1087
- });
1088
- Object.defineProperty(exports, "EcdsaInitKeygenResult", {
1089
- enumerable: true,
1090
- get: function () { return node.EcdsaInitKeygenResult; }
1091
- });
1092
- Object.defineProperty(exports, "EcdsaKeygenResult", {
1093
- enumerable: true,
1094
- get: function () { return node.EcdsaKeygenResult; }
1095
- });
1096
- Object.defineProperty(exports, "EcdsaPublicKey", {
1097
- enumerable: true,
1098
- get: function () { return node.EcdsaPublicKey; }
1099
- });
1100
- Object.defineProperty(exports, "EcdsaSignature", {
1101
- enumerable: true,
1102
- get: function () { return node.EcdsaSignature; }
1103
- });
1104
- Object.defineProperty(exports, "Ed25519", {
1480
+ const createCore = ({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug = false })=>{
1481
+ const coreLogger = logger;
1482
+ coreLogger.setLogLevel(debug ? 'DEBUG' : DEFAULT_LOG_LEVEL);
1483
+ const createApiClient = (options = {})=>{
1484
+ return new core.DynamicApiClient(_extends({
1485
+ environmentId,
1486
+ baseApiUrl
1487
+ }, options));
1488
+ };
1489
+ return {
1490
+ environmentId,
1491
+ createApiClient,
1492
+ logger: coreLogger,
1493
+ baseMPCRelayApiUrl,
1494
+ baseApiUrl,
1495
+ debug
1496
+ };
1497
+ };
1498
+
1499
+ // Helper function to create API client for delegated operations
1500
+ const createDelegatedApiClient = (client, options = {})=>{
1501
+ return client.createApiClient(options);
1502
+ };
1503
+ // Helper function to create API client with wallet-specific headers
1504
+ const createDelegatedApiClientWithWalletKey = (client, walletApiKey)=>{
1505
+ const apiClient = client.createApiClient();
1506
+ // Add the wallet-specific API key header to all requests from this client
1507
+ apiClient.apiClient.defaults.headers['x-dyn-wallet-api-key'] = walletApiKey;
1508
+ return apiClient;
1509
+ };
1510
+ const createDelegatedWalletClient = ({ environmentId, baseApiUrl, baseMPCRelayApiUrl, apiKey, debug = false })=>{
1511
+ const core = createCore({
1512
+ environmentId,
1513
+ baseApiUrl,
1514
+ baseMPCRelayApiUrl,
1515
+ debug
1516
+ });
1517
+ // Store the API key for use in delegated operations
1518
+ core.apiKey = apiKey;
1519
+ const walletMap = {};
1520
+ const client = {
1521
+ get environmentId () {
1522
+ return core.environmentId;
1523
+ },
1524
+ get debug () {
1525
+ return core.debug;
1526
+ },
1527
+ get apiUrl () {
1528
+ var _core_baseApiUrl;
1529
+ return (_core_baseApiUrl = core.baseApiUrl) != null ? _core_baseApiUrl : 'https://app.dynamicauth.com';
1530
+ },
1531
+ get wallets () {
1532
+ return walletMap;
1533
+ },
1534
+ createApiClient: (options = {})=>{
1535
+ return core.createApiClient(_extends({
1536
+ authToken: apiKey
1537
+ }, options));
1538
+ },
1539
+ logger: core.logger,
1540
+ apiKey,
1541
+ baseMPCRelayApiUrl: core.baseMPCRelayApiUrl
1542
+ };
1543
+ return client;
1544
+ };
1545
+
1546
+ const dynamicDelegatedSign = async (client, { walletId, message, isFormatted, walletApiKey, onError, context })=>{
1547
+ const dynamicRequestId = uuid.v4();
1548
+ // Convert message to hex if it's a Uint8Array
1549
+ if (typeof message !== 'string') {
1550
+ message = '0x' + Buffer.from(message).toString('hex');
1551
+ }
1552
+ const apiClient = createDelegatedApiClientWithWalletKey(client, walletApiKey);
1553
+ const data = await apiClient.delegatedSignMessage({
1554
+ walletId,
1555
+ message,
1556
+ isFormatted,
1557
+ dynamicRequestId,
1558
+ onError,
1559
+ context: context ? JSON.parse(JSON.stringify(context, (_key, value)=>typeof value === 'bigint' ? value.toString() : value)) : undefined
1560
+ });
1561
+ return data;
1562
+ };
1563
+ const delegatedSign = async (client, { chainName, message, roomId, keyShare, derivationPath, isFormatted })=>{
1564
+ try {
1565
+ const mpcSigner = getMPCSigner({
1566
+ chainName,
1567
+ baseRelayUrl: client.baseMPCRelayApiUrl
1568
+ });
1569
+ const formattedMessage = isFormatted ? new node.MessageHash(message) : formatMessage(chainName, message);
1570
+ const signature = await mpcSigner.sign(roomId, keyShare, formattedMessage, derivationPath);
1571
+ return signature;
1572
+ } catch (error) {
1573
+ client.logger.error('Error in delegatedSign', error);
1574
+ throw error;
1575
+ }
1576
+ };
1577
+ const delegatedSignMessage = async (client, { walletId, walletApiKey, keyShare, message, chainName, isFormatted = false, onError, context })=>{
1578
+ // Validate required parameters
1579
+ if (!keyShare) {
1580
+ throw new Error('Delegated key share is required to sign a message');
1581
+ }
1582
+ const wallet = await getWallet(client, {
1583
+ walletId
1584
+ });
1585
+ // Perform the dynamic server sign
1586
+ const data = await dynamicDelegatedSign(client, {
1587
+ walletId,
1588
+ walletApiKey,
1589
+ message,
1590
+ isFormatted,
1591
+ onError,
1592
+ context
1593
+ });
1594
+ const derivationPath = wallet.derivationPath && wallet.derivationPath !== '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
1595
+ // Perform the external server sign and return the signature
1596
+ const signature = await delegatedSign(client, {
1597
+ chainName,
1598
+ message,
1599
+ roomId: data.roomId,
1600
+ keyShare,
1601
+ derivationPath,
1602
+ isFormatted
1603
+ });
1604
+ return signature;
1605
+ };
1606
+ // Helper function to get wallet (to be implemented in wallet module)
1607
+ const getWallet = async (client, { walletId })=>{
1608
+ const wallets = client.wallets;
1609
+ // Check if wallet is already cached
1610
+ if (wallets[walletId]) {
1611
+ return wallets[walletId];
1612
+ }
1613
+ // Fetch wallet from API
1614
+ const apiClient = createDelegatedApiClient(client);
1615
+ const { wallet } = await apiClient.getWaasWalletById({
1616
+ walletId
1617
+ });
1618
+ const waasWallet = {
1619
+ walletId,
1620
+ chainName: wallet.chainName,
1621
+ accountAddress: wallet.accountAddress,
1622
+ externalServerKeyShares: [],
1623
+ derivationPath: wallet.derivationPath,
1624
+ thresholdSignatureScheme: wallet.thresholdSignatureScheme,
1625
+ externalServerKeySharesBackupInfo: {
1626
+ passwordEncrypted: false,
1627
+ backups: {
1628
+ dynamic: [],
1629
+ googleDrive: [],
1630
+ iCloud: [],
1631
+ user: [],
1632
+ external: [],
1633
+ delegated: []
1634
+ }
1635
+ }
1636
+ };
1637
+ // Cache the wallet
1638
+ wallets[walletId] = waasWallet;
1639
+ return waasWallet;
1640
+ };
1641
+
1642
+ const revokeDelegation = async (client, walletId)=>{
1643
+ try {
1644
+ // TODO: Uncomment when API method is implemented
1645
+ // const apiClient = createDelegatedApiClient(client);
1646
+ // await apiClient.revokeDelegation({
1647
+ // walletId,
1648
+ // });
1649
+ client.logger.info(`Delegation revoked for wallet: ${walletId}`);
1650
+ } catch (error) {
1651
+ client.logger.error('Error revoking delegation', error);
1652
+ throw new Error('Failed to revoke delegation');
1653
+ }
1654
+ };
1655
+
1656
+ Object.defineProperty(exports, "SOLANA_RPC_URL", {
1105
1657
  enumerable: true,
1106
- get: function () { return node.Ed25519; }
1658
+ get: function () { return core.SOLANA_RPC_URL; }
1107
1659
  });
1108
- Object.defineProperty(exports, "Ed25519InitKeygenResult", {
1660
+ Object.defineProperty(exports, "ThresholdSignatureScheme", {
1109
1661
  enumerable: true,
1110
- get: function () { return node.Ed25519InitKeygenResult; }
1662
+ get: function () { return core.ThresholdSignatureScheme; }
1111
1663
  });
1112
- Object.defineProperty(exports, "Ed25519KeygenResult", {
1664
+ Object.defineProperty(exports, "WalletOperation", {
1113
1665
  enumerable: true,
1114
- get: function () { return node.Ed25519KeygenResult; }
1666
+ get: function () { return core.WalletOperation; }
1115
1667
  });
1116
- Object.defineProperty(exports, "MessageHash", {
1668
+ Object.defineProperty(exports, "getMPCChainConfig", {
1117
1669
  enumerable: true,
1118
- get: function () { return node.MessageHash; }
1670
+ get: function () { return core.getMPCChainConfig; }
1119
1671
  });
1120
1672
  exports.DynamicWalletClient = DynamicWalletClient;
1121
1673
  exports.base64ToBytes = base64ToBytes;
1122
1674
  exports.bytesToBase64 = bytesToBase64;
1675
+ exports.createDelegatedWalletClient = createDelegatedWalletClient;
1676
+ exports.delegatedSignMessage = delegatedSignMessage;
1123
1677
  exports.ensureBase64Padding = ensureBase64Padding;
1678
+ exports.formatEvmMessage = formatEvmMessage;
1679
+ exports.formatMessage = formatMessage;
1124
1680
  exports.getExternalServerKeyShareBackupInfo = getExternalServerKeyShareBackupInfo;
1125
1681
  exports.getMPCSignatureScheme = getMPCSignatureScheme;
1126
1682
  exports.getMPCSigner = getMPCSigner;
1127
1683
  exports.isHexString = isHexString;
1128
1684
  exports.mergeUniqueKeyShares = mergeUniqueKeyShares;
1129
1685
  exports.retryPromise = retryPromise;
1686
+ exports.revokeDelegation = revokeDelegation;
1130
1687
  exports.stringToBytes = stringToBytes;
1131
- Object.keys(core).forEach(function (k) {
1688
+ Object.keys(core$1).forEach(function (k) {
1132
1689
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1133
1690
  enumerable: true,
1134
- get: function () { return core[k]; }
1691
+ get: function () { return core$1[k]; }
1135
1692
  });
1136
1693
  });