@dynamic-labs-wallet/node 1.1.34 → 1.1.36
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 +319 -71
- package/index.esm.js +320 -73
- package/package.json +3 -3
- package/src/client.d.ts +10 -5
- package/src/client.d.ts.map +1 -1
- package/src/clientValidationError.d.ts +4 -0
- package/src/clientValidationError.d.ts.map +1 -0
- package/src/index.d.ts +1 -0
- package/src/index.d.ts.map +1 -1
- package/src/observability/createErrorForwardingLogger.d.ts +1 -23
- package/src/observability/createErrorForwardingLogger.d.ts.map +1 -1
- package/src/observability/errorTelemetry.d.ts +29 -0
- package/src/observability/errorTelemetry.d.ts.map +1 -0
- package/src/utils.d.ts.map +1 -1
- package/src/version.d.ts +2 -0
- package/src/version.d.ts.map +1 -0
package/index.cjs
CHANGED
|
@@ -10,6 +10,13 @@ var crypto = require('node:crypto');
|
|
|
10
10
|
var logger = require('@dynamic-labs/logger');
|
|
11
11
|
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
12
12
|
|
|
13
|
+
class ClientValidationError extends TypeError {
|
|
14
|
+
constructor(message, options){
|
|
15
|
+
super(message, options);
|
|
16
|
+
this.name = 'ClientValidationError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
// Removed duplicate exports - these are already exported from #internal/core
|
|
14
21
|
const getMPCSignatureScheme = ({ signingAlgorithm, baseRelayUrl = core$1.MPC_RELAY_PROD_API_URL, variant = core$1.DEFAULT_ED25519_VARIANT })=>{
|
|
15
22
|
switch(signingAlgorithm){
|
|
@@ -81,6 +88,180 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
81
88
|
}
|
|
82
89
|
}
|
|
83
90
|
|
|
91
|
+
var version = "1.1.36";
|
|
92
|
+
|
|
93
|
+
const MAX_CAUSE_CHAIN_LENGTH = 4;
|
|
94
|
+
const SAFE_ERROR_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/;
|
|
95
|
+
const TRANSPORT_ERROR_CODES = new Set([
|
|
96
|
+
'EAI_AGAIN',
|
|
97
|
+
'ECONNREFUSED',
|
|
98
|
+
'ECONNRESET',
|
|
99
|
+
'EHOSTUNREACH',
|
|
100
|
+
'ENETUNREACH',
|
|
101
|
+
'ETIMEDOUT',
|
|
102
|
+
'UND_ERR_CONNECT_TIMEOUT'
|
|
103
|
+
]);
|
|
104
|
+
const getSafeErrorName = (error)=>SAFE_ERROR_NAME_PATTERN.test(error.name) ? error.name : 'Error';
|
|
105
|
+
const normalizeContext = (context)=>{
|
|
106
|
+
const backendReached = context == null ? void 0 : context['backendReached'];
|
|
107
|
+
const dynamicRequestId = context == null ? void 0 : context['dynamicRequestId'];
|
|
108
|
+
const failurePhase = context == null ? void 0 : context['failurePhase'];
|
|
109
|
+
const traceId = context == null ? void 0 : context['traceId'];
|
|
110
|
+
return _extends({}, typeof backendReached === 'boolean' ? {
|
|
111
|
+
backendReached
|
|
112
|
+
} : {}, typeof dynamicRequestId === 'string' ? {
|
|
113
|
+
dynamicRequestId
|
|
114
|
+
} : {}, typeof failurePhase === 'string' ? {
|
|
115
|
+
failurePhase
|
|
116
|
+
} : {}, typeof traceId === 'string' ? {
|
|
117
|
+
traceId
|
|
118
|
+
} : {});
|
|
119
|
+
};
|
|
120
|
+
const getHeader = (error, name)=>{
|
|
121
|
+
var _error_config;
|
|
122
|
+
const headers = (_error_config = error.config) == null ? void 0 : _error_config.headers;
|
|
123
|
+
if (!headers) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
const get = headers.get;
|
|
127
|
+
let value;
|
|
128
|
+
if (typeof get === 'function') {
|
|
129
|
+
value = get.call(headers, name);
|
|
130
|
+
} else {
|
|
131
|
+
const headerRecord = headers;
|
|
132
|
+
const matchingKey = Object.keys(headerRecord).find((key)=>key.toLowerCase() === name.toLowerCase());
|
|
133
|
+
value = matchingKey ? headerRecord[matchingKey] : undefined;
|
|
134
|
+
}
|
|
135
|
+
return typeof value === 'string' ? value : undefined;
|
|
136
|
+
};
|
|
137
|
+
const getSafeRequestUrl = (error)=>{
|
|
138
|
+
var _error_config;
|
|
139
|
+
const requestUrl = (_error_config = error.config) == null ? void 0 : _error_config.url;
|
|
140
|
+
if (!requestUrl) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
var _error_config1;
|
|
145
|
+
const url = new URL(requestUrl, (_error_config1 = error.config) == null ? void 0 : _error_config1.baseURL);
|
|
146
|
+
return url.protocol === 'https:' || url.protocol === 'http:' ? url.origin : undefined;
|
|
147
|
+
} catch (e) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const getErrorCauseChain = (error)=>{
|
|
152
|
+
const chain = [];
|
|
153
|
+
const visited = new Set();
|
|
154
|
+
let current = error instanceof Error ? error : undefined;
|
|
155
|
+
while(current && chain.length < MAX_CAUSE_CHAIN_LENGTH && !visited.has(current)){
|
|
156
|
+
chain.push(current);
|
|
157
|
+
visited.add(current);
|
|
158
|
+
current = current.cause instanceof Error ? current.cause : undefined;
|
|
159
|
+
}
|
|
160
|
+
return chain;
|
|
161
|
+
};
|
|
162
|
+
const serializeError = (error)=>{
|
|
163
|
+
let serialized;
|
|
164
|
+
for (const current of getErrorCauseChain(error).reverse()){
|
|
165
|
+
serialized = _extends({
|
|
166
|
+
name: getSafeErrorName(current)
|
|
167
|
+
}, serialized ? {
|
|
168
|
+
cause: serialized
|
|
169
|
+
} : {});
|
|
170
|
+
}
|
|
171
|
+
return serialized != null ? serialized : {
|
|
172
|
+
name: 'Error'
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
const findErrorInCauseChain = (error, predicate)=>getErrorCauseChain(error).find(predicate);
|
|
176
|
+
const isWalletApiError = (error)=>error instanceof core$1.WalletApiError;
|
|
177
|
+
const isClientValidationErrorInstance = (error)=>error instanceof ClientValidationError;
|
|
178
|
+
const isAxiosErrorInstance = (error)=>core$1.isAxiosError(error);
|
|
179
|
+
const hasTransportErrorCode = (error)=>{
|
|
180
|
+
const code = error.code;
|
|
181
|
+
return typeof code === 'string' && TRANSPORT_ERROR_CODES.has(code);
|
|
182
|
+
};
|
|
183
|
+
const getHttpFailureCategory = (statusCode, isServerFailure)=>{
|
|
184
|
+
if (statusCode === undefined) {
|
|
185
|
+
return 'transport';
|
|
186
|
+
}
|
|
187
|
+
return isServerFailure ? 'backend' : 'unknown';
|
|
188
|
+
};
|
|
189
|
+
const getFailureCategory = (isClientValidation, isNetworkFailure, phase)=>{
|
|
190
|
+
if (isClientValidation) {
|
|
191
|
+
return 'client_validation';
|
|
192
|
+
}
|
|
193
|
+
if (isNetworkFailure) {
|
|
194
|
+
return 'transport';
|
|
195
|
+
}
|
|
196
|
+
return (phase == null ? void 0 : phase.startsWith('mpc_')) ? 'mpc_protocol' : 'unknown';
|
|
197
|
+
};
|
|
198
|
+
const classifyAxiosError = (error, context, outerError)=>{
|
|
199
|
+
var _error_response, _error_config_method, _error_config;
|
|
200
|
+
const statusCode = (_error_response = error.response) == null ? void 0 : _error_response.status;
|
|
201
|
+
var _context_backendReached;
|
|
202
|
+
const backendReached = (_context_backendReached = context.backendReached) != null ? _context_backendReached : statusCode !== undefined;
|
|
203
|
+
const isServerFailure = statusCode !== undefined && statusCode >= 500;
|
|
204
|
+
const category = getHttpFailureCategory(statusCode, isServerFailure);
|
|
205
|
+
const requestUrl = getSafeRequestUrl(error);
|
|
206
|
+
const requestMethod = (_error_config = error.config) == null ? void 0 : (_error_config_method = _error_config.method) == null ? void 0 : _error_config_method.toUpperCase();
|
|
207
|
+
const http = _extends({}, requestMethod ? {
|
|
208
|
+
method: requestMethod
|
|
209
|
+
} : {}, statusCode !== undefined ? {
|
|
210
|
+
status_code: statusCode
|
|
211
|
+
} : {}, requestUrl ? {
|
|
212
|
+
url: requestUrl
|
|
213
|
+
} : {});
|
|
214
|
+
var _getHeader, _getHeader1;
|
|
215
|
+
return _extends({
|
|
216
|
+
dynRequestId: (_getHeader = getHeader(error, 'x-dyn-request-id')) != null ? _getHeader : context.dynamicRequestId,
|
|
217
|
+
error: serializeError(outerError),
|
|
218
|
+
failure: {
|
|
219
|
+
actionable: statusCode === undefined || isServerFailure,
|
|
220
|
+
backendReached,
|
|
221
|
+
category,
|
|
222
|
+
phase: context.failurePhase,
|
|
223
|
+
retryable: statusCode === undefined || statusCode === 429 || isServerFailure
|
|
224
|
+
}
|
|
225
|
+
}, Object.keys(http).length > 0 ? {
|
|
226
|
+
http
|
|
227
|
+
} : {}, {
|
|
228
|
+
sdkVersion: version,
|
|
229
|
+
traceId: (_getHeader1 = getHeader(error, 'x-dyn-trace-id')) != null ? _getHeader1 : context.traceId
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
const buildForwardedErrorTelemetry = (error, context)=>{
|
|
233
|
+
const normalizedError = error instanceof Error ? error : undefined;
|
|
234
|
+
const telemetryContext = normalizeContext(context);
|
|
235
|
+
const axiosError = findErrorInCauseChain(normalizedError, isAxiosErrorInstance);
|
|
236
|
+
if (normalizedError && axiosError) {
|
|
237
|
+
return classifyAxiosError(axiosError, telemetryContext, normalizedError);
|
|
238
|
+
}
|
|
239
|
+
const { backendReached: contextBackendReached, dynamicRequestId, failurePhase: phase, traceId } = telemetryContext;
|
|
240
|
+
const isClientValidation = Boolean(findErrorInCauseChain(normalizedError, isClientValidationErrorInstance));
|
|
241
|
+
const walletApiError = findErrorInCauseChain(normalizedError, isWalletApiError);
|
|
242
|
+
const isNetworkFailure = (walletApiError == null ? void 0 : walletApiError.code) === core$1.NETWORK_ERROR_CODE || Boolean(findErrorInCauseChain(normalizedError, hasTransportErrorCode));
|
|
243
|
+
const category = getFailureCategory(isClientValidation, isNetworkFailure, phase);
|
|
244
|
+
return _extends({}, dynamicRequestId ? {
|
|
245
|
+
dynRequestId: dynamicRequestId
|
|
246
|
+
} : {}, normalizedError ? {
|
|
247
|
+
error: serializeError(normalizedError)
|
|
248
|
+
} : {}, {
|
|
249
|
+
failure: _extends({
|
|
250
|
+
actionable: !isClientValidation,
|
|
251
|
+
backendReached: isClientValidation ? false : contextBackendReached != null ? contextBackendReached : false,
|
|
252
|
+
category
|
|
253
|
+
}, phase ? {
|
|
254
|
+
phase
|
|
255
|
+
} : {}, {
|
|
256
|
+
retryable: isNetworkFailure
|
|
257
|
+
}),
|
|
258
|
+
sdkVersion: version
|
|
259
|
+
}, traceId ? {
|
|
260
|
+
traceId
|
|
261
|
+
} : {});
|
|
262
|
+
};
|
|
263
|
+
const isClientValidationError = (error)=>Boolean(findErrorInCauseChain(error instanceof Error ? error : undefined, isClientValidationErrorInstance));
|
|
264
|
+
|
|
84
265
|
const createLogError = (clientTag)=>({ message, error, context })=>logError({
|
|
85
266
|
message,
|
|
86
267
|
error,
|
|
@@ -92,11 +273,18 @@ const logError = ({ message, error, context, clientTag = 'node' })=>{
|
|
|
92
273
|
core$1.handleAxiosError(error, message, context);
|
|
93
274
|
return;
|
|
94
275
|
}
|
|
95
|
-
|
|
276
|
+
const logMessage = `[DynamicWaasWalletClient] Error in ${clientTag} client`;
|
|
277
|
+
if (isClientValidationError(error)) {
|
|
278
|
+
core$1.Logger.warn(logMessage, _extends({
|
|
279
|
+
message,
|
|
280
|
+
context
|
|
281
|
+
}, buildForwardedErrorTelemetry(error, context)));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
core$1.Logger.error(logMessage, {
|
|
96
285
|
message,
|
|
97
|
-
error: error instanceof Error ? error.message : String(error),
|
|
98
286
|
context
|
|
99
|
-
});
|
|
287
|
+
}, error);
|
|
100
288
|
};
|
|
101
289
|
const bytesToBase64 = (arr)=>{
|
|
102
290
|
return Buffer.from(arr).toString('base64');
|
|
@@ -409,24 +597,28 @@ const getKey = async ({ password, salt, encryptionConfig })=>{
|
|
|
409
597
|
// walletId resolution server-side.
|
|
410
598
|
const CEREMONY_COMPLETE_WAIT_MS = 5000;
|
|
411
599
|
|
|
412
|
-
//
|
|
413
|
-
// cf-worker-log-ingestion's allowlisted `service` override (dynamic-labs/cf-worker-log-ingestion#13).
|
|
600
|
+
// Matches the ingestion worker's allowlisted server-SDK service override.
|
|
414
601
|
const SERVICE_NAME = 'waas-server-sdk';
|
|
415
602
|
const SDK_NAME = 'node';
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
// to the local console; this instance's console output is simply unused.
|
|
421
|
-
const forwardingLogger = new logger.Logger('waas-server-sdk');
|
|
603
|
+
const ScopedLogger = logger.Logger;
|
|
604
|
+
const forwardingLogger = new ScopedLogger(SERVICE_NAME, undefined, {
|
|
605
|
+
emitErrors: false
|
|
606
|
+
});
|
|
422
607
|
const extractErrorAndContext = (args)=>{
|
|
423
608
|
let error;
|
|
424
609
|
let context;
|
|
425
|
-
for (const
|
|
610
|
+
for (const _ref of args){
|
|
611
|
+
let arg = _ref;
|
|
426
612
|
if (arg instanceof Error) {
|
|
427
613
|
error = arg;
|
|
428
614
|
} else if (arg && typeof arg === 'object') {
|
|
429
|
-
|
|
615
|
+
const { error: contextError } = arg, safeContext = _object_without_properties_loose(arg, [
|
|
616
|
+
"error"
|
|
617
|
+
]);
|
|
618
|
+
if (contextError instanceof Error) {
|
|
619
|
+
error = contextError;
|
|
620
|
+
}
|
|
621
|
+
context = _extends({}, context, safeContext);
|
|
430
622
|
}
|
|
431
623
|
}
|
|
432
624
|
return {
|
|
@@ -434,52 +626,39 @@ const extractErrorAndContext = (args)=>{
|
|
|
434
626
|
context
|
|
435
627
|
};
|
|
436
628
|
};
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
* `@dynamic-labs/redaction` before it leaves the process.
|
|
445
|
-
*
|
|
446
|
-
* Deliberately does NOT call `DynamicLogger.setEmitErrors(true)`: that flag is
|
|
447
|
-
* static and process-global, so flipping it would make the *wrapped* logger's
|
|
448
|
-
* own `.error()` call (two lines below) auto-forward too — double-sending
|
|
449
|
-
* every error, and breaking a later client's `errorLogging: false` opt-out
|
|
450
|
-
* for as long as any other client in the process has forwarding enabled.
|
|
451
|
-
* `emitHttpLogs` below is a direct call and works regardless of that flag.
|
|
452
|
-
*
|
|
453
|
-
* IMPORTANT — process-global state: `environmentId` IS still static/shared
|
|
454
|
-
* (`DynamicLogger.setEnvironmentId`), so a process that constructs multiple
|
|
455
|
-
* `DynamicWalletClient`s for *different* `environmentId`s will have every one
|
|
456
|
-
* of them forward under whichever environmentId was set last — there is no
|
|
457
|
-
* per-instance scoping. This is a real regression versus the fetch-based
|
|
458
|
-
* implementation, which threads `environmentId` through every call explicitly.
|
|
459
|
-
*/ const createErrorForwardingLogger = (logger$1, { environmentId })=>{
|
|
629
|
+
const disableAutomaticErrorForwarding = (logger)=>{
|
|
630
|
+
const configurableLogger = logger;
|
|
631
|
+
configurableLogger.setEmitErrors == null ? void 0 : configurableLogger.setEmitErrors.call(configurableLogger, false);
|
|
632
|
+
};
|
|
633
|
+
/** Adds one redacted server event per root error while preserving local logger output. */ const createErrorForwardingLogger = (logger$1, { environmentId })=>{
|
|
634
|
+
disableAutomaticErrorForwarding(logger$1);
|
|
635
|
+
const forwardedErrors = new WeakSet();
|
|
460
636
|
return {
|
|
461
637
|
debug: logger$1.debug.bind(logger$1),
|
|
462
638
|
info: logger$1.info.bind(logger$1),
|
|
463
639
|
warn: logger$1.warn.bind(logger$1),
|
|
464
640
|
error: (message, ...args)=>{
|
|
465
|
-
logger$1.error(message, ...args);
|
|
466
641
|
const { error, context } = extractErrorAndContext(args);
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
642
|
+
const telemetry = buildForwardedErrorTelemetry(error, context);
|
|
643
|
+
if (telemetry.failure.category === 'client_validation') {
|
|
644
|
+
logger$1.warn(message, _extends({}, context, telemetry), error);
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
logger$1.error(message, ...args);
|
|
648
|
+
const errorChain = getErrorCauseChain(error);
|
|
649
|
+
if (errorChain.some((candidate)=>forwardedErrors.has(candidate))) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
errorChain.forEach((candidate)=>forwardedErrors.add(candidate));
|
|
474
653
|
forwardingLogger.emitHttpLogs(logger.LogLevel.ERROR, message, {
|
|
475
654
|
args: [
|
|
476
655
|
_extends({}, context, {
|
|
477
656
|
service: SERVICE_NAME,
|
|
478
657
|
sdk: SDK_NAME
|
|
479
|
-
},
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
658
|
+
}, telemetry)
|
|
659
|
+
],
|
|
660
|
+
environmentId,
|
|
661
|
+
stackField: 'callsiteStack'
|
|
483
662
|
});
|
|
484
663
|
}
|
|
485
664
|
};
|
|
@@ -843,11 +1022,18 @@ class DynamicWalletClient {
|
|
|
843
1022
|
}));
|
|
844
1023
|
return data;
|
|
845
1024
|
} catch (error) {
|
|
846
|
-
this.logger.error('Error in dynamicServerInitializeKeyGen',
|
|
847
|
-
|
|
1025
|
+
this.logger.error('Error in dynamicServerInitializeKeyGen', {
|
|
1026
|
+
backendReached: true,
|
|
1027
|
+
dynamicRequestId: createWalletAccountRequest.dynamicRequestId,
|
|
1028
|
+
failurePhase: 'backend_keygen',
|
|
1029
|
+
operation: 'keygen'
|
|
1030
|
+
}, error);
|
|
1031
|
+
throw new Error('Error creating wallet account in dynamicServerInitializeKeyGen', {
|
|
1032
|
+
cause: error
|
|
1033
|
+
});
|
|
848
1034
|
}
|
|
849
1035
|
}
|
|
850
|
-
async externalServerInitializeKeyGen({ chainName, thresholdSignatureScheme, bitcoinConfig }) {
|
|
1036
|
+
async externalServerInitializeKeyGen({ chainName, dynamicRequestId, thresholdSignatureScheme, bitcoinConfig }) {
|
|
851
1037
|
try {
|
|
852
1038
|
// Get the mpc signer
|
|
853
1039
|
const mpcSigner = getMPCSigner({
|
|
@@ -859,11 +1045,19 @@ class DynamicWalletClient {
|
|
|
859
1045
|
const keygenInitResults = await Promise.all(new Array(clientThreshold).fill(null).map(()=>mpcSigner.initKeygen()));
|
|
860
1046
|
return keygenInitResults;
|
|
861
1047
|
} catch (error) {
|
|
862
|
-
this.logger.error('Error in externalServerInitializeKeyGen',
|
|
863
|
-
|
|
1048
|
+
this.logger.error('Error in externalServerInitializeKeyGen', {
|
|
1049
|
+
backendReached: false,
|
|
1050
|
+
chain: chainName,
|
|
1051
|
+
dynamicRequestId,
|
|
1052
|
+
failurePhase: 'mpc_keygen',
|
|
1053
|
+
operation: 'keygen'
|
|
1054
|
+
}, error);
|
|
1055
|
+
throw new Error('Error initializing keygen in externalServerInitializeKeyGen', {
|
|
1056
|
+
cause: error
|
|
1057
|
+
});
|
|
864
1058
|
}
|
|
865
1059
|
}
|
|
866
|
-
async derivePublicKey({ chainName, keyShare, derivationPath, bitcoinConfig }) {
|
|
1060
|
+
async derivePublicKey({ chainName, keyShare, derivationPath, bitcoinConfig, dynamicRequestId }) {
|
|
867
1061
|
try {
|
|
868
1062
|
const mpcSigner = getMPCSigner({
|
|
869
1063
|
chainName,
|
|
@@ -880,11 +1074,19 @@ class DynamicWalletClient {
|
|
|
880
1074
|
}
|
|
881
1075
|
return publicKey;
|
|
882
1076
|
} catch (error) {
|
|
883
|
-
this.logger.error('Error in derivePublicKey',
|
|
884
|
-
|
|
1077
|
+
this.logger.error('Error in derivePublicKey', {
|
|
1078
|
+
backendReached: Boolean(dynamicRequestId),
|
|
1079
|
+
chain: chainName,
|
|
1080
|
+
dynamicRequestId,
|
|
1081
|
+
failurePhase: 'mpc_keygen',
|
|
1082
|
+
operation: 'keygen'
|
|
1083
|
+
}, error);
|
|
1084
|
+
throw new Error('Error deriving public key in derivePublicKey', {
|
|
1085
|
+
cause: error
|
|
1086
|
+
});
|
|
885
1087
|
}
|
|
886
1088
|
}
|
|
887
|
-
async forwardMPCExternalServerKeyGen({ chainName, roomId, dynamicServerKeygenIds, externalServerInitKeygenResults, thresholdSignatureScheme, bitcoinConfig }) {
|
|
1089
|
+
async forwardMPCExternalServerKeyGen({ chainName, roomId, dynamicServerKeygenIds, externalServerInitKeygenResults, dynamicRequestId, thresholdSignatureScheme, bitcoinConfig }) {
|
|
888
1090
|
try {
|
|
889
1091
|
const chainConfig = core$1.getMPCChainConfig(chainName, bitcoinConfig);
|
|
890
1092
|
const signingAlgo = chainConfig.signingAlgorithm;
|
|
@@ -918,7 +1120,8 @@ class DynamicWalletClient {
|
|
|
918
1120
|
chainName,
|
|
919
1121
|
keyShare: serverKeygenResult,
|
|
920
1122
|
derivationPath,
|
|
921
|
-
bitcoinConfig
|
|
1123
|
+
bitcoinConfig,
|
|
1124
|
+
dynamicRequestId
|
|
922
1125
|
});
|
|
923
1126
|
return {
|
|
924
1127
|
rawPublicKey,
|
|
@@ -927,6 +1130,7 @@ class DynamicWalletClient {
|
|
|
927
1130
|
} catch (error) {
|
|
928
1131
|
this.logger.error('Error during forward MPC external server keygen', error, {
|
|
929
1132
|
chainName,
|
|
1133
|
+
dynamicRequestId,
|
|
930
1134
|
environmentId: this.environmentId
|
|
931
1135
|
});
|
|
932
1136
|
throw error;
|
|
@@ -934,7 +1138,7 @@ class DynamicWalletClient {
|
|
|
934
1138
|
this.apiClient.forwardMPCClient.disconnect();
|
|
935
1139
|
}
|
|
936
1140
|
}
|
|
937
|
-
async externalServerKeyGen({ chainName, roomId, dynamicServerKeygenIds, externalServerInitKeygenResults, thresholdSignatureScheme, bitcoinConfig }) {
|
|
1141
|
+
async externalServerKeyGen({ chainName, roomId, dynamicRequestId, dynamicServerKeygenIds, externalServerInitKeygenResults, thresholdSignatureScheme, bitcoinConfig }) {
|
|
938
1142
|
// Try forward MPC first if enabled
|
|
939
1143
|
if (this.forwardMPCEnabled && !this.shouldSkipForwardMPC(chainName)) {
|
|
940
1144
|
try {
|
|
@@ -943,6 +1147,7 @@ class DynamicWalletClient {
|
|
|
943
1147
|
roomId,
|
|
944
1148
|
dynamicServerKeygenIds,
|
|
945
1149
|
externalServerInitKeygenResults,
|
|
1150
|
+
dynamicRequestId,
|
|
946
1151
|
thresholdSignatureScheme,
|
|
947
1152
|
bitcoinConfig
|
|
948
1153
|
});
|
|
@@ -992,15 +1197,24 @@ class DynamicWalletClient {
|
|
|
992
1197
|
chainName,
|
|
993
1198
|
keyShare: serverKeygenResult,
|
|
994
1199
|
derivationPath,
|
|
995
|
-
bitcoinConfig
|
|
1200
|
+
bitcoinConfig,
|
|
1201
|
+
dynamicRequestId
|
|
996
1202
|
});
|
|
997
1203
|
return {
|
|
998
1204
|
rawPublicKey,
|
|
999
1205
|
externalServerKeyGenResults: serverKeygenResults
|
|
1000
1206
|
};
|
|
1001
1207
|
} catch (error) {
|
|
1002
|
-
this.logger.error('Error in externalServerKeyGen',
|
|
1003
|
-
|
|
1208
|
+
this.logger.error('Error in externalServerKeyGen', {
|
|
1209
|
+
backendReached: true,
|
|
1210
|
+
chain: chainName,
|
|
1211
|
+
dynamicRequestId,
|
|
1212
|
+
failurePhase: 'mpc_keygen',
|
|
1213
|
+
operation: 'keygen'
|
|
1214
|
+
}, error);
|
|
1215
|
+
throw new Error('Error deriving public key in externalServerKeyGen', {
|
|
1216
|
+
cause: error
|
|
1217
|
+
});
|
|
1004
1218
|
}
|
|
1005
1219
|
}
|
|
1006
1220
|
validatePasswordForBackup({ password, backUpToDynamic }) {
|
|
@@ -1038,9 +1252,11 @@ class DynamicWalletClient {
|
|
|
1038
1252
|
backUpToDynamic
|
|
1039
1253
|
});
|
|
1040
1254
|
const dynamicRequestId = uuid.v4();
|
|
1255
|
+
let backendReached = false;
|
|
1041
1256
|
try {
|
|
1042
1257
|
const externalServerInitKeygenResults = await this.externalServerInitializeKeyGen({
|
|
1043
1258
|
chainName,
|
|
1259
|
+
dynamicRequestId,
|
|
1044
1260
|
thresholdSignatureScheme,
|
|
1045
1261
|
bitcoinConfig
|
|
1046
1262
|
});
|
|
@@ -1053,12 +1269,14 @@ class DynamicWalletClient {
|
|
|
1053
1269
|
skipLock,
|
|
1054
1270
|
bitcoinConfig
|
|
1055
1271
|
};
|
|
1272
|
+
backendReached = true;
|
|
1056
1273
|
const { roomId, serverKeygenIds: dynamicServerKeygenIds } = await this.dynamicServerInitializeKeyGen(_extends({}, createWalletAccountRequest, {
|
|
1057
1274
|
onCeremonyComplete
|
|
1058
1275
|
}));
|
|
1059
1276
|
const { rawPublicKey, externalServerKeyGenResults } = await this.externalServerKeyGen({
|
|
1060
1277
|
chainName,
|
|
1061
1278
|
roomId,
|
|
1279
|
+
dynamicRequestId,
|
|
1062
1280
|
dynamicServerKeygenIds,
|
|
1063
1281
|
externalServerInitKeygenResults,
|
|
1064
1282
|
thresholdSignatureScheme,
|
|
@@ -1069,8 +1287,16 @@ class DynamicWalletClient {
|
|
|
1069
1287
|
externalServerKeyShares: externalServerKeyGenResults
|
|
1070
1288
|
};
|
|
1071
1289
|
} catch (error) {
|
|
1072
|
-
this.logger.error('Error in keyGen',
|
|
1073
|
-
|
|
1290
|
+
this.logger.error('Error in keyGen', {
|
|
1291
|
+
backendReached,
|
|
1292
|
+
chain: chainName,
|
|
1293
|
+
dynamicRequestId,
|
|
1294
|
+
failurePhase: 'keygen',
|
|
1295
|
+
operation: 'keygen'
|
|
1296
|
+
}, error);
|
|
1297
|
+
throw new Error('Error creating wallet account in keyGen', {
|
|
1298
|
+
cause: error
|
|
1299
|
+
});
|
|
1074
1300
|
}
|
|
1075
1301
|
}
|
|
1076
1302
|
async importRawPrivateKey({ chainName, privateKey, thresholdSignatureScheme, bitcoinConfig, password, backUpToDynamic, onError, onCeremonyComplete }) {
|
|
@@ -1093,6 +1319,7 @@ class DynamicWalletClient {
|
|
|
1093
1319
|
});
|
|
1094
1320
|
const externalServerKeygenInitResults = await this.externalServerInitializeKeyGen({
|
|
1095
1321
|
chainName,
|
|
1322
|
+
dynamicRequestId,
|
|
1096
1323
|
thresholdSignatureScheme,
|
|
1097
1324
|
bitcoinConfig
|
|
1098
1325
|
});
|
|
@@ -1129,7 +1356,8 @@ class DynamicWalletClient {
|
|
|
1129
1356
|
chainName,
|
|
1130
1357
|
keyShare: externalServerKeygenResult,
|
|
1131
1358
|
derivationPath: undefined,
|
|
1132
|
-
bitcoinConfig
|
|
1359
|
+
bitcoinConfig,
|
|
1360
|
+
dynamicRequestId
|
|
1133
1361
|
});
|
|
1134
1362
|
return {
|
|
1135
1363
|
rawPublicKey,
|
|
@@ -1158,7 +1386,7 @@ class DynamicWalletClient {
|
|
|
1158
1386
|
dynamicRequestId
|
|
1159
1387
|
});
|
|
1160
1388
|
}
|
|
1161
|
-
async externalServerSign({ chainName, message, roomId, keyShare, derivationPath, isFormatted, bitcoinConfig }) {
|
|
1389
|
+
async externalServerSign({ chainName, message, roomId, keyShare, derivationPath, isFormatted, bitcoinConfig, dynamicRequestId }) {
|
|
1162
1390
|
try {
|
|
1163
1391
|
const mpcSigner = getMPCSigner({
|
|
1164
1392
|
chainName,
|
|
@@ -1170,7 +1398,13 @@ class DynamicWalletClient {
|
|
|
1170
1398
|
const signature = await mpcSigner.sign(roomId, keyShare, formattedMessage, derivationPath, tweak);
|
|
1171
1399
|
return signature;
|
|
1172
1400
|
} catch (error) {
|
|
1173
|
-
this.logger.error('Error in externalServerSign',
|
|
1401
|
+
this.logger.error('Error in externalServerSign', {
|
|
1402
|
+
backendReached: true,
|
|
1403
|
+
chain: chainName,
|
|
1404
|
+
dynamicRequestId,
|
|
1405
|
+
failurePhase: 'mpc_sign',
|
|
1406
|
+
operation: 'sign'
|
|
1407
|
+
}, error);
|
|
1174
1408
|
throw error;
|
|
1175
1409
|
}
|
|
1176
1410
|
}
|
|
@@ -1276,6 +1510,8 @@ class DynamicWalletClient {
|
|
|
1276
1510
|
}
|
|
1277
1511
|
}
|
|
1278
1512
|
async sign({ accountAddress, externalServerKeyShares, message, chainName, password = undefined, isFormatted = false, context, onError, bitcoinConfig, walletMetadata, walletOperation = core$1.WalletOperation.SIGN_MESSAGE, passwordPreVerified = false }) {
|
|
1513
|
+
const dynamicRequestId = uuid.v4();
|
|
1514
|
+
let backendReached = false;
|
|
1279
1515
|
try {
|
|
1280
1516
|
this.assertAddressMatchesMetadata(accountAddress, walletMetadata);
|
|
1281
1517
|
const backupInfo = walletMetadata.externalServerKeySharesBackupInfo;
|
|
@@ -1316,6 +1552,7 @@ class DynamicWalletClient {
|
|
|
1316
1552
|
// timeout.
|
|
1317
1553
|
const sseErrorGate = core$1.createRejectablePromise();
|
|
1318
1554
|
// Perform the dynamic server sign
|
|
1555
|
+
backendReached = true;
|
|
1319
1556
|
const data = await this.dynamicServerSign({
|
|
1320
1557
|
walletId,
|
|
1321
1558
|
message,
|
|
@@ -1326,7 +1563,8 @@ class DynamicWalletClient {
|
|
|
1326
1563
|
sseErrorGate.reject(error);
|
|
1327
1564
|
onError == null ? void 0 : onError(error);
|
|
1328
1565
|
},
|
|
1329
|
-
shareSetId: walletMetadata.shareSetId
|
|
1566
|
+
shareSetId: walletMetadata.shareSetId,
|
|
1567
|
+
dynamicRequestId
|
|
1330
1568
|
});
|
|
1331
1569
|
const derivationPath = derivationPathStr && derivationPathStr != '' ? new Uint32Array(Object.values(JSON.parse(derivationPathStr))) : undefined;
|
|
1332
1570
|
// Try forward MPC first if enabled, with fallback to relay-based signing on attestation failure
|
|
@@ -1353,7 +1591,8 @@ class DynamicWalletClient {
|
|
|
1353
1591
|
keyShare: resolvedShares[0],
|
|
1354
1592
|
derivationPath,
|
|
1355
1593
|
isFormatted,
|
|
1356
|
-
bitcoinConfig
|
|
1594
|
+
bitcoinConfig,
|
|
1595
|
+
dynamicRequestId
|
|
1357
1596
|
});
|
|
1358
1597
|
})();
|
|
1359
1598
|
// The losing branch's rejection (e.g. the relay timeout after a policy
|
|
@@ -1366,7 +1605,13 @@ class DynamicWalletClient {
|
|
|
1366
1605
|
]);
|
|
1367
1606
|
} catch (error) {
|
|
1368
1607
|
if (!(error instanceof Error && error.message === 'External server key shares are required to sign a message')) {
|
|
1369
|
-
this.logger.error('Error in sign',
|
|
1608
|
+
this.logger.error('Error in sign', {
|
|
1609
|
+
backendReached,
|
|
1610
|
+
chain: chainName,
|
|
1611
|
+
dynamicRequestId,
|
|
1612
|
+
failurePhase: 'sign',
|
|
1613
|
+
operation: 'sign'
|
|
1614
|
+
}, error);
|
|
1370
1615
|
}
|
|
1371
1616
|
throw error;
|
|
1372
1617
|
}
|
|
@@ -2197,7 +2442,9 @@ class DynamicWalletClient {
|
|
|
2197
2442
|
// We can't distinguish wrong-password from stale-metadata without a
|
|
2198
2443
|
// server-side backupInfo lookup (fetchWalletMetadata returns identity
|
|
2199
2444
|
// only). Surface both possibilities so customers know where to look.
|
|
2200
|
-
throw new Error('Failed to verify password. Either the password is incorrect, or the cached `walletMetadata.externalServerKeySharesBackupInfo` is stale ' + '(merge the `backupInfo` returned from updatePassword/refreshWalletAccountShares/reshare into your cached walletMetadata).'
|
|
2445
|
+
throw new Error('Failed to verify password. Either the password is incorrect, or the cached `walletMetadata.externalServerKeySharesBackupInfo` is stale ' + '(merge the `backupInfo` returned from updatePassword/refreshWalletAccountShares/reshare into your cached walletMetadata).', {
|
|
2446
|
+
cause: error
|
|
2447
|
+
});
|
|
2201
2448
|
}
|
|
2202
2449
|
}
|
|
2203
2450
|
async isPasswordEncrypted({ accountAddress, walletMetadata, backupInfo }) {
|
|
@@ -2979,6 +3226,7 @@ Object.defineProperty(exports, "SignMessageRawSignHashFunctionEnum", {
|
|
|
2979
3226
|
enumerable: true,
|
|
2980
3227
|
get: function () { return sdkApiCore.SignMessageRawSignHashFunctionEnum; }
|
|
2981
3228
|
});
|
|
3229
|
+
exports.ClientValidationError = ClientValidationError;
|
|
2982
3230
|
exports.DynamicServerApiClient = DynamicServerApiClient;
|
|
2983
3231
|
exports.DynamicWalletClient = DynamicWalletClient;
|
|
2984
3232
|
exports.ERROR_RAW_SIGN_CONTEXT_REQUIRED = ERROR_RAW_SIGN_CONTEXT_REQUIRED;
|