@dynamic-labs-wallet/node 0.0.0-pr384.2 → 0.0.0-pr534.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +530 -90
- package/index.esm.js +527 -94
- package/internal/core/bip340.cjs +1 -0
- package/internal/core/bip340.d.ts +1 -1
- package/internal/core/common.cjs +1 -0
- package/internal/core/common.d.ts +1 -0
- package/internal/core/ecdsa.cjs +1 -0
- package/internal/core/ecdsa.d.ts +1 -1
- package/internal/core/ed25519.cjs +1 -0
- package/internal/core/ed25519_exportable.cjs +1 -0
- package/internal/core/ed25519_exportable.d.ts +0 -1
- package/internal/core/index.cjs +1 -0
- package/internal/core/native.d.ts +2 -2
- package/internal/core/sr25519.cjs +1 -0
- package/internal/core/types.cjs +1 -0
- package/internal/node/index.cjs +1 -0
- package/internal/node/index.d.ts +1 -1
- package/internal/node/native/libmpc_executor_linux_arm64_nodejs.node +0 -0
- package/internal/node/native/libmpc_executor_linux_x86_64_nodejs.node +0 -0
- package/internal/node/native/libmpc_executor_macos_arm64_nodejs.node +0 -0
- package/internal/node/native/libmpc_executor_macos_x86_64_nodejs.node +0 -0
- package/internal/node/native.cjs +1 -0
- package/internal/node/native.d.ts +1 -1
- package/package.json +6 -4
- package/src/client.d.ts +56 -17
- package/src/client.d.ts.map +1 -1
- package/src/core/createCore.d.ts +25 -0
- package/src/core/createCore.d.ts.map +1 -0
- package/src/core/types.d.ts +7 -0
- package/src/core/types.d.ts.map +1 -0
- package/src/delegatedClient/createDelegatedClient.d.ts +23 -0
- package/src/delegatedClient/createDelegatedClient.d.ts.map +1 -0
- package/src/delegatedClient/index.d.ts +7 -0
- package/src/delegatedClient/index.d.ts.map +1 -0
- package/src/delegatedClient/modules/decryptWebhookData.d.ts +18 -0
- package/src/delegatedClient/modules/decryptWebhookData.d.ts.map +1 -0
- package/src/delegatedClient/modules/revokeDelegation.d.ts +3 -0
- package/src/delegatedClient/modules/revokeDelegation.d.ts.map +1 -0
- package/src/delegatedClient/modules/sign.d.ts +31 -0
- package/src/delegatedClient/modules/sign.d.ts.map +1 -0
- package/src/index.d.ts +4 -1
- package/src/index.d.ts.map +1 -1
- package/src/types.d.ts +3 -0
- package/src/types.d.ts.map +1 -1
- package/src/utils.d.ts.map +1 -1
- package/internal/core/bip340.js +0 -1
- package/internal/core/common.js +0 -1
- package/internal/core/ecdsa.js +0 -1
- package/internal/core/ed25519.js +0 -1
- package/internal/core/ed25519_exportable.js +0 -1
- package/internal/core/index.js +0 -1
- package/internal/core/package.json +0 -17
- package/internal/core/sr25519.js +0 -1
- package/internal/core/types.js +0 -1
- package/internal/node/index.js +0 -1
- package/internal/node/native.js +0 -1
- package/internal/node/package.json +0 -17
- /package/internal/core/{native.js → native.cjs} +0 -0
package/index.cjs.js
CHANGED
|
@@ -4,8 +4,9 @@ var core$1 = require('#internal/core');
|
|
|
4
4
|
var core = require('@dynamic-labs-wallet/core');
|
|
5
5
|
var node = require('#internal/node');
|
|
6
6
|
var uuid = require('uuid');
|
|
7
|
-
var logger$1 = require('@dynamic-labs/logger');
|
|
8
7
|
var crypto = require('crypto');
|
|
8
|
+
var logger$1 = require('@dynamic-labs/logger');
|
|
9
|
+
require('node:crypto');
|
|
9
10
|
|
|
10
11
|
// Removed duplicate exports - these are already exported from #internal/core
|
|
11
12
|
const getMPCSignatureScheme = ({ signingAlgorithm, baseRelayUrl = core.MPC_RELAY_PROD_API_URL })=>{
|
|
@@ -68,7 +69,8 @@ const getExternalServerKeyShareBackupInfo = (params)=>{
|
|
|
68
69
|
[core.BackupLocation.GOOGLE_DRIVE]: [],
|
|
69
70
|
[core.BackupLocation.ICLOUD]: [],
|
|
70
71
|
[core.BackupLocation.USER]: [],
|
|
71
|
-
[core.BackupLocation.EXTERNAL]: []
|
|
72
|
+
[core.BackupLocation.EXTERNAL]: [],
|
|
73
|
+
[core.BackupLocation.DELEGATED]: []
|
|
72
74
|
};
|
|
73
75
|
if (!(params == null ? void 0 : (_params_walletProperties = params.walletProperties) == null ? void 0 : _params_walletProperties.keyShares)) {
|
|
74
76
|
return {
|
|
@@ -80,7 +82,8 @@ const getExternalServerKeyShareBackupInfo = (params)=>{
|
|
|
80
82
|
if (backups[keyShare.backupLocation]) {
|
|
81
83
|
backups[keyShare.backupLocation].push({
|
|
82
84
|
location: keyShare.backupLocation,
|
|
83
|
-
keyShareId: keyShare.id
|
|
85
|
+
keyShareId: keyShare.id,
|
|
86
|
+
passwordEncrypted: keyShare.passwordEncrypted
|
|
84
87
|
});
|
|
85
88
|
}
|
|
86
89
|
});
|
|
@@ -239,7 +242,7 @@ const getKey = async ({ password, salt, encryptionConfig })=>{
|
|
|
239
242
|
cipher: bytesToBase64(new Uint8Array(encryptedData)),
|
|
240
243
|
version
|
|
241
244
|
};
|
|
242
|
-
} catch (
|
|
245
|
+
} catch (e) {
|
|
243
246
|
throw new Error('Error encrypting data');
|
|
244
247
|
}
|
|
245
248
|
};
|
|
@@ -283,6 +286,16 @@ const getKey = async ({ password, salt, encryptionConfig })=>{
|
|
|
283
286
|
const DEFAULT_LOG_LEVEL = 'INFO';
|
|
284
287
|
|
|
285
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
|
+
}
|
|
286
299
|
ensureApiClientAuthenticated() {
|
|
287
300
|
if (!this.isApiClientAuthenticated) {
|
|
288
301
|
throw new Error('Client must be authenticated before making API calls. Call authenticateApiToken first.');
|
|
@@ -306,7 +319,7 @@ class DynamicWalletClient {
|
|
|
306
319
|
});
|
|
307
320
|
this.isApiClientAuthenticated = true;
|
|
308
321
|
}
|
|
309
|
-
async dynamicServerInitializeKeyGen({ chainName, externalServerKeygenIds, thresholdSignatureScheme, dynamicRequestId, onError, onCeremonyComplete }) {
|
|
322
|
+
async dynamicServerInitializeKeyGen({ chainName, externalServerKeygenIds, thresholdSignatureScheme, dynamicRequestId, skipLock, onError, onCeremonyComplete }) {
|
|
310
323
|
this.ensureApiClientAuthenticated();
|
|
311
324
|
try {
|
|
312
325
|
const data = await this.apiClient.createWalletAccount({
|
|
@@ -314,6 +327,7 @@ class DynamicWalletClient {
|
|
|
314
327
|
clientKeygenIds: externalServerKeygenIds,
|
|
315
328
|
thresholdSignatureScheme,
|
|
316
329
|
dynamicRequestId,
|
|
330
|
+
skipLock,
|
|
317
331
|
onError,
|
|
318
332
|
onCeremonyComplete
|
|
319
333
|
});
|
|
@@ -400,7 +414,7 @@ class DynamicWalletClient {
|
|
|
400
414
|
throw new Error('Error deriving public key in externalServerKeyGen');
|
|
401
415
|
}
|
|
402
416
|
}
|
|
403
|
-
async keyGen({ chainName, thresholdSignatureScheme, onError, onCeremonyComplete }) {
|
|
417
|
+
async keyGen({ chainName, thresholdSignatureScheme, skipLock, onError, onCeremonyComplete }) {
|
|
404
418
|
const dynamicRequestId = uuid.v4();
|
|
405
419
|
try {
|
|
406
420
|
const externalServerInitKeygenResults = await this.externalServerInitializeKeyGen({
|
|
@@ -413,6 +427,7 @@ class DynamicWalletClient {
|
|
|
413
427
|
externalServerKeygenIds,
|
|
414
428
|
dynamicRequestId,
|
|
415
429
|
thresholdSignatureScheme,
|
|
430
|
+
skipLock,
|
|
416
431
|
onCeremonyComplete
|
|
417
432
|
});
|
|
418
433
|
const { rawPublicKey, externalServerKeyGenResults } = await this.externalServerKeyGen({
|
|
@@ -480,7 +495,7 @@ class DynamicWalletClient {
|
|
|
480
495
|
externalServerKeyShares: externalServerKeygenResults
|
|
481
496
|
};
|
|
482
497
|
}
|
|
483
|
-
async dynamicServerSign({ walletId, message, isFormatted }) {
|
|
498
|
+
async dynamicServerSign({ walletId, message, isFormatted, context, onError }) {
|
|
484
499
|
const dynamicRequestId = uuid.v4();
|
|
485
500
|
this.ensureApiClientAuthenticated();
|
|
486
501
|
// Create the room and sign the message
|
|
@@ -491,7 +506,10 @@ class DynamicWalletClient {
|
|
|
491
506
|
walletId,
|
|
492
507
|
message,
|
|
493
508
|
isFormatted,
|
|
494
|
-
dynamicRequestId
|
|
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
|
|
495
513
|
});
|
|
496
514
|
return data;
|
|
497
515
|
}
|
|
@@ -509,38 +527,102 @@ class DynamicWalletClient {
|
|
|
509
527
|
throw error;
|
|
510
528
|
}
|
|
511
529
|
}
|
|
512
|
-
async
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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;
|
|
526
625
|
}
|
|
527
|
-
// Perform the dynamic server sign
|
|
528
|
-
const data = await this.dynamicServerSign({
|
|
529
|
-
walletId: wallet.walletId,
|
|
530
|
-
message,
|
|
531
|
-
isFormatted
|
|
532
|
-
});
|
|
533
|
-
const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
|
|
534
|
-
// Perform the external server sign and return the signature
|
|
535
|
-
const signature = await this.externalServerSign({
|
|
536
|
-
chainName,
|
|
537
|
-
message,
|
|
538
|
-
roomId: data.roomId,
|
|
539
|
-
keyShare: externalServerKeyShares[0],
|
|
540
|
-
derivationPath,
|
|
541
|
-
isFormatted
|
|
542
|
-
});
|
|
543
|
-
return signature;
|
|
544
626
|
}
|
|
545
627
|
async refreshWalletAccountShares({ accountAddress, chainName, password = undefined, externalServerKeyShares, backUpToClientShareService = false }) {
|
|
546
628
|
this.ensureApiClientAuthenticated();
|
|
@@ -818,19 +900,21 @@ class DynamicWalletClient {
|
|
|
818
900
|
if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
|
|
819
901
|
throw new Error(`WalletId not found for accountAddress: ${accountAddress}`);
|
|
820
902
|
}
|
|
903
|
+
const passwordEncryptedFlag = Boolean(password) && password !== this.environmentId;
|
|
821
904
|
const locations = [];
|
|
822
905
|
if (backUpToClientShareService) {
|
|
823
906
|
const data = await this.apiClient.storeEncryptedBackupByWallet({
|
|
824
907
|
walletId: this.walletMap[accountAddress].walletId,
|
|
825
908
|
encryptedKeyShares: encryptedKeyShares,
|
|
826
|
-
passwordEncrypted:
|
|
909
|
+
passwordEncrypted: passwordEncryptedFlag,
|
|
827
910
|
encryptionVersion: ENCRYPTION_VERSION_CURRENT,
|
|
828
911
|
requiresSignedSessionId: false,
|
|
829
912
|
dynamicRequestId
|
|
830
913
|
});
|
|
831
914
|
locations.push({
|
|
832
915
|
location: core.BackupLocation.DYNAMIC,
|
|
833
|
-
externalKeyShareId: data.keyShareIds[0]
|
|
916
|
+
externalKeyShareId: data.keyShareIds[0],
|
|
917
|
+
passwordEncrypted: passwordEncryptedFlag
|
|
834
918
|
});
|
|
835
919
|
} else {
|
|
836
920
|
locations.push({
|
|
@@ -849,7 +933,7 @@ class DynamicWalletClient {
|
|
|
849
933
|
id: ks.keyShareId,
|
|
850
934
|
backupLocation: ks.location,
|
|
851
935
|
externalKeyShareId: ks.externalKeyShareId,
|
|
852
|
-
passwordEncrypted:
|
|
936
|
+
passwordEncrypted: passwordEncryptedFlag
|
|
853
937
|
})),
|
|
854
938
|
thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme
|
|
855
939
|
}
|
|
@@ -881,12 +965,25 @@ class DynamicWalletClient {
|
|
|
881
965
|
});
|
|
882
966
|
}
|
|
883
967
|
async getExternalServerKeyShares({ accountAddress, password }) {
|
|
968
|
+
var _wallet_externalServerKeySharesBackupInfo_backups, _wallet_externalServerKeySharesBackupInfo;
|
|
884
969
|
const wallet = await this.getWallet({
|
|
885
970
|
accountAddress,
|
|
886
971
|
password,
|
|
887
972
|
walletOperation: core.WalletOperation.REACH_THRESHOLD
|
|
888
973
|
});
|
|
889
|
-
|
|
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;
|
|
890
987
|
}
|
|
891
988
|
async updatePassword({ accountAddress, existingPassword, newPassword, backUpToClientShareService }) {
|
|
892
989
|
await this.getWallet({
|
|
@@ -928,10 +1025,14 @@ class DynamicWalletClient {
|
|
|
928
1025
|
if (shareCount !== undefined) {
|
|
929
1026
|
requiredShareCount = shareCount;
|
|
930
1027
|
}
|
|
931
|
-
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;
|
|
932
1033
|
return {
|
|
933
1034
|
shares: {
|
|
934
|
-
[
|
|
1035
|
+
[backupLocation]: sharesToUse.map((ks)=>{
|
|
935
1036
|
var _ks_externalKeyShareId, _ref;
|
|
936
1037
|
return (_ref = (_ks_externalKeyShareId = ks.externalKeyShareId) != null ? _ks_externalKeyShareId : ks.keyShareId) != null ? _ref : '';
|
|
937
1038
|
})
|
|
@@ -939,9 +1040,42 @@ class DynamicWalletClient {
|
|
|
939
1040
|
requiredShareCount
|
|
940
1041
|
};
|
|
941
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
|
+
}
|
|
942
1068
|
async recoverEncryptedBackupByWallet({ accountAddress, password, walletOperation, shareCount = undefined, storeRecoveredShares = true }) {
|
|
1069
|
+
var _wallet_externalServerKeySharesBackupInfo;
|
|
943
1070
|
this.ensureApiClientAuthenticated();
|
|
944
|
-
|
|
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
|
+
}
|
|
945
1079
|
this.logger.debug(`recoverEncryptedBackupByWallet wallet: ${walletOperation}`, wallet);
|
|
946
1080
|
const { shares } = this.recoverStrategy({
|
|
947
1081
|
externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
|
|
@@ -949,13 +1083,30 @@ class DynamicWalletClient {
|
|
|
949
1083
|
walletOperation,
|
|
950
1084
|
shareCount
|
|
951
1085
|
});
|
|
952
|
-
|
|
953
|
-
const
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
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
|
+
}
|
|
958
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
|
+
}
|
|
959
1110
|
const decryptedKeyShares = await Promise.all(dynamicKeyShares.map((keyShare)=>this.decryptKeyShare({
|
|
960
1111
|
keyShare: keyShare.encryptedAccountCredential,
|
|
961
1112
|
password: password != null ? password : this.environmentId
|
|
@@ -985,6 +1136,7 @@ class DynamicWalletClient {
|
|
|
985
1136
|
* @param walletOperation - The wallet operation that determines required fields
|
|
986
1137
|
* @returns boolean indicating if wallet needs to be re-fetched and restored from server
|
|
987
1138
|
*/ async checkWalletFields({ accountAddress, walletOperation = core.WalletOperation.REACH_THRESHOLD, shareCount }) {
|
|
1139
|
+
var _existingWallet_externalServerKeyShares;
|
|
988
1140
|
let keyshareCheck = false;
|
|
989
1141
|
let walletCheck = false;
|
|
990
1142
|
let thresholdSignatureSchemeCheck = false;
|
|
@@ -1004,7 +1156,7 @@ class DynamicWalletClient {
|
|
|
1004
1156
|
}
|
|
1005
1157
|
// check if wallet already exists with sufficient keyshares
|
|
1006
1158
|
if (existingWallet) {
|
|
1007
|
-
var
|
|
1159
|
+
var _existingWallet_externalServerKeyShares1;
|
|
1008
1160
|
const { shares } = this.recoverStrategy({
|
|
1009
1161
|
externalServerKeySharesBackupInfo: existingWallet.externalServerKeySharesBackupInfo || {
|
|
1010
1162
|
backups: getExternalServerKeyShareBackupInfo()
|
|
@@ -1014,11 +1166,35 @@ class DynamicWalletClient {
|
|
|
1014
1166
|
shareCount
|
|
1015
1167
|
});
|
|
1016
1168
|
const { dynamic: requiredDynamicKeyShareIds = [] } = shares;
|
|
1017
|
-
|
|
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) {
|
|
1018
1184
|
keyshareCheck = true;
|
|
1019
1185
|
}
|
|
1020
1186
|
}
|
|
1021
|
-
|
|
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;
|
|
1022
1198
|
}
|
|
1023
1199
|
/**
|
|
1024
1200
|
* verifyPassword attempts to recover and decrypt a single client key share using the provided password.
|
|
@@ -1044,8 +1220,10 @@ class DynamicWalletClient {
|
|
|
1044
1220
|
accountAddress
|
|
1045
1221
|
});
|
|
1046
1222
|
const { dynamic: dynamicKeyShareIds = [] } = backups;
|
|
1047
|
-
|
|
1048
|
-
|
|
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');
|
|
1049
1227
|
}
|
|
1050
1228
|
try {
|
|
1051
1229
|
await this.recoverEncryptedBackupByWallet({
|
|
@@ -1090,34 +1268,44 @@ class DynamicWalletClient {
|
|
|
1090
1268
|
if (walletOperation === core.WalletOperation.REACH_ALL_PARTIES || walletOperation === core.WalletOperation.REFRESH || walletOperation === core.WalletOperation.RESHARE) {
|
|
1091
1269
|
return true;
|
|
1092
1270
|
}
|
|
1093
|
-
const { requiredShareCount } = this.recoverStrategy({
|
|
1271
|
+
const { shares, requiredShareCount } = this.recoverStrategy({
|
|
1094
1272
|
externalServerKeySharesBackupInfo,
|
|
1095
1273
|
thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme,
|
|
1096
1274
|
walletOperation
|
|
1097
1275
|
});
|
|
1098
|
-
|
|
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) {
|
|
1099
1281
|
return false;
|
|
1100
1282
|
}
|
|
1101
1283
|
return true;
|
|
1102
1284
|
}
|
|
1103
1285
|
async getWalletExternalServerKeyShareBackupInfo({ accountAddress }) {
|
|
1104
|
-
var
|
|
1286
|
+
var _wallet_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC, _wallet_externalServerKeySharesBackupInfo_backups, _wallet_externalServerKeySharesBackupInfo, _user_verifiedCredentials;
|
|
1105
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
|
+
}
|
|
1106
1296
|
// Return existing backup info if it exists
|
|
1107
|
-
if (((
|
|
1108
|
-
return
|
|
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;
|
|
1109
1299
|
}
|
|
1110
1300
|
// Get backup info from server
|
|
1111
1301
|
const user = await this.apiClient.getUser(uuid.v4());
|
|
1112
|
-
const
|
|
1302
|
+
const walletData = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
|
|
1113
1303
|
return getExternalServerKeyShareBackupInfo({
|
|
1114
|
-
walletProperties:
|
|
1304
|
+
walletProperties: walletData == null ? void 0 : walletData.walletProperties
|
|
1115
1305
|
});
|
|
1116
1306
|
}
|
|
1117
1307
|
async getWallet({ accountAddress, walletOperation = core.WalletOperation.NO_OPERATION, shareCount = undefined, password = undefined }) {
|
|
1118
|
-
const dynamicRequestId = uuid.v4();
|
|
1119
1308
|
try {
|
|
1120
|
-
var _user_verifiedCredentials;
|
|
1121
1309
|
this.ensureApiClientAuthenticated();
|
|
1122
1310
|
const existingWalletCheck = await this.checkWalletFields({
|
|
1123
1311
|
accountAddress,
|
|
@@ -1128,22 +1316,13 @@ class DynamicWalletClient {
|
|
|
1128
1316
|
this.logger.debug(`Wallet ${accountAddress} already exists`);
|
|
1129
1317
|
return this.walletMap[accountAddress];
|
|
1130
1318
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1319
|
+
const wallet = await this.getWalletByAddress(accountAddress);
|
|
1320
|
+
if (!wallet) {
|
|
1321
|
+
throw new Error(`Wallet not found for address 3: ${accountAddress}`);
|
|
1322
|
+
}
|
|
1135
1323
|
this.logger.debug('Restoring wallet', wallet);
|
|
1136
|
-
|
|
1137
|
-
this.walletMap[accountAddress] =
|
|
1138
|
-
walletId: wallet.id,
|
|
1139
|
-
chainName: wallet.chainName,
|
|
1140
|
-
accountAddress,
|
|
1141
|
-
thresholdSignatureScheme: walletProperties.thresholdSignatureScheme,
|
|
1142
|
-
derivationPath: walletProperties.derivationPath,
|
|
1143
|
-
externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
|
|
1144
|
-
walletProperties
|
|
1145
|
-
})
|
|
1146
|
-
});
|
|
1324
|
+
// The wallet is already processed, so we can use it directly
|
|
1325
|
+
this.walletMap[accountAddress] = wallet;
|
|
1147
1326
|
if (walletOperation !== core.WalletOperation.NO_OPERATION && await this.requiresRestoreBackupSharesForOperation({
|
|
1148
1327
|
accountAddress,
|
|
1149
1328
|
walletOperation
|
|
@@ -1171,14 +1350,82 @@ class DynamicWalletClient {
|
|
|
1171
1350
|
throw error;
|
|
1172
1351
|
}
|
|
1173
1352
|
}
|
|
1174
|
-
|
|
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];
|
|
1360
|
+
}
|
|
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;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
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() {
|
|
1175
1422
|
var _user_verifiedCredentials;
|
|
1176
1423
|
this.ensureApiClientAuthenticated();
|
|
1177
1424
|
const user = await this.apiClient.getUser(uuid.v4());
|
|
1178
1425
|
const waasWallets = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.filter((vc)=>vc.walletName === 'dynamicwaas');
|
|
1179
1426
|
const wallets = waasWallets.map((vc)=>{
|
|
1180
|
-
var _this_walletMap_vc_address,
|
|
1181
|
-
var
|
|
1427
|
+
var _this_walletMap_vc_address, _vc_walletProperties, _vc_walletProperties1;
|
|
1428
|
+
var _vc_walletProperties_derivationPath;
|
|
1182
1429
|
return {
|
|
1183
1430
|
walletId: vc.id,
|
|
1184
1431
|
chainName: vc.chain,
|
|
@@ -1187,39 +1434,225 @@ class DynamicWalletClient {
|
|
|
1187
1434
|
walletProperties: vc.walletProperties || {}
|
|
1188
1435
|
}),
|
|
1189
1436
|
externalServerKeyShares: ((_this_walletMap_vc_address = this.walletMap[vc.address]) == null ? void 0 : _this_walletMap_vc_address.externalServerKeyShares) || [],
|
|
1190
|
-
derivationPath: (
|
|
1191
|
-
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
|
|
1192
1439
|
};
|
|
1193
1440
|
});
|
|
1194
1441
|
this.walletMap = wallets.reduce((acc, wallet)=>{
|
|
1195
|
-
var _acc_accountAddress;
|
|
1196
|
-
const accountAddress = wallet.accountAddress;
|
|
1197
1442
|
acc[wallet.accountAddress] = {
|
|
1198
1443
|
walletId: wallet.walletId,
|
|
1199
1444
|
chainName: wallet.chainName,
|
|
1200
1445
|
accountAddress: wallet.accountAddress,
|
|
1201
1446
|
externalServerKeyShares: wallet.externalServerKeyShares || [],
|
|
1202
1447
|
externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
|
|
1203
|
-
derivationPath:
|
|
1448
|
+
derivationPath: wallet.derivationPath,
|
|
1204
1449
|
thresholdSignatureScheme: wallet.thresholdSignatureScheme
|
|
1205
1450
|
};
|
|
1206
1451
|
return acc;
|
|
1207
1452
|
}, {});
|
|
1208
1453
|
return wallets;
|
|
1209
1454
|
}
|
|
1210
|
-
constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug }){
|
|
1455
|
+
constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug, forwardMPCClient, enableMPCAccelerator = false }){
|
|
1211
1456
|
this.logger = logger;
|
|
1212
1457
|
this.walletMap = {} // todo: store in session storage
|
|
1213
1458
|
;
|
|
1214
1459
|
this.isApiClientAuthenticated = false;
|
|
1460
|
+
this.forwardMPCEnabled = false;
|
|
1215
1461
|
this.environmentId = environmentId;
|
|
1216
1462
|
this.baseMPCRelayApiUrl = baseMPCRelayApiUrl;
|
|
1217
1463
|
this.baseApiUrl = baseApiUrl;
|
|
1218
1464
|
this.debug = Boolean(debug);
|
|
1219
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
|
+
}
|
|
1220
1477
|
}
|
|
1221
1478
|
}
|
|
1222
1479
|
|
|
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
|
+
|
|
1223
1656
|
Object.defineProperty(exports, "SOLANA_RPC_URL", {
|
|
1224
1657
|
enumerable: true,
|
|
1225
1658
|
get: function () { return core.SOLANA_RPC_URL; }
|
|
@@ -1232,9 +1665,15 @@ Object.defineProperty(exports, "WalletOperation", {
|
|
|
1232
1665
|
enumerable: true,
|
|
1233
1666
|
get: function () { return core.WalletOperation; }
|
|
1234
1667
|
});
|
|
1668
|
+
Object.defineProperty(exports, "getMPCChainConfig", {
|
|
1669
|
+
enumerable: true,
|
|
1670
|
+
get: function () { return core.getMPCChainConfig; }
|
|
1671
|
+
});
|
|
1235
1672
|
exports.DynamicWalletClient = DynamicWalletClient;
|
|
1236
1673
|
exports.base64ToBytes = base64ToBytes;
|
|
1237
1674
|
exports.bytesToBase64 = bytesToBase64;
|
|
1675
|
+
exports.createDelegatedWalletClient = createDelegatedWalletClient;
|
|
1676
|
+
exports.delegatedSignMessage = delegatedSignMessage;
|
|
1238
1677
|
exports.ensureBase64Padding = ensureBase64Padding;
|
|
1239
1678
|
exports.formatEvmMessage = formatEvmMessage;
|
|
1240
1679
|
exports.formatMessage = formatMessage;
|
|
@@ -1244,6 +1683,7 @@ exports.getMPCSigner = getMPCSigner;
|
|
|
1244
1683
|
exports.isHexString = isHexString;
|
|
1245
1684
|
exports.mergeUniqueKeyShares = mergeUniqueKeyShares;
|
|
1246
1685
|
exports.retryPromise = retryPromise;
|
|
1686
|
+
exports.revokeDelegation = revokeDelegation;
|
|
1247
1687
|
exports.stringToBytes = stringToBytes;
|
|
1248
1688
|
Object.keys(core$1).forEach(function (k) {
|
|
1249
1689
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|