@dynamic-labs-wallet/browser 0.0.0-beta.310 → 0.0.0-beta.311
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 +440 -291
- package/index.esm.js +442 -289
- package/package.json +6 -2
- package/src/backup/encryption/argon2.d.ts +10 -0
- package/src/backup/encryption/argon2.d.ts.map +1 -0
- package/src/backup/encryption/config.d.ts +39 -0
- package/src/backup/encryption/config.d.ts.map +1 -0
- package/src/backup/encryption/constants.d.ts +35 -0
- package/src/backup/encryption/constants.d.ts.map +1 -0
- package/src/backup/encryption/core.d.ts +27 -0
- package/src/backup/encryption/core.d.ts.map +1 -0
- package/src/backup/encryption/pbkdf2.d.ts +10 -0
- package/src/backup/encryption/pbkdf2.d.ts.map +1 -0
- package/src/backup/encryption/types.d.ts +46 -0
- package/src/backup/encryption/types.d.ts.map +1 -0
- package/src/backup/encryption/utils.d.ts +9 -0
- package/src/backup/encryption/utils.d.ts.map +1 -0
- package/src/client.d.ts +5 -3
- package/src/client.d.ts.map +1 -1
- package/src/services/axiosErrorResponse.d.ts.map +1 -1
- package/src/utils.d.ts +2 -6
- package/src/utils.d.ts.map +1 -1
- package/src/backup/encryption.d.ts +0 -62
- package/src/backup/encryption.d.ts.map +0 -1
package/index.cjs.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@dynamic-labs-wallet/core');
|
|
4
4
|
var web = require('./internal/web');
|
|
5
|
-
var uuid = require('uuid');
|
|
6
5
|
var semver = require('semver');
|
|
6
|
+
var uuid = require('uuid');
|
|
7
7
|
var logger$1 = require('@dynamic-labs/logger');
|
|
8
|
-
var
|
|
8
|
+
var loadArgon2idWasm = require('argon2id');
|
|
9
9
|
var axios = require('axios');
|
|
10
10
|
var createHttpError = require('http-errors');
|
|
11
|
+
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
11
12
|
|
|
12
13
|
function _extends() {
|
|
13
14
|
_extends = Object.assign || function assign(target) {
|
|
@@ -41,65 +42,118 @@ const getMPCSigner = ({ chainName, baseRelayUrl })=>{
|
|
|
41
42
|
return signatureScheme;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Encryption version identifiers
|
|
47
|
+
*/ var EncryptionVersion = /*#__PURE__*/ function(EncryptionVersion) {
|
|
48
|
+
EncryptionVersion["V1_LEGACY"] = "v1";
|
|
49
|
+
EncryptionVersion["V2_PBKDF2"] = "v2";
|
|
50
|
+
EncryptionVersion["V3_ARGON2"] = "v3";
|
|
51
|
+
return EncryptionVersion;
|
|
52
|
+
}({});
|
|
53
|
+
/**
|
|
54
|
+
* Current default version for new encryptions
|
|
55
|
+
*/ const ENCRYPTION_VERSION_CURRENT = "v3";
|
|
56
|
+
/**
|
|
57
|
+
* Algorithm constants
|
|
58
|
+
*/ const PBKDF2_ALGORITHM = 'PBKDF2';
|
|
59
|
+
const HASH_ALGORITHM = 'SHA-256'; // Generic hash algorithm constant
|
|
60
|
+
const ARGON2_ALGORITHM = 'Argon2id';
|
|
61
|
+
const AES_GCM_ALGORITHM = 'AES-GCM';
|
|
62
|
+
const AES_GCM_LENGTH = 256;
|
|
63
|
+
/**
|
|
64
|
+
* Argon2 configuration constants, values were chosen based on RFC (https://www.rfc-editor.org/rfc/rfc9106.html#name-parameter-choice)
|
|
65
|
+
* taking into account that this runs in the client, possibly in smartphones with limited resources
|
|
66
|
+
*/ const ARGON2_MEMORY_SIZE = 65536; // 64 MB in KiB
|
|
67
|
+
const ARGON2_ITERATIONS = 3;
|
|
68
|
+
const ARGON2_PARALLELISM = 2;
|
|
69
|
+
const ARGON2_HASH_LENGTH = 32;
|
|
70
|
+
/**
|
|
71
|
+
* PBKDF2 configuration constants
|
|
72
|
+
*/ const PBKDF2_ITERATIONS_V1 = 100000;
|
|
73
|
+
const PBKDF2_ITERATIONS_V2 = 1000000;
|
|
53
74
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Derives a key using Argon2id algorithm
|
|
77
|
+
* @param params - Key derivation parameters
|
|
78
|
+
* @param encryptionConfig - Encryption configuration
|
|
79
|
+
* @returns Promise<CryptoKey>
|
|
80
|
+
*/ const deriveArgon2Key = async ({ password, salt }, encryptionConfig)=>{
|
|
81
|
+
const argon2id = await loadArgon2idWasm();
|
|
82
|
+
const argon2Config = encryptionConfig;
|
|
83
|
+
const passwordBytes = new TextEncoder().encode(password);
|
|
84
|
+
const hash = argon2id({
|
|
85
|
+
password: passwordBytes,
|
|
86
|
+
salt: salt,
|
|
87
|
+
parallelism: argon2Config.parallelism || ARGON2_PARALLELISM,
|
|
88
|
+
passes: argon2Config.iterations,
|
|
89
|
+
memorySize: argon2Config.memorySize || ARGON2_MEMORY_SIZE,
|
|
90
|
+
tagLength: argon2Config.hashLength || ARGON2_HASH_LENGTH
|
|
60
91
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
case 422:
|
|
69
|
-
throw createHttpError(422, 'Unprocessable content');
|
|
70
|
-
case 500:
|
|
71
|
-
throw createHttpError(500, 'Internal server error');
|
|
72
|
-
default:
|
|
73
|
-
throw createHttpError(500, 'Internal server error');
|
|
74
|
-
}
|
|
92
|
+
return crypto.subtle.importKey('raw', new Uint8Array(hash), {
|
|
93
|
+
name: encryptionConfig.algorithm,
|
|
94
|
+
length: encryptionConfig.algorithmLength
|
|
95
|
+
}, false, [
|
|
96
|
+
'encrypt',
|
|
97
|
+
'decrypt'
|
|
98
|
+
]);
|
|
75
99
|
};
|
|
76
100
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Encryption configuration for each version
|
|
103
|
+
*/ const ENCRYPTION_VERSIONS = {
|
|
104
|
+
[EncryptionVersion.V1_LEGACY]: {
|
|
105
|
+
version: EncryptionVersion.V1_LEGACY,
|
|
106
|
+
algorithm: AES_GCM_ALGORITHM,
|
|
107
|
+
keyDerivation: PBKDF2_ALGORITHM,
|
|
108
|
+
iterations: PBKDF2_ITERATIONS_V1,
|
|
109
|
+
hashAlgorithm: HASH_ALGORITHM,
|
|
110
|
+
algorithmLength: AES_GCM_LENGTH
|
|
111
|
+
},
|
|
112
|
+
[EncryptionVersion.V2_PBKDF2]: {
|
|
113
|
+
version: EncryptionVersion.V2_PBKDF2,
|
|
114
|
+
algorithm: AES_GCM_ALGORITHM,
|
|
115
|
+
keyDerivation: PBKDF2_ALGORITHM,
|
|
116
|
+
iterations: PBKDF2_ITERATIONS_V2,
|
|
117
|
+
hashAlgorithm: HASH_ALGORITHM,
|
|
118
|
+
algorithmLength: AES_GCM_LENGTH
|
|
119
|
+
},
|
|
120
|
+
[EncryptionVersion.V3_ARGON2]: {
|
|
121
|
+
version: EncryptionVersion.V3_ARGON2,
|
|
122
|
+
algorithm: AES_GCM_ALGORITHM,
|
|
123
|
+
keyDerivation: ARGON2_ALGORITHM,
|
|
124
|
+
iterations: ARGON2_ITERATIONS,
|
|
125
|
+
hashAlgorithm: ARGON2_ALGORITHM,
|
|
126
|
+
algorithmLength: AES_GCM_LENGTH,
|
|
127
|
+
memorySize: ARGON2_MEMORY_SIZE,
|
|
128
|
+
parallelism: ARGON2_PARALLELISM,
|
|
129
|
+
hashLength: ARGON2_HASH_LENGTH
|
|
90
130
|
}
|
|
91
131
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Helper function to get encryption configuration by version string
|
|
134
|
+
* @param version - The version string (e.g., 'v1', 'v2', 'v3')
|
|
135
|
+
* @returns The encryption configuration for the specified version
|
|
136
|
+
*/ const getEncryptionConfig = (version)=>{
|
|
137
|
+
// If no version specified, use legacy for backward compatibility
|
|
138
|
+
if (!version) {
|
|
139
|
+
return ENCRYPTION_VERSIONS[EncryptionVersion.V1_LEGACY];
|
|
140
|
+
}
|
|
141
|
+
const config = ENCRYPTION_VERSIONS[version];
|
|
142
|
+
if (!config) {
|
|
143
|
+
throw new Error(`Unsupported encryption version: ${version}`);
|
|
95
144
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
145
|
+
return config;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Check if a configuration uses Argon2
|
|
149
|
+
*/ const isArgon2Config = (config)=>{
|
|
150
|
+
return config.keyDerivation === ARGON2_ALGORITHM;
|
|
100
151
|
};
|
|
101
152
|
|
|
102
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Utility functions for encryption operations
|
|
155
|
+
* These functions are separated to avoid circular dependencies
|
|
156
|
+
*/ const bytesToBase64 = (arr)=>{
|
|
103
157
|
return btoa(Array.from(arr, (b)=>String.fromCharCode(b)).join(''));
|
|
104
158
|
};
|
|
105
159
|
const stringToBytes = (str)=>{
|
|
@@ -112,168 +166,13 @@ const base64ToBytes = (base64)=>{
|
|
|
112
166
|
const ensureBase64Padding = (str)=>{
|
|
113
167
|
return str.padEnd(Math.ceil(str.length / 4) * 4, '=');
|
|
114
168
|
};
|
|
115
|
-
const isBrowser = ()=>typeof window !== 'undefined';
|
|
116
|
-
const getClientKeyShareExportFileName = ({ thresholdSignatureScheme, accountAddress })=>{
|
|
117
|
-
return `${CLIENT_KEYSHARE_EXPORT_FILENAME_PREFIX}-${thresholdSignatureScheme}-${accountAddress}.json`;
|
|
118
|
-
};
|
|
119
|
-
const getClientKeyShareBackupInfo = (params)=>{
|
|
120
|
-
var _params_walletProperties, _params_walletProperties_keyShares_;
|
|
121
|
-
const backups = {
|
|
122
|
-
[core.BackupLocation.DYNAMIC]: [],
|
|
123
|
-
[core.BackupLocation.GOOGLE_DRIVE]: [],
|
|
124
|
-
[core.BackupLocation.ICLOUD]: [],
|
|
125
|
-
[core.BackupLocation.USER]: [],
|
|
126
|
-
[core.BackupLocation.EXTERNAL]: []
|
|
127
|
-
};
|
|
128
|
-
if (!(params == null ? void 0 : (_params_walletProperties = params.walletProperties) == null ? void 0 : _params_walletProperties.keyShares)) {
|
|
129
|
-
return {
|
|
130
|
-
backups,
|
|
131
|
-
passwordEncrypted: false
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
params.walletProperties.keyShares.forEach((keyShare)=>{
|
|
135
|
-
if (backups[keyShare.backupLocation]) {
|
|
136
|
-
backups[keyShare.backupLocation].push({
|
|
137
|
-
location: keyShare.backupLocation,
|
|
138
|
-
keyShareId: keyShare.id,
|
|
139
|
-
externalKeyShareId: keyShare == null ? void 0 : keyShare.externalKeyShareId
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
const passwordEncrypted = Boolean((_params_walletProperties_keyShares_ = params.walletProperties.keyShares[0]) == null ? void 0 : _params_walletProperties_keyShares_.passwordEncrypted);
|
|
144
|
-
return {
|
|
145
|
-
backups,
|
|
146
|
-
passwordEncrypted
|
|
147
|
-
};
|
|
148
|
-
};
|
|
149
|
-
/**
|
|
150
|
-
* Helper function to merge keyshares and remove duplicates based on pubkey and secretShare
|
|
151
|
-
* @param existingKeyShares - Array of existing keyshares
|
|
152
|
-
* @param newKeyShares - Array of new keyshares to merge
|
|
153
|
-
* @returns Array of merged unique keyshares
|
|
154
|
-
*/ const mergeUniqueKeyShares = (existingKeyShares, newKeyShares)=>{
|
|
155
|
-
const uniqueKeyShares = newKeyShares.filter((newShare)=>!existingKeyShares.some((existingShare)=>{
|
|
156
|
-
if (!(newShare == null ? void 0 : newShare.pubkey) || !(existingShare == null ? void 0 : existingShare.pubkey)) return false;
|
|
157
|
-
return newShare.pubkey.toString() === existingShare.pubkey.toString() && newShare.secretShare === existingShare.secretShare;
|
|
158
|
-
}));
|
|
159
|
-
return [
|
|
160
|
-
...existingKeyShares,
|
|
161
|
-
...uniqueKeyShares
|
|
162
|
-
];
|
|
163
|
-
};
|
|
164
|
-
const timeoutPromise = ({ timeInMs, activity = 'Ceremony' })=>{
|
|
165
|
-
return new Promise((_, reject)=>setTimeout(()=>reject(new Error(`${activity} did not complete in ${timeInMs}ms`)), timeInMs));
|
|
166
|
-
};
|
|
167
|
-
/**
|
|
168
|
-
* Generic helper function to retry a promise-based operations
|
|
169
|
-
*
|
|
170
|
-
* @param operation - The async operation to retry
|
|
171
|
-
* @param config - Configuration options for retry behavior
|
|
172
|
-
* @returns Promise with the operation result
|
|
173
|
-
* @throws Last error encountered after all retries are exhausted
|
|
174
|
-
*/ async function retryPromise(operation, { maxAttempts = 5, retryInterval = 500, operationName = 'operation', logContext = {} } = {}) {
|
|
175
|
-
let attempts = 0;
|
|
176
|
-
while(attempts < maxAttempts){
|
|
177
|
-
try {
|
|
178
|
-
return await operation();
|
|
179
|
-
} catch (error) {
|
|
180
|
-
attempts++;
|
|
181
|
-
if (attempts === maxAttempts) {
|
|
182
|
-
logger.error(`Failed to execute ${operationName} after ${maxAttempts} attempts`, _extends({}, logContext, {
|
|
183
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
184
|
-
}));
|
|
185
|
-
throw error;
|
|
186
|
-
}
|
|
187
|
-
// Calculate exponential backoff delay
|
|
188
|
-
const exponentialDelay = retryInterval * 2 ** (attempts - 1);
|
|
189
|
-
await new Promise((resolve)=>setTimeout(resolve, exponentialDelay));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// TypeScript needs this even though it's unreachable
|
|
193
|
-
throw new Error('Unreachable code');
|
|
194
|
-
}
|
|
195
|
-
const formatEvmMessage = (message)=>{
|
|
196
|
-
if (typeof message === 'string' && message.startsWith('0x')) {
|
|
197
|
-
const serializedTxBytes = Uint8Array.from(Buffer.from(message.slice(2), 'hex'));
|
|
198
|
-
return web.MessageHash.keccak256(serializedTxBytes);
|
|
199
|
-
}
|
|
200
|
-
return web.MessageHash.keccak256(message);
|
|
201
|
-
};
|
|
202
|
-
const isHexString = (str)=>{
|
|
203
|
-
// Remove 0x prefix if present
|
|
204
|
-
const hex = str.startsWith('0x') ? str.slice(2) : str;
|
|
205
|
-
// Check if string contains only hex characters
|
|
206
|
-
return /^[0-9A-Fa-f]+$/.test(hex);
|
|
207
|
-
};
|
|
208
|
-
const formatSolanaMessage = (message)=>{
|
|
209
|
-
if (typeof message === 'string') {
|
|
210
|
-
if (!isHexString(message)) {
|
|
211
|
-
return Buffer.from(message).toString('hex');
|
|
212
|
-
} else {
|
|
213
|
-
return new Uint8Array(Buffer.from(message, 'hex'));
|
|
214
|
-
}
|
|
215
|
-
} else {
|
|
216
|
-
return message;
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
const formatMessage = (chainName, message)=>{
|
|
220
|
-
switch(chainName){
|
|
221
|
-
case 'EVM':
|
|
222
|
-
return formatEvmMessage(message);
|
|
223
|
-
case 'SVM':
|
|
224
|
-
return formatSolanaMessage(message);
|
|
225
|
-
case 'SUI':
|
|
226
|
-
return message;
|
|
227
|
-
default:
|
|
228
|
-
throw new Error('Unsupported chain name');
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
const getGoogleOAuthAccountId = (verifiedCredentials)=>{
|
|
232
|
-
const googleVerifiedCredential = verifiedCredentials == null ? void 0 : verifiedCredentials.find((credential)=>credential.oauthProvider === sdkApiCore.ProviderEnum.Google);
|
|
233
|
-
return googleVerifiedCredential == null ? void 0 : googleVerifiedCredential.id;
|
|
234
|
-
};
|
|
235
|
-
const createBackupData = ({ encryptedKeyShares, accountAddress, thresholdSignatureScheme, hasPassword = true })=>{
|
|
236
|
-
return {
|
|
237
|
-
keyShares: encryptedKeyShares,
|
|
238
|
-
metadata: {
|
|
239
|
-
createdAt: new Date().toISOString(),
|
|
240
|
-
accountAddress,
|
|
241
|
-
thresholdSignatureScheme,
|
|
242
|
-
hasPassword,
|
|
243
|
-
encryption: getEncryptionMetadataForVersion(ENCRYPTION_VERSION_CURRENT),
|
|
244
|
-
encryptionVersion: ENCRYPTION_VERSION_CURRENT,
|
|
245
|
-
shareCount: encryptedKeyShares.length
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
};
|
|
249
169
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
const ENCRYPTION_VERSIONS = {
|
|
257
|
-
[ENCRYPTION_VERSION_LEGACY]: {
|
|
258
|
-
version: ENCRYPTION_VERSION_LEGACY,
|
|
259
|
-
algorithm: AES_GCM_ALGORITHM,
|
|
260
|
-
keyDerivation: PBKDF2_ALGORITHM,
|
|
261
|
-
iterations: 100000,
|
|
262
|
-
hashAlgorithm: PBKDF2_HASH_ALGORITHM,
|
|
263
|
-
algorithmLength: AES_GCM_LENGTH
|
|
264
|
-
},
|
|
265
|
-
[ENCRYPTION_VERSION_CURRENT]: {
|
|
266
|
-
version: ENCRYPTION_VERSION_CURRENT,
|
|
267
|
-
algorithm: AES_GCM_ALGORITHM,
|
|
268
|
-
keyDerivation: PBKDF2_ALGORITHM,
|
|
269
|
-
iterations: 1000000,
|
|
270
|
-
hashAlgorithm: PBKDF2_HASH_ALGORITHM,
|
|
271
|
-
algorithmLength: AES_GCM_LENGTH
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
|
-
ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_CURRENT].iterations;
|
|
275
|
-
ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_LEGACY].iterations;
|
|
276
|
-
const getKey = async ({ password, salt, encryptionConfig })=>{
|
|
170
|
+
/**
|
|
171
|
+
* Derives a key using PBKDF2 algorithm
|
|
172
|
+
* @param params - Key derivation parameters
|
|
173
|
+
* @param encryptionConfig - Encryption configuration
|
|
174
|
+
* @returns Promise<CryptoKey>
|
|
175
|
+
*/ const derivePBKDF2Key = async ({ password, salt }, encryptionConfig)=>{
|
|
277
176
|
const passwordBytes = stringToBytes(password);
|
|
278
177
|
const initialKey = await crypto.subtle.importKey('raw', passwordBytes, {
|
|
279
178
|
name: 'PBKDF2'
|
|
@@ -293,23 +192,30 @@ const getKey = async ({ password, salt, encryptionConfig })=>{
|
|
|
293
192
|
'decrypt'
|
|
294
193
|
]);
|
|
295
194
|
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get the appropriate key derivation function based on the encryption config
|
|
198
|
+
*/ const getKey = async (params, encryptionConfig)=>{
|
|
199
|
+
// Use Argon2 for v3, PBKDF2 for v1 and v2
|
|
200
|
+
if (encryptionConfig.keyDerivation === ARGON2_ALGORITHM) {
|
|
201
|
+
return deriveArgon2Key(params, encryptionConfig);
|
|
202
|
+
} else {
|
|
203
|
+
return derivePBKDF2Key(params, encryptionConfig);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
296
206
|
/**
|
|
297
207
|
* Encrypts data using the specified encryption version.
|
|
298
208
|
* Always uses the latest encryption configuration for new encryptions by default.
|
|
299
209
|
*/ const encryptData = async ({ data, password, version = ENCRYPTION_VERSION_CURRENT })=>{
|
|
300
|
-
const encryptionConfig =
|
|
301
|
-
if (!encryptionConfig) {
|
|
302
|
-
throw new Error(`Unsupported encryption version: ${version}`);
|
|
303
|
-
}
|
|
210
|
+
const encryptionConfig = getEncryptionConfig(version);
|
|
304
211
|
try {
|
|
305
212
|
// Generate a random salt and IV
|
|
306
213
|
const salt = crypto.getRandomValues(new Uint8Array(16));
|
|
307
214
|
const iv = crypto.getRandomValues(new Uint8Array(12)); // AES-GCM requires 12 bytes
|
|
308
215
|
const key = await getKey({
|
|
309
216
|
password,
|
|
310
|
-
salt
|
|
311
|
-
|
|
312
|
-
});
|
|
217
|
+
salt
|
|
218
|
+
}, encryptionConfig);
|
|
313
219
|
// Convert the input string to bytes
|
|
314
220
|
const dataBytes = new TextEncoder().encode(data);
|
|
315
221
|
// Encrypt the data
|
|
@@ -325,13 +231,15 @@ const getKey = async ({ password, salt, encryptionConfig })=>{
|
|
|
325
231
|
version
|
|
326
232
|
};
|
|
327
233
|
} catch (error) {
|
|
328
|
-
|
|
234
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
235
|
+
throw new Error(`Error encrypting data: ${errorMessage} (version: ${version})`);
|
|
329
236
|
}
|
|
330
237
|
};
|
|
331
238
|
/**
|
|
332
239
|
* Decrypts data with version-based configuration.
|
|
333
240
|
* Uses the version field from the data to determine encryption parameters.
|
|
334
241
|
* Falls back to legacy version for backward compatibility if no version is specified.
|
|
242
|
+
* For v3 (Argon2), retries with parallelism=1 if an OperationError occurs.
|
|
335
243
|
*/ const decryptData = async ({ data, password })=>{
|
|
336
244
|
const { salt, iv, cipher, version } = data;
|
|
337
245
|
// Ensure proper base64 padding for all values
|
|
@@ -341,26 +249,42 @@ const getKey = async ({ password, salt, encryptionConfig })=>{
|
|
|
341
249
|
const saltBytes = base64ToBytes(paddedSalt);
|
|
342
250
|
const ivBytes = base64ToBytes(paddedIv);
|
|
343
251
|
const cipherBytes = base64ToBytes(paddedCipher);
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (version && ENCRYPTION_VERSIONS[version]) {
|
|
347
|
-
encryptionConfig = ENCRYPTION_VERSIONS[version];
|
|
348
|
-
} else {
|
|
349
|
-
// Fallback to legacy version for backward compatibility
|
|
350
|
-
encryptionConfig = ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_LEGACY];
|
|
351
|
-
}
|
|
252
|
+
// Determine which encryption configuration to use
|
|
253
|
+
const encryptionConfig = getEncryptionConfig(version);
|
|
352
254
|
try {
|
|
353
255
|
const key = await getKey({
|
|
354
256
|
password,
|
|
355
|
-
salt: saltBytes
|
|
356
|
-
|
|
357
|
-
});
|
|
257
|
+
salt: saltBytes
|
|
258
|
+
}, encryptionConfig);
|
|
358
259
|
const decryptedData = await crypto.subtle.decrypt({
|
|
359
260
|
name: AES_GCM_ALGORITHM,
|
|
360
261
|
iv: ivBytes
|
|
361
262
|
}, key, cipherBytes);
|
|
362
263
|
return new TextDecoder().decode(decryptedData);
|
|
363
264
|
} catch (error) {
|
|
265
|
+
// For a short period of time we lowered the parallelism for v3 (Argon2) to 1 to try to fix issues
|
|
266
|
+
// for users with limited resources, however this introduced a new issue that the decryption would fail
|
|
267
|
+
// for existing users with v3 (Argon2) encryption, this is a fallback for a few users.
|
|
268
|
+
if (error instanceof Error && error.name === 'OperationError' && version === 'v3' && isArgon2Config(encryptionConfig)) {
|
|
269
|
+
try {
|
|
270
|
+
// Create a modified config with parallelism=1
|
|
271
|
+
const modifiedConfig = _extends({}, encryptionConfig, {
|
|
272
|
+
parallelism: 1
|
|
273
|
+
});
|
|
274
|
+
const key = await getKey({
|
|
275
|
+
password,
|
|
276
|
+
salt: saltBytes
|
|
277
|
+
}, modifiedConfig);
|
|
278
|
+
const decryptedData = await crypto.subtle.decrypt({
|
|
279
|
+
name: AES_GCM_ALGORITHM,
|
|
280
|
+
iv: ivBytes
|
|
281
|
+
}, key, cipherBytes);
|
|
282
|
+
return new TextDecoder().decode(decryptedData);
|
|
283
|
+
} catch (retryError) {
|
|
284
|
+
// If retry also fails, throw the original error with additional context
|
|
285
|
+
throw new Error(`Decryption failed after retry with parallelism=1: ${retryError}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
364
288
|
throw new Error('Decryption failed: ' + error);
|
|
365
289
|
}
|
|
366
290
|
};
|
|
@@ -368,17 +292,21 @@ const getKey = async ({ password, salt, encryptionConfig })=>{
|
|
|
368
292
|
* Gets encryption metadata for a specific version.
|
|
369
293
|
* Used when we need to include metadata in legacy systems or APIs that require it.
|
|
370
294
|
*/ const getEncryptionMetadataForVersion = (version)=>{
|
|
371
|
-
const encryptionConfig =
|
|
372
|
-
|
|
373
|
-
throw new Error(`Unsupported encryption version: ${version}`);
|
|
374
|
-
}
|
|
375
|
-
return {
|
|
295
|
+
const encryptionConfig = getEncryptionConfig(version);
|
|
296
|
+
const metadata = {
|
|
376
297
|
algorithm: encryptionConfig.algorithm,
|
|
377
298
|
keyDerivation: encryptionConfig.keyDerivation,
|
|
378
299
|
iterations: encryptionConfig.iterations,
|
|
379
300
|
hashAlgorithm: encryptionConfig.hashAlgorithm,
|
|
380
301
|
algorithmLength: encryptionConfig.algorithmLength
|
|
381
302
|
};
|
|
303
|
+
// Add Argon2-specific metadata if applicable
|
|
304
|
+
if (isArgon2Config(encryptionConfig)) {
|
|
305
|
+
metadata.memorySize = encryptionConfig.memorySize;
|
|
306
|
+
metadata.parallelism = encryptionConfig.parallelism;
|
|
307
|
+
metadata.hashLength = encryptionConfig.hashLength;
|
|
308
|
+
}
|
|
309
|
+
return metadata;
|
|
382
310
|
};
|
|
383
311
|
|
|
384
312
|
const GOOGLE_DRIVE_UPLOAD_API = 'https://www.googleapis.com';
|
|
@@ -477,6 +405,207 @@ const downloadFileFromGoogleDrive = async ({ accessToken, fileName })=>{
|
|
|
477
405
|
}
|
|
478
406
|
};
|
|
479
407
|
|
|
408
|
+
const handleAxiosError = (error, message, context)=>{
|
|
409
|
+
var _error_response, _error_response1, _error_response2;
|
|
410
|
+
logger.error('[DynamicWaasWalletClient] Axios error: ', {
|
|
411
|
+
message,
|
|
412
|
+
error: (_error_response = error.response) == null ? void 0 : _error_response.data,
|
|
413
|
+
status: (_error_response1 = error.response) == null ? void 0 : _error_response1.status,
|
|
414
|
+
context
|
|
415
|
+
});
|
|
416
|
+
switch((_error_response2 = error.response) == null ? void 0 : _error_response2.status){
|
|
417
|
+
case 400:
|
|
418
|
+
throw createHttpError(400, 'Invalid request');
|
|
419
|
+
case 401:
|
|
420
|
+
throw createHttpError(401, 'Authorization header or cookie is required');
|
|
421
|
+
case 403:
|
|
422
|
+
throw createHttpError(403, 'Forbidden');
|
|
423
|
+
case 422:
|
|
424
|
+
throw createHttpError(422, 'Unprocessable content');
|
|
425
|
+
case 500:
|
|
426
|
+
throw createHttpError(500, 'Internal server error');
|
|
427
|
+
default:
|
|
428
|
+
throw createHttpError(500, 'Internal server error');
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const logger = new logger$1.Logger('DynamicWaasWalletClient', logger$1.LogLevel.DEBUG);
|
|
433
|
+
const setLoggerContext = ({ environmentId, authMode = core.AuthMode.HEADER, sessionId = undefined, userId = undefined })=>{
|
|
434
|
+
try {
|
|
435
|
+
logger$1.Logger.setEnvironmentId(environmentId);
|
|
436
|
+
logger$1.Logger.globalMetaData.set('sid', sessionId);
|
|
437
|
+
logger$1.Logger.globalMetaData.set('user_id', userId);
|
|
438
|
+
logger$1.Logger.globalMetaData.set('auth_mode', authMode);
|
|
439
|
+
} catch (error) {
|
|
440
|
+
logError({
|
|
441
|
+
message: '[DynamicWaasWalletClient] Error setting logger context',
|
|
442
|
+
error: error,
|
|
443
|
+
context: {}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
const logError = ({ message, error, context })=>{
|
|
448
|
+
if (error instanceof axios.AxiosError) {
|
|
449
|
+
handleAxiosError(error, message, context);
|
|
450
|
+
}
|
|
451
|
+
logger.error('[DynamicWaasWalletClient] Error in browser client', {
|
|
452
|
+
error: error instanceof Error ? error.message : String(error),
|
|
453
|
+
context
|
|
454
|
+
});
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
const DEFAULT_LOG_LEVEL = logger$1.LogLevel.DEBUG; //todo: change back to info when done debugging
|
|
458
|
+
const STORAGE_KEY = 'dynamic-waas-wallet-client';
|
|
459
|
+
const CLIENT_KEYSHARE_EXPORT_FILENAME_PREFIX = 'dynamicWalletKeyShareBackup';
|
|
460
|
+
const SIGNED_SESSION_ID_MIN_VERSION = '4.25.4';
|
|
461
|
+
// Namespace-specific version requirements
|
|
462
|
+
const SIGNED_SESSION_ID_MIN_VERSION_BY_NAMESPACE = {
|
|
463
|
+
WalletKit: '4.25.4',
|
|
464
|
+
ClientSDK: '0.1.0-alpha.0'
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const isBrowser = ()=>typeof window !== 'undefined';
|
|
468
|
+
const getClientKeyShareExportFileName = ({ thresholdSignatureScheme, accountAddress })=>{
|
|
469
|
+
return `${CLIENT_KEYSHARE_EXPORT_FILENAME_PREFIX}-${thresholdSignatureScheme}-${accountAddress}.json`;
|
|
470
|
+
};
|
|
471
|
+
const getClientKeyShareBackupInfo = (params)=>{
|
|
472
|
+
var _params_walletProperties, _params_walletProperties_keyShares_;
|
|
473
|
+
const backups = {
|
|
474
|
+
[core.BackupLocation.DYNAMIC]: [],
|
|
475
|
+
[core.BackupLocation.GOOGLE_DRIVE]: [],
|
|
476
|
+
[core.BackupLocation.ICLOUD]: [],
|
|
477
|
+
[core.BackupLocation.USER]: [],
|
|
478
|
+
[core.BackupLocation.EXTERNAL]: []
|
|
479
|
+
};
|
|
480
|
+
if (!(params == null ? void 0 : (_params_walletProperties = params.walletProperties) == null ? void 0 : _params_walletProperties.keyShares)) {
|
|
481
|
+
return {
|
|
482
|
+
backups,
|
|
483
|
+
passwordEncrypted: false
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
params.walletProperties.keyShares.forEach((keyShare)=>{
|
|
487
|
+
if (backups[keyShare.backupLocation]) {
|
|
488
|
+
backups[keyShare.backupLocation].push({
|
|
489
|
+
location: keyShare.backupLocation,
|
|
490
|
+
keyShareId: keyShare.id,
|
|
491
|
+
externalKeyShareId: keyShare == null ? void 0 : keyShare.externalKeyShareId
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
const passwordEncrypted = Boolean((_params_walletProperties_keyShares_ = params.walletProperties.keyShares[0]) == null ? void 0 : _params_walletProperties_keyShares_.passwordEncrypted);
|
|
496
|
+
return {
|
|
497
|
+
backups,
|
|
498
|
+
passwordEncrypted
|
|
499
|
+
};
|
|
500
|
+
};
|
|
501
|
+
/**
|
|
502
|
+
* Helper function to merge keyshares and remove duplicates based on pubkey and secretShare
|
|
503
|
+
* @param existingKeyShares - Array of existing keyshares
|
|
504
|
+
* @param newKeyShares - Array of new keyshares to merge
|
|
505
|
+
* @returns Array of merged unique keyshares
|
|
506
|
+
*/ const mergeUniqueKeyShares = (existingKeyShares, newKeyShares)=>{
|
|
507
|
+
const uniqueKeyShares = newKeyShares.filter((newShare)=>!existingKeyShares.some((existingShare)=>{
|
|
508
|
+
if (!(newShare == null ? void 0 : newShare.pubkey) || !(existingShare == null ? void 0 : existingShare.pubkey)) return false;
|
|
509
|
+
return newShare.pubkey.toString() === existingShare.pubkey.toString() && newShare.secretShare === existingShare.secretShare;
|
|
510
|
+
}));
|
|
511
|
+
return [
|
|
512
|
+
...existingKeyShares,
|
|
513
|
+
...uniqueKeyShares
|
|
514
|
+
];
|
|
515
|
+
};
|
|
516
|
+
const timeoutPromise = ({ timeInMs, activity = 'Ceremony' })=>{
|
|
517
|
+
return new Promise((_, reject)=>setTimeout(()=>reject(new Error(`${activity} did not complete in ${timeInMs}ms`)), timeInMs));
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* Generic helper function to retry a promise-based operations
|
|
521
|
+
*
|
|
522
|
+
* @param operation - The async operation to retry
|
|
523
|
+
* @param config - Configuration options for retry behavior
|
|
524
|
+
* @returns Promise with the operation result
|
|
525
|
+
* @throws Last error encountered after all retries are exhausted
|
|
526
|
+
*/ async function retryPromise(operation, { maxAttempts = 5, retryInterval = 500, operationName = 'operation', logContext = {} } = {}) {
|
|
527
|
+
let attempts = 0;
|
|
528
|
+
while(attempts < maxAttempts){
|
|
529
|
+
try {
|
|
530
|
+
return await operation();
|
|
531
|
+
} catch (error) {
|
|
532
|
+
var _error_response;
|
|
533
|
+
attempts++;
|
|
534
|
+
logger.warn(`Failed to execute ${operationName} on attempt ${attempts}`, _extends({}, logContext, {
|
|
535
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
536
|
+
axiosError: error instanceof axios.AxiosError ? (_error_response = error.response) == null ? void 0 : _error_response.data : undefined
|
|
537
|
+
}));
|
|
538
|
+
if (attempts === maxAttempts) {
|
|
539
|
+
var _error_response1;
|
|
540
|
+
logger.error(`Failed to execute ${operationName} after ${maxAttempts} attempts`, _extends({}, logContext, {
|
|
541
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
542
|
+
axiosError: error instanceof axios.AxiosError ? (_error_response1 = error.response) == null ? void 0 : _error_response1.data : undefined
|
|
543
|
+
}));
|
|
544
|
+
throw error;
|
|
545
|
+
}
|
|
546
|
+
// Calculate exponential backoff delay
|
|
547
|
+
const exponentialDelay = retryInterval * 2 ** (attempts - 1);
|
|
548
|
+
await new Promise((resolve)=>setTimeout(resolve, exponentialDelay));
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
// TypeScript needs this even though it's unreachable
|
|
552
|
+
throw new Error('Unreachable code');
|
|
553
|
+
}
|
|
554
|
+
const formatEvmMessage = (message)=>{
|
|
555
|
+
if (typeof message === 'string' && message.startsWith('0x')) {
|
|
556
|
+
const serializedTxBytes = Uint8Array.from(Buffer.from(message.slice(2), 'hex'));
|
|
557
|
+
return web.MessageHash.keccak256(serializedTxBytes);
|
|
558
|
+
}
|
|
559
|
+
return web.MessageHash.keccak256(message);
|
|
560
|
+
};
|
|
561
|
+
const isHexString = (str)=>{
|
|
562
|
+
// Remove 0x prefix if present
|
|
563
|
+
const hex = str.startsWith('0x') ? str.slice(2) : str;
|
|
564
|
+
// Check if string contains only hex characters
|
|
565
|
+
return /^[0-9A-Fa-f]+$/.test(hex);
|
|
566
|
+
};
|
|
567
|
+
const formatSolanaMessage = (message)=>{
|
|
568
|
+
if (typeof message === 'string') {
|
|
569
|
+
if (!isHexString(message)) {
|
|
570
|
+
return Buffer.from(message).toString('hex');
|
|
571
|
+
} else {
|
|
572
|
+
return new Uint8Array(Buffer.from(message, 'hex'));
|
|
573
|
+
}
|
|
574
|
+
} else {
|
|
575
|
+
return message;
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
const formatMessage = (chainName, message)=>{
|
|
579
|
+
switch(chainName){
|
|
580
|
+
case 'EVM':
|
|
581
|
+
return formatEvmMessage(message);
|
|
582
|
+
case 'SVM':
|
|
583
|
+
return formatSolanaMessage(message);
|
|
584
|
+
case 'SUI':
|
|
585
|
+
return message;
|
|
586
|
+
default:
|
|
587
|
+
throw new Error('Unsupported chain name');
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
const getGoogleOAuthAccountId = (verifiedCredentials)=>{
|
|
591
|
+
const googleVerifiedCredential = verifiedCredentials == null ? void 0 : verifiedCredentials.find((credential)=>credential.oauthProvider === sdkApiCore.ProviderEnum.Google);
|
|
592
|
+
return googleVerifiedCredential == null ? void 0 : googleVerifiedCredential.id;
|
|
593
|
+
};
|
|
594
|
+
const createBackupData = ({ encryptedKeyShares, accountAddress, thresholdSignatureScheme, hasPassword = true })=>{
|
|
595
|
+
return {
|
|
596
|
+
keyShares: encryptedKeyShares,
|
|
597
|
+
metadata: {
|
|
598
|
+
createdAt: new Date().toISOString(),
|
|
599
|
+
accountAddress,
|
|
600
|
+
thresholdSignatureScheme,
|
|
601
|
+
hasPassword,
|
|
602
|
+
encryption: getEncryptionMetadataForVersion(ENCRYPTION_VERSION_CURRENT),
|
|
603
|
+
encryptionVersion: ENCRYPTION_VERSION_CURRENT,
|
|
604
|
+
shareCount: encryptedKeyShares.length
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
};
|
|
608
|
+
|
|
480
609
|
/**
|
|
481
610
|
* Uploads a backup to Google Drive App
|
|
482
611
|
* @param accessToken - The access token for the Google Drive API
|
|
@@ -656,7 +785,7 @@ class DynamicWalletClient {
|
|
|
656
785
|
this.sessionId = sessionId;
|
|
657
786
|
} catch (error) {
|
|
658
787
|
logError({
|
|
659
|
-
message: '
|
|
788
|
+
message: 'Error initializing logger context',
|
|
660
789
|
error: error,
|
|
661
790
|
context: {}
|
|
662
791
|
});
|
|
@@ -813,7 +942,7 @@ class DynamicWalletClient {
|
|
|
813
942
|
};
|
|
814
943
|
} catch (error) {
|
|
815
944
|
logError({
|
|
816
|
-
message: '
|
|
945
|
+
message: 'Error in keyGen',
|
|
817
946
|
error: error,
|
|
818
947
|
context: {
|
|
819
948
|
chainName,
|
|
@@ -893,7 +1022,7 @@ class DynamicWalletClient {
|
|
|
893
1022
|
};
|
|
894
1023
|
} catch (error) {
|
|
895
1024
|
logError({
|
|
896
|
-
message: '
|
|
1025
|
+
message: 'Error in importRawPrivateKey',
|
|
897
1026
|
error: error,
|
|
898
1027
|
context: {
|
|
899
1028
|
chainName,
|
|
@@ -904,7 +1033,7 @@ class DynamicWalletClient {
|
|
|
904
1033
|
throw error;
|
|
905
1034
|
}
|
|
906
1035
|
}
|
|
907
|
-
async serverSign({ walletId, message, isFormatted, mfaToken, context, onError }) {
|
|
1036
|
+
async serverSign({ walletId, message, isFormatted, mfaToken, context, onError, dynamicRequestId }) {
|
|
908
1037
|
// Create the room and sign the message
|
|
909
1038
|
if (typeof message !== 'string') {
|
|
910
1039
|
message = `0x${Buffer.from(message).toString('hex')}`;
|
|
@@ -913,14 +1042,14 @@ class DynamicWalletClient {
|
|
|
913
1042
|
walletId,
|
|
914
1043
|
message,
|
|
915
1044
|
isFormatted,
|
|
916
|
-
dynamicRequestId
|
|
1045
|
+
dynamicRequestId,
|
|
917
1046
|
mfaToken,
|
|
918
1047
|
context: context ? JSON.parse(JSON.stringify(context, (_key, value)=>typeof value === 'bigint' ? value.toString() : value)) : undefined,
|
|
919
1048
|
onError
|
|
920
1049
|
});
|
|
921
1050
|
return data;
|
|
922
1051
|
}
|
|
923
|
-
async clientSign({ chainName, message, roomId, keyShare, derivationPath, isFormatted }) {
|
|
1052
|
+
async clientSign({ chainName, message, roomId, keyShare, derivationPath, isFormatted, dynamicRequestId }) {
|
|
924
1053
|
try {
|
|
925
1054
|
const mpcSigner = getMPCSigner({
|
|
926
1055
|
chainName,
|
|
@@ -938,13 +1067,14 @@ class DynamicWalletClient {
|
|
|
938
1067
|
return signature;
|
|
939
1068
|
} catch (error) {
|
|
940
1069
|
logError({
|
|
941
|
-
message: '
|
|
1070
|
+
message: 'Error in clientSign',
|
|
942
1071
|
error: error,
|
|
943
1072
|
context: {
|
|
944
1073
|
chainName,
|
|
945
1074
|
roomId,
|
|
946
1075
|
derivationPath,
|
|
947
|
-
isFormatted
|
|
1076
|
+
isFormatted,
|
|
1077
|
+
dynamicRequestId
|
|
948
1078
|
}
|
|
949
1079
|
});
|
|
950
1080
|
throw error;
|
|
@@ -952,6 +1082,7 @@ class DynamicWalletClient {
|
|
|
952
1082
|
}
|
|
953
1083
|
//todo: need to modify with imported flag
|
|
954
1084
|
async sign({ accountAddress, message, chainName, password = undefined, isFormatted = false, signedSessionId, mfaToken, context, onError }) {
|
|
1085
|
+
const dynamicRequestId = uuid.v4();
|
|
955
1086
|
try {
|
|
956
1087
|
await this.verifyPassword({
|
|
957
1088
|
accountAddress,
|
|
@@ -972,13 +1103,15 @@ class DynamicWalletClient {
|
|
|
972
1103
|
isFormatted,
|
|
973
1104
|
mfaToken,
|
|
974
1105
|
context,
|
|
975
|
-
onError
|
|
1106
|
+
onError,
|
|
1107
|
+
dynamicRequestId
|
|
976
1108
|
});
|
|
977
1109
|
this.logger.debug('[DynamicWaasWalletClient] Server sign completed', {
|
|
978
1110
|
message,
|
|
979
1111
|
accountAddress,
|
|
980
1112
|
walletId: wallet.walletId,
|
|
981
|
-
roomId: data.roomId
|
|
1113
|
+
roomId: data.roomId,
|
|
1114
|
+
dynamicRequestId
|
|
982
1115
|
});
|
|
983
1116
|
const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
|
|
984
1117
|
// Perform the client sign and return the signature
|
|
@@ -991,7 +1124,8 @@ class DynamicWalletClient {
|
|
|
991
1124
|
roomId: data.roomId,
|
|
992
1125
|
keyShare: clientKeyShares[0],
|
|
993
1126
|
derivationPath,
|
|
994
|
-
isFormatted
|
|
1127
|
+
isFormatted,
|
|
1128
|
+
dynamicRequestId
|
|
995
1129
|
});
|
|
996
1130
|
this.logger.debug('[DynamicWaasWalletClient] Client sign completed', {
|
|
997
1131
|
chainName,
|
|
@@ -1003,12 +1137,13 @@ class DynamicWalletClient {
|
|
|
1003
1137
|
return signature;
|
|
1004
1138
|
} catch (error) {
|
|
1005
1139
|
logError({
|
|
1006
|
-
message: '
|
|
1140
|
+
message: 'Error in sign',
|
|
1007
1141
|
error: error,
|
|
1008
1142
|
context: {
|
|
1009
1143
|
accountAddress,
|
|
1010
1144
|
chainName,
|
|
1011
|
-
isFormatted: isFormatted ? 'true' : 'false'
|
|
1145
|
+
isFormatted: isFormatted ? 'true' : 'false',
|
|
1146
|
+
dynamicRequestId
|
|
1012
1147
|
}
|
|
1013
1148
|
});
|
|
1014
1149
|
throw error;
|
|
@@ -1056,7 +1191,7 @@ class DynamicWalletClient {
|
|
|
1056
1191
|
});
|
|
1057
1192
|
} catch (error) {
|
|
1058
1193
|
logError({
|
|
1059
|
-
message: '
|
|
1194
|
+
message: 'Error in refreshWalletAccountShares',
|
|
1060
1195
|
error: error,
|
|
1061
1196
|
context: {
|
|
1062
1197
|
accountAddress,
|
|
@@ -1200,7 +1335,7 @@ class DynamicWalletClient {
|
|
|
1200
1335
|
}
|
|
1201
1336
|
} catch (error) {
|
|
1202
1337
|
logError({
|
|
1203
|
-
message: '
|
|
1338
|
+
message: 'Error in reshare',
|
|
1204
1339
|
error: error,
|
|
1205
1340
|
context: {
|
|
1206
1341
|
accountAddress,
|
|
@@ -1235,7 +1370,7 @@ class DynamicWalletClient {
|
|
|
1235
1370
|
return data;
|
|
1236
1371
|
} catch (error) {
|
|
1237
1372
|
logError({
|
|
1238
|
-
message: '
|
|
1373
|
+
message: 'Error in sendKeySharesToDelegatedAccess',
|
|
1239
1374
|
error: error,
|
|
1240
1375
|
context: {
|
|
1241
1376
|
accountAddress,
|
|
@@ -1288,7 +1423,7 @@ class DynamicWalletClient {
|
|
|
1288
1423
|
}
|
|
1289
1424
|
} catch (error) {
|
|
1290
1425
|
logError({
|
|
1291
|
-
message: '
|
|
1426
|
+
message: 'Error in delegateKeyShares',
|
|
1292
1427
|
error: error,
|
|
1293
1428
|
context: {
|
|
1294
1429
|
accountAddress
|
|
@@ -1355,7 +1490,7 @@ class DynamicWalletClient {
|
|
|
1355
1490
|
};
|
|
1356
1491
|
} catch (error) {
|
|
1357
1492
|
logError({
|
|
1358
|
-
message: '
|
|
1493
|
+
message: 'Error in exportKey',
|
|
1359
1494
|
error: error,
|
|
1360
1495
|
context: {
|
|
1361
1496
|
accountAddress,
|
|
@@ -1403,7 +1538,7 @@ class DynamicWalletClient {
|
|
|
1403
1538
|
};
|
|
1404
1539
|
} catch (error) {
|
|
1405
1540
|
logError({
|
|
1406
|
-
message: '
|
|
1541
|
+
message: 'Error in offlineExportKey',
|
|
1407
1542
|
error: error,
|
|
1408
1543
|
context: {
|
|
1409
1544
|
chainName
|
|
@@ -1441,7 +1576,7 @@ class DynamicWalletClient {
|
|
|
1441
1576
|
return (parsedWalletObject == null ? void 0 : parsedWalletObject.clientKeyShares) || [];
|
|
1442
1577
|
} catch (error) {
|
|
1443
1578
|
logError({
|
|
1444
|
-
message: `
|
|
1579
|
+
message: `Error parsing clientKeyShares: Error for accountAddress:`,
|
|
1445
1580
|
error: error,
|
|
1446
1581
|
context: {
|
|
1447
1582
|
accountAddress
|
|
@@ -1488,6 +1623,7 @@ class DynamicWalletClient {
|
|
|
1488
1623
|
* @param params.backupToGoogleDrive - Whether to backup to Google Drive (defaults to false)
|
|
1489
1624
|
* @returns Promise with backup metadata including share locations and IDs
|
|
1490
1625
|
*/ async storeEncryptedBackupByWallet({ accountAddress, clientKeyShares = undefined, password = undefined, signedSessionId, backupToGoogleDrive = false }) {
|
|
1626
|
+
const dynamicRequestId = uuid.v4();
|
|
1491
1627
|
try {
|
|
1492
1628
|
var _this_walletMap_accountAddress, _this_walletMap_accountAddress_clientKeySharesBackupInfo_backups_BackupLocation_GOOGLE_DRIVE, _this_walletMap_accountAddress_clientKeySharesBackupInfo_backups, _this_walletMap_accountAddress_clientKeySharesBackupInfo, _this_walletMap_accountAddress1;
|
|
1493
1629
|
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
@@ -1496,7 +1632,7 @@ class DynamicWalletClient {
|
|
|
1496
1632
|
if (!((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.walletId)) {
|
|
1497
1633
|
const error = new Error(`WalletId not found for accountAddress ${accountAddress}`);
|
|
1498
1634
|
logError({
|
|
1499
|
-
message: '
|
|
1635
|
+
message: 'Error in storeEncryptedBackupByWallet, wallet or walletId not found from the wallet map',
|
|
1500
1636
|
error,
|
|
1501
1637
|
context: {
|
|
1502
1638
|
accountAddress,
|
|
@@ -1533,7 +1669,8 @@ class DynamicWalletClient {
|
|
|
1533
1669
|
encryptionVersion: ENCRYPTION_VERSION_CURRENT,
|
|
1534
1670
|
signedSessionId,
|
|
1535
1671
|
authMode: this.authMode,
|
|
1536
|
-
requiresSignedSessionId: this.requiresSignedSessionId()
|
|
1672
|
+
requiresSignedSessionId: this.requiresSignedSessionId(),
|
|
1673
|
+
dynamicRequestId
|
|
1537
1674
|
});
|
|
1538
1675
|
if (data.keyShareIds.length === 0) {
|
|
1539
1676
|
throw new Error('No key shares were backed up');
|
|
@@ -1555,7 +1692,8 @@ class DynamicWalletClient {
|
|
|
1555
1692
|
}
|
|
1556
1693
|
const backupData = await this.apiClient.markKeySharesAsBackedUp({
|
|
1557
1694
|
walletId: this.walletMap[accountAddress].walletId,
|
|
1558
|
-
locations
|
|
1695
|
+
locations,
|
|
1696
|
+
dynamicRequestId
|
|
1559
1697
|
});
|
|
1560
1698
|
const updatedBackupInfo = getClientKeyShareBackupInfo({
|
|
1561
1699
|
walletProperties: {
|
|
@@ -1576,16 +1714,18 @@ class DynamicWalletClient {
|
|
|
1576
1714
|
return data;
|
|
1577
1715
|
} catch (error) {
|
|
1578
1716
|
logError({
|
|
1579
|
-
message: '
|
|
1717
|
+
message: 'Error in storeEncryptedBackupByWallet',
|
|
1580
1718
|
error: error,
|
|
1581
1719
|
context: {
|
|
1582
|
-
accountAddress
|
|
1720
|
+
accountAddress,
|
|
1721
|
+
dynamicRequestId
|
|
1583
1722
|
}
|
|
1584
1723
|
});
|
|
1585
1724
|
throw error;
|
|
1586
1725
|
}
|
|
1587
1726
|
}
|
|
1588
1727
|
async storeEncryptedBackupByDelegatedWallet({ accountAddress, clientKeyShares = undefined, password = undefined, signedSessionId }) {
|
|
1728
|
+
const dynamicRequestId = uuid.v4();
|
|
1589
1729
|
try {
|
|
1590
1730
|
var _this_walletMap_accountAddress, _this_walletMap_accountAddress_clientKeySharesBackupInfo_backups_BackupLocation_EXTERNAL, _this_walletMap_accountAddress_clientKeySharesBackupInfo_backups, _this_walletMap_accountAddress_clientKeySharesBackupInfo, _this_walletMap_accountAddress1;
|
|
1591
1731
|
const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
|
|
@@ -1594,7 +1734,7 @@ class DynamicWalletClient {
|
|
|
1594
1734
|
if (!((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.walletId)) {
|
|
1595
1735
|
const error = new Error(`WalletId not found for accountAddress ${accountAddress}`);
|
|
1596
1736
|
logError({
|
|
1597
|
-
message: '
|
|
1737
|
+
message: 'Error in storeEncryptedBackupByWallet, wallet or walletId not found from the wallet map',
|
|
1598
1738
|
error,
|
|
1599
1739
|
context: {
|
|
1600
1740
|
accountAddress,
|
|
@@ -1626,10 +1766,12 @@ class DynamicWalletClient {
|
|
|
1626
1766
|
encryptionVersion: ENCRYPTION_VERSION_CURRENT,
|
|
1627
1767
|
signedSessionId,
|
|
1628
1768
|
authMode: this.authMode,
|
|
1629
|
-
requiresSignedSessionId: this.requiresSignedSessionId()
|
|
1769
|
+
requiresSignedSessionId: this.requiresSignedSessionId(),
|
|
1770
|
+
dynamicRequestId
|
|
1630
1771
|
});
|
|
1631
1772
|
await this.apiClient.markKeySharesAsBackedUp({
|
|
1632
1773
|
walletId: this.walletMap[accountAddress].walletId,
|
|
1774
|
+
dynamicRequestId,
|
|
1633
1775
|
locations: [
|
|
1634
1776
|
{
|
|
1635
1777
|
location: core.BackupLocation.DYNAMIC
|
|
@@ -1658,7 +1800,8 @@ class DynamicWalletClient {
|
|
|
1658
1800
|
{
|
|
1659
1801
|
location: core.BackupLocation.EXTERNAL
|
|
1660
1802
|
}
|
|
1661
|
-
]
|
|
1803
|
+
],
|
|
1804
|
+
dynamicRequestId
|
|
1662
1805
|
});
|
|
1663
1806
|
}
|
|
1664
1807
|
const updatedBackupInfo = getClientKeyShareBackupInfo({
|
|
@@ -1675,10 +1818,11 @@ class DynamicWalletClient {
|
|
|
1675
1818
|
return data;
|
|
1676
1819
|
} catch (error) {
|
|
1677
1820
|
logError({
|
|
1678
|
-
message: '
|
|
1821
|
+
message: 'Error in storeEncryptedBackupByDelegatedWallet',
|
|
1679
1822
|
error: error,
|
|
1680
1823
|
context: {
|
|
1681
|
-
accountAddress
|
|
1824
|
+
accountAddress,
|
|
1825
|
+
dynamicRequestId
|
|
1682
1826
|
}
|
|
1683
1827
|
});
|
|
1684
1828
|
throw error;
|
|
@@ -1725,8 +1869,9 @@ class DynamicWalletClient {
|
|
|
1725
1869
|
* @returns The Google OAuth Account ID
|
|
1726
1870
|
* @throws Error if no Google OAuth account ID is found
|
|
1727
1871
|
*/ async getGoogleOauthAccountIdOrThrow(accountAddress) {
|
|
1872
|
+
const dynamicRequestId = uuid.v4();
|
|
1728
1873
|
try {
|
|
1729
|
-
const user = await this.apiClient.getUser();
|
|
1874
|
+
const user = await this.apiClient.getUser(dynamicRequestId);
|
|
1730
1875
|
const oauthAccountId = getGoogleOAuthAccountId(user == null ? void 0 : user.verifiedCredentials);
|
|
1731
1876
|
if (!oauthAccountId) {
|
|
1732
1877
|
const error = new Error('No Google OAuth account ID found');
|
|
@@ -1743,10 +1888,11 @@ class DynamicWalletClient {
|
|
|
1743
1888
|
return oauthAccountId;
|
|
1744
1889
|
} catch (error) {
|
|
1745
1890
|
logError({
|
|
1746
|
-
message: '
|
|
1891
|
+
message: 'Error in getGoogleOauthAccountIdOrThrow',
|
|
1747
1892
|
error: error,
|
|
1748
1893
|
context: {
|
|
1749
|
-
accountAddress
|
|
1894
|
+
accountAddress,
|
|
1895
|
+
dynamicRequestId
|
|
1750
1896
|
}
|
|
1751
1897
|
});
|
|
1752
1898
|
throw error;
|
|
@@ -1816,7 +1962,7 @@ class DynamicWalletClient {
|
|
|
1816
1962
|
return decryptedKeyShares;
|
|
1817
1963
|
} catch (error) {
|
|
1818
1964
|
logError({
|
|
1819
|
-
message: '
|
|
1965
|
+
message: 'Error in recoverEncryptedBackupByWallet',
|
|
1820
1966
|
error: error,
|
|
1821
1967
|
context: {
|
|
1822
1968
|
accountAddress,
|
|
@@ -1882,7 +2028,7 @@ class DynamicWalletClient {
|
|
|
1882
2028
|
}
|
|
1883
2029
|
} catch (error) {
|
|
1884
2030
|
logError({
|
|
1885
|
-
message: '
|
|
2031
|
+
message: 'Error in backupKeySharesToGoogleDrive',
|
|
1886
2032
|
error: error,
|
|
1887
2033
|
context: {
|
|
1888
2034
|
accountAddress
|
|
@@ -1930,7 +2076,7 @@ class DynamicWalletClient {
|
|
|
1930
2076
|
return;
|
|
1931
2077
|
} catch (error) {
|
|
1932
2078
|
logError({
|
|
1933
|
-
message: '
|
|
2079
|
+
message: 'Error in backupKeySharesToGoogleDrive',
|
|
1934
2080
|
error: error,
|
|
1935
2081
|
context: {
|
|
1936
2082
|
accountAddress
|
|
@@ -1962,7 +2108,7 @@ class DynamicWalletClient {
|
|
|
1962
2108
|
}));
|
|
1963
2109
|
} catch (error) {
|
|
1964
2110
|
logError({
|
|
1965
|
-
message: '
|
|
2111
|
+
message: 'Failed to download backup from Google Drive',
|
|
1966
2112
|
error: error,
|
|
1967
2113
|
context: {
|
|
1968
2114
|
accountAddress,
|
|
@@ -1974,7 +2120,7 @@ class DynamicWalletClient {
|
|
|
1974
2120
|
if (!backupData) {
|
|
1975
2121
|
const error = new Error('No backup file found');
|
|
1976
2122
|
logError({
|
|
1977
|
-
message: '
|
|
2123
|
+
message: 'No backup file found',
|
|
1978
2124
|
error: new Error('No backup file found'),
|
|
1979
2125
|
context: {
|
|
1980
2126
|
accountAddress,
|
|
@@ -1987,7 +2133,7 @@ class DynamicWalletClient {
|
|
|
1987
2133
|
if (!backupData.keyShares || !backupData.metadata) {
|
|
1988
2134
|
const error = new Error('Invalid backup format: missing keyShares or metadata');
|
|
1989
2135
|
logError({
|
|
1990
|
-
message: '
|
|
2136
|
+
message: 'Invalid backup format: missing keyShares or metadata',
|
|
1991
2137
|
error,
|
|
1992
2138
|
context: {
|
|
1993
2139
|
accountAddress,
|
|
@@ -2009,7 +2155,7 @@ class DynamicWalletClient {
|
|
|
2009
2155
|
return decryptedKeyShares;
|
|
2010
2156
|
} catch (error) {
|
|
2011
2157
|
logError({
|
|
2012
|
-
message: '
|
|
2158
|
+
message: 'Error in restoreBackupFromGoogleDrive',
|
|
2013
2159
|
error: error,
|
|
2014
2160
|
context: {
|
|
2015
2161
|
accountAddress
|
|
@@ -2141,7 +2287,7 @@ class DynamicWalletClient {
|
|
|
2141
2287
|
});
|
|
2142
2288
|
} catch (error) {
|
|
2143
2289
|
logError({
|
|
2144
|
-
message: '
|
|
2290
|
+
message: 'Error in verifyPassword',
|
|
2145
2291
|
error: error,
|
|
2146
2292
|
context: {
|
|
2147
2293
|
accountAddress
|
|
@@ -2193,6 +2339,7 @@ class DynamicWalletClient {
|
|
|
2193
2339
|
return true;
|
|
2194
2340
|
}
|
|
2195
2341
|
async getWalletClientKeyShareBackupInfo({ accountAddress }) {
|
|
2342
|
+
const dynamicRequestId = uuid.v4();
|
|
2196
2343
|
try {
|
|
2197
2344
|
var _this_walletMap_accountAddress_clientKeySharesBackupInfo_backups_BackupLocation_DYNAMIC, _this_walletMap_accountAddress_clientKeySharesBackupInfo_backups, _this_walletMap_accountAddress_clientKeySharesBackupInfo, _this_walletMap_accountAddress, _user_verifiedCredentials;
|
|
2198
2345
|
// Return existing backup info if it exists
|
|
@@ -2200,23 +2347,25 @@ class DynamicWalletClient {
|
|
|
2200
2347
|
return this.walletMap[accountAddress].clientKeySharesBackupInfo;
|
|
2201
2348
|
}
|
|
2202
2349
|
// Get backup info from server
|
|
2203
|
-
const user = await this.apiClient.getUser();
|
|
2350
|
+
const user = await this.apiClient.getUser(dynamicRequestId);
|
|
2204
2351
|
const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
|
|
2205
2352
|
return getClientKeyShareBackupInfo({
|
|
2206
2353
|
walletProperties: wallet == null ? void 0 : wallet.walletProperties
|
|
2207
2354
|
});
|
|
2208
2355
|
} catch (error) {
|
|
2209
2356
|
logError({
|
|
2210
|
-
message: '
|
|
2357
|
+
message: 'Error in getWalletClientKeyShareBackupInfo',
|
|
2211
2358
|
error: error,
|
|
2212
2359
|
context: {
|
|
2213
|
-
accountAddress
|
|
2360
|
+
accountAddress,
|
|
2361
|
+
dynamicRequestId
|
|
2214
2362
|
}
|
|
2215
2363
|
});
|
|
2216
2364
|
throw error;
|
|
2217
2365
|
}
|
|
2218
2366
|
}
|
|
2219
2367
|
async getWallet({ accountAddress, walletOperation = core.WalletOperation.NO_OPERATION, shareCount = undefined, password = undefined, signedSessionId }) {
|
|
2368
|
+
const dynamicRequestId = uuid.v4();
|
|
2220
2369
|
try {
|
|
2221
2370
|
var _user_verifiedCredentials;
|
|
2222
2371
|
const existingWalletCheck = await this.checkWalletFields({
|
|
@@ -2229,7 +2378,7 @@ class DynamicWalletClient {
|
|
|
2229
2378
|
return this.walletMap[accountAddress];
|
|
2230
2379
|
}
|
|
2231
2380
|
// Fetch and restore wallet from server
|
|
2232
|
-
const user = await this.apiClient.getUser();
|
|
2381
|
+
const user = await this.apiClient.getUser(dynamicRequestId);
|
|
2233
2382
|
const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
|
|
2234
2383
|
this.logger.debug('[DynamicWaasWalletClient] Restoring wallet', wallet);
|
|
2235
2384
|
const walletProperties = wallet.walletProperties;
|
|
@@ -2275,21 +2424,23 @@ class DynamicWalletClient {
|
|
|
2275
2424
|
return this.walletMap[accountAddress];
|
|
2276
2425
|
} catch (error) {
|
|
2277
2426
|
logError({
|
|
2278
|
-
message: '
|
|
2427
|
+
message: 'Error in getWallet',
|
|
2279
2428
|
error: error,
|
|
2280
2429
|
context: {
|
|
2281
2430
|
accountAddress,
|
|
2282
2431
|
walletOperation,
|
|
2283
|
-
shareCount
|
|
2432
|
+
shareCount,
|
|
2433
|
+
dynamicRequestId
|
|
2284
2434
|
}
|
|
2285
2435
|
});
|
|
2286
2436
|
throw error;
|
|
2287
2437
|
}
|
|
2288
2438
|
}
|
|
2289
2439
|
async getWallets() {
|
|
2440
|
+
const dynamicRequestId = uuid.v4();
|
|
2290
2441
|
try {
|
|
2291
2442
|
var _user_verifiedCredentials;
|
|
2292
|
-
const user = await this.apiClient.getUser();
|
|
2443
|
+
const user = await this.apiClient.getUser(dynamicRequestId);
|
|
2293
2444
|
this.userId = user.id;
|
|
2294
2445
|
const waasWallets = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.filter((vc)=>vc.walletName === 'dynamicwaas');
|
|
2295
2446
|
const wallets = waasWallets.map((vc)=>{
|
|
@@ -2322,9 +2473,11 @@ class DynamicWalletClient {
|
|
|
2322
2473
|
return wallets;
|
|
2323
2474
|
} catch (error) {
|
|
2324
2475
|
logError({
|
|
2325
|
-
message: '
|
|
2476
|
+
message: 'Error in getWallets',
|
|
2326
2477
|
error: error,
|
|
2327
|
-
context: {
|
|
2478
|
+
context: {
|
|
2479
|
+
dynamicRequestId
|
|
2480
|
+
}
|
|
2328
2481
|
});
|
|
2329
2482
|
throw error;
|
|
2330
2483
|
}
|
|
@@ -2455,10 +2608,7 @@ exports.ERROR_SIGN_MESSAGE = ERROR_SIGN_MESSAGE;
|
|
|
2455
2608
|
exports.ERROR_SIGN_TYPED_DATA = ERROR_SIGN_TYPED_DATA;
|
|
2456
2609
|
exports.ERROR_VERIFY_MESSAGE_SIGNATURE = ERROR_VERIFY_MESSAGE_SIGNATURE;
|
|
2457
2610
|
exports.ERROR_VERIFY_TRANSACTION_SIGNATURE = ERROR_VERIFY_TRANSACTION_SIGNATURE;
|
|
2458
|
-
exports.base64ToBytes = base64ToBytes;
|
|
2459
|
-
exports.bytesToBase64 = bytesToBase64;
|
|
2460
2611
|
exports.createBackupData = createBackupData;
|
|
2461
|
-
exports.ensureBase64Padding = ensureBase64Padding;
|
|
2462
2612
|
exports.formatEvmMessage = formatEvmMessage;
|
|
2463
2613
|
exports.formatMessage = formatMessage;
|
|
2464
2614
|
exports.getClientKeyShareBackupInfo = getClientKeyShareBackupInfo;
|
|
@@ -2470,7 +2620,6 @@ exports.isBrowser = isBrowser;
|
|
|
2470
2620
|
exports.isHexString = isHexString;
|
|
2471
2621
|
exports.mergeUniqueKeyShares = mergeUniqueKeyShares;
|
|
2472
2622
|
exports.retryPromise = retryPromise;
|
|
2473
|
-
exports.stringToBytes = stringToBytes;
|
|
2474
2623
|
exports.timeoutPromise = timeoutPromise;
|
|
2475
2624
|
Object.keys(core).forEach(function (k) {
|
|
2476
2625
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|