@portal-hq/provider 4.4.0 → 4.6.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/lib/commonjs/providers/index.js +24 -8
- package/lib/commonjs/signers/enclave.js +150 -16
- package/lib/commonjs/signers/mpc.js +151 -9
- package/lib/esm/providers/index.js +26 -10
- package/lib/esm/signers/enclave.js +151 -14
- package/lib/esm/signers/mpc.js +152 -7
- package/package.json +4 -4
- package/src/providers/index.ts +29 -6
- package/src/signers/enclave.ts +204 -6
- package/src/signers/mpc.ts +227 -5
- package/types.d.ts +25 -1
|
@@ -8,15 +8,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { PortalCurve } from '@portal-hq/core';
|
|
11
|
-
import { HttpRequester, PortalErrorCodes, PortalMpcError, getClientPlatformVersion,
|
|
12
|
-
import UUID from 'react-native-uuid';
|
|
11
|
+
import { DEFAULT_HOSTS, HttpRequester, PortalErrorCodes, PortalMpcError, generateTraceId, getClientPlatformVersion, sdkLogger, } from '@portal-hq/utils';
|
|
13
12
|
var Operation;
|
|
14
13
|
(function (Operation) {
|
|
15
14
|
Operation["SIGN"] = "sign";
|
|
16
15
|
Operation["RAW_SIGN"] = "raw_sign";
|
|
17
16
|
})(Operation || (Operation = {}));
|
|
18
17
|
class EnclaveSigner {
|
|
19
|
-
constructor({ keychain, enclaveMPCHost, version = 'v6', portalApi, featureFlags = {}, }) {
|
|
18
|
+
constructor({ keychain, enclaveMPCHost, version = 'v6', portalApi, featureFlags = {}, presignatureSource, }) {
|
|
20
19
|
this.version = 'v6';
|
|
21
20
|
this.buildParams = (method, txParams) => {
|
|
22
21
|
let params = txParams;
|
|
@@ -47,19 +46,21 @@ class EnclaveSigner {
|
|
|
47
46
|
this.enclaveMPCHost = enclaveMPCHost !== null && enclaveMPCHost !== void 0 ? enclaveMPCHost : DEFAULT_HOSTS.ENCLAVE_MPC;
|
|
48
47
|
this.version = version;
|
|
49
48
|
this.portalApi = portalApi;
|
|
49
|
+
this.presignatureSource = presignatureSource;
|
|
50
50
|
this.requests = new HttpRequester({
|
|
51
51
|
baseUrl: `https://${this.enclaveMPCHost}`,
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
sign(message, provider) {
|
|
55
|
+
var _a;
|
|
55
56
|
return __awaiter(this, void 0, void 0, function* () {
|
|
56
57
|
// Always track metrics, but only send if feature flag is enabled
|
|
57
58
|
const shouldSendMetrics = this.featureFlags.enableSdkPerformanceMetrics === true;
|
|
58
59
|
const signStartTime = performance.now();
|
|
59
60
|
const preOperationStartTime = performance.now();
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
// Use traceId from message if available (e.g. options.traceId), otherwise generate a new UUID
|
|
62
|
+
const traceId = (_a = message.traceId) !== null && _a !== void 0 ? _a : generateTraceId();
|
|
63
|
+
sdkLogger.info(`[Portal MPC] enclave sign started | method=${message.method} | traceId=${traceId} | chainId=${message.chainId} | curve=${message.curve}`);
|
|
63
64
|
const metrics = {
|
|
64
65
|
hasError: false,
|
|
65
66
|
operation: Operation.SIGN,
|
|
@@ -114,6 +115,21 @@ class EnclaveSigner {
|
|
|
114
115
|
reqId: traceId,
|
|
115
116
|
connectionTracingEnabled: shouldSendMetrics,
|
|
116
117
|
};
|
|
118
|
+
// Presignature path (SECP256K1 only): try consume before building params; fallback to normal sign.
|
|
119
|
+
if (curve === PortalCurve.SECP256K1 &&
|
|
120
|
+
this.featureFlags.usePresignatures === true &&
|
|
121
|
+
this.presignatureSource) {
|
|
122
|
+
const presignature = yield this.presignatureSource.consumePresignature(PortalCurve.SECP256K1);
|
|
123
|
+
if (presignature === null || presignature === void 0 ? void 0 : presignature.data) {
|
|
124
|
+
sdkLogger.debug('[Portal] Signing with presignature (EnclaveSigner)', { method: message.method, chainId: message.chainId });
|
|
125
|
+
try {
|
|
126
|
+
return yield this.signWithPresignature(Object.assign(Object.assign({}, message), { presignatureData: presignature.data, traceId }), provider);
|
|
127
|
+
}
|
|
128
|
+
catch (presignError) {
|
|
129
|
+
sdkLogger.warn('[Portal.Provider.EnclaveSigner] signWithPresignature failed, falling back to normal sign:', presignError);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
117
133
|
// Build params
|
|
118
134
|
// Avoid double JSON encoding: if params is already a string (e.g. a hex message), pass it directly; otherwise stringify objects/arrays.
|
|
119
135
|
const params = this.buildParams(method, message.params);
|
|
@@ -148,6 +164,7 @@ class EnclaveSigner {
|
|
|
148
164
|
requestBody = {
|
|
149
165
|
params: formattedParams,
|
|
150
166
|
share: JSON.stringify(signingShare),
|
|
167
|
+
metadataStr: JSON.stringify(metadata),
|
|
151
168
|
};
|
|
152
169
|
}
|
|
153
170
|
else {
|
|
@@ -167,7 +184,7 @@ class EnclaveSigner {
|
|
|
167
184
|
// Make API request and process response
|
|
168
185
|
let result;
|
|
169
186
|
try {
|
|
170
|
-
const response = yield this.makeEnclaveRequest(endpoint, apiKey, requestBody);
|
|
187
|
+
const response = yield this.makeEnclaveRequest(endpoint, apiKey, requestBody, traceId);
|
|
171
188
|
result = this.processEnclaveResponse(response);
|
|
172
189
|
}
|
|
173
190
|
catch (error) {
|
|
@@ -218,7 +235,7 @@ class EnclaveSigner {
|
|
|
218
235
|
try {
|
|
219
236
|
yield this.sendMetrics(metrics, apiKey);
|
|
220
237
|
}
|
|
221
|
-
catch (
|
|
238
|
+
catch (_b) {
|
|
222
239
|
// No-op
|
|
223
240
|
}
|
|
224
241
|
}
|
|
@@ -263,15 +280,12 @@ class EnclaveSigner {
|
|
|
263
280
|
* Make HTTP request to Enclave API
|
|
264
281
|
* Returns raw response without processing
|
|
265
282
|
*/
|
|
266
|
-
makeEnclaveRequest(endpoint, apiKey, body) {
|
|
283
|
+
makeEnclaveRequest(endpoint, apiKey, body, traceId) {
|
|
267
284
|
return __awaiter(this, void 0, void 0, function* () {
|
|
268
|
-
return yield this.requests.post(endpoint, {
|
|
269
|
-
headers: {
|
|
285
|
+
return yield this.requests.post(endpoint, Object.assign({ headers: {
|
|
270
286
|
Authorization: `Bearer ${apiKey}`,
|
|
271
287
|
'Content-Type': 'application/json',
|
|
272
|
-
},
|
|
273
|
-
body,
|
|
274
|
-
});
|
|
288
|
+
}, body }, (traceId ? { traceId } : {})));
|
|
275
289
|
});
|
|
276
290
|
}
|
|
277
291
|
/**
|
|
@@ -369,5 +383,128 @@ class EnclaveSigner {
|
|
|
369
383
|
}
|
|
370
384
|
});
|
|
371
385
|
}
|
|
386
|
+
/**
|
|
387
|
+
* Sign using a pre-generated presignature via the Enclave REST API.
|
|
388
|
+
* Uses the same endpoints as normal signing (/v1/sign, /v1/raw/sign/:curve)
|
|
389
|
+
* but includes the optional `presignature` field in the request body.
|
|
390
|
+
* NOTE: Only supports SECP256K1 curve.
|
|
391
|
+
*/
|
|
392
|
+
signWithPresignature(message, provider) {
|
|
393
|
+
var _a;
|
|
394
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
395
|
+
const { method, chainId, isRaw = false, curve, presignatureData } = message;
|
|
396
|
+
const targetCurve = curve || PortalCurve.SECP256K1;
|
|
397
|
+
if (targetCurve !== PortalCurve.SECP256K1) {
|
|
398
|
+
throw new Error('[Portal.Provider.EnclaveSigner] Presignatures are only supported for SECP256K1 curve');
|
|
399
|
+
}
|
|
400
|
+
const shouldSendMetrics = this.featureFlags.enableSdkPerformanceMetrics;
|
|
401
|
+
const traceId = (_a = message.traceId) !== null && _a !== void 0 ? _a : generateTraceId();
|
|
402
|
+
const metrics = {
|
|
403
|
+
hasError: false,
|
|
404
|
+
operation: 'signWithPresignature',
|
|
405
|
+
signingMethod: method,
|
|
406
|
+
traceId,
|
|
407
|
+
};
|
|
408
|
+
if (chainId) {
|
|
409
|
+
metrics.chainId = chainId;
|
|
410
|
+
}
|
|
411
|
+
const requestStartTime = performance.now();
|
|
412
|
+
try {
|
|
413
|
+
const preOperationStartTime = performance.now();
|
|
414
|
+
const apiKey = provider.apiKey;
|
|
415
|
+
if (!apiKey) {
|
|
416
|
+
throw new Error('[Portal.Provider.EnclaveSigner] The API key is missing.');
|
|
417
|
+
}
|
|
418
|
+
const shares = yield this.keychain.getShares();
|
|
419
|
+
const signingShare = shares.secp256k1.share;
|
|
420
|
+
if (!signingShare) {
|
|
421
|
+
throw new Error('[Portal.Provider.EnclaveSigner] The SECP256K1 share is missing from the keychain.');
|
|
422
|
+
}
|
|
423
|
+
const metadata = {
|
|
424
|
+
clientPlatform: 'REACT_NATIVE',
|
|
425
|
+
clientPlatformVersion: getClientPlatformVersion(),
|
|
426
|
+
isMultiBackupEnabled: this.featureFlags.isMultiBackupEnabled,
|
|
427
|
+
mpcServerVersion: this.version,
|
|
428
|
+
optimized: true,
|
|
429
|
+
curve: PortalCurve.SECP256K1,
|
|
430
|
+
chainId,
|
|
431
|
+
isRaw,
|
|
432
|
+
reqId: traceId,
|
|
433
|
+
connectionTracingEnabled: shouldSendMetrics,
|
|
434
|
+
};
|
|
435
|
+
let endpoint;
|
|
436
|
+
let requestBody;
|
|
437
|
+
if (isRaw) {
|
|
438
|
+
const params = this.buildParams(method, message.params);
|
|
439
|
+
if (typeof params !== 'string') {
|
|
440
|
+
throw new Error('[Portal.Provider.EnclaveSigner] For raw signing with presignature, params must be a string (e.g., a hex-encoded message).');
|
|
441
|
+
}
|
|
442
|
+
endpoint = `/v1/raw/sign/${targetCurve}`;
|
|
443
|
+
requestBody = {
|
|
444
|
+
params,
|
|
445
|
+
share: JSON.stringify(signingShare),
|
|
446
|
+
metadataStr: JSON.stringify(metadata),
|
|
447
|
+
presignature: presignatureData,
|
|
448
|
+
};
|
|
449
|
+
metrics.operation = 'raw_signWithPresignature';
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
const params = this.buildParams(method, message.params);
|
|
453
|
+
const formattedParams = typeof params === 'string' ? params : JSON.stringify(params);
|
|
454
|
+
const rpcUrl = provider.getGatewayUrl(chainId);
|
|
455
|
+
endpoint = '/v1/sign';
|
|
456
|
+
requestBody = {
|
|
457
|
+
method: message.method,
|
|
458
|
+
params: formattedParams,
|
|
459
|
+
share: JSON.stringify(signingShare),
|
|
460
|
+
chainId: chainId || '',
|
|
461
|
+
rpcUrl,
|
|
462
|
+
metadataStr: JSON.stringify(metadata),
|
|
463
|
+
clientPlatform: 'REACT_NATIVE',
|
|
464
|
+
clientPlatformVersion: getClientPlatformVersion(),
|
|
465
|
+
presignature: presignatureData,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
metrics.sdkPreOperationMs = performance.now() - preOperationStartTime;
|
|
469
|
+
const enclaveSignStartTime = performance.now();
|
|
470
|
+
let result;
|
|
471
|
+
try {
|
|
472
|
+
const response = yield this.makeEnclaveRequest(endpoint, apiKey, requestBody, traceId);
|
|
473
|
+
result = this.processEnclaveResponse(response);
|
|
474
|
+
}
|
|
475
|
+
catch (error) {
|
|
476
|
+
this.handleEnclaveError(error);
|
|
477
|
+
}
|
|
478
|
+
const postOperationStartTime = performance.now();
|
|
479
|
+
metrics.enclaveHttpCallMs = performance.now() - enclaveSignStartTime;
|
|
480
|
+
metrics.sdkPostOperationMs = performance.now() - postOperationStartTime;
|
|
481
|
+
metrics.sdkOperationMs = performance.now() - requestStartTime;
|
|
482
|
+
if (shouldSendMetrics && this.portalApi) {
|
|
483
|
+
try {
|
|
484
|
+
yield this.sendMetrics(metrics, apiKey);
|
|
485
|
+
}
|
|
486
|
+
catch (error) {
|
|
487
|
+
// No-op
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return result;
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
sdkLogger.error('[Portal.Provider.EnclaveSigner] signWithPresignature error:', error);
|
|
494
|
+
metrics.sdkOperationMs = performance.now() - requestStartTime;
|
|
495
|
+
metrics.hasError = true;
|
|
496
|
+
if (shouldSendMetrics && this.portalApi) {
|
|
497
|
+
const apiKey = provider.apiKey;
|
|
498
|
+
try {
|
|
499
|
+
yield this.sendMetrics(metrics, apiKey);
|
|
500
|
+
}
|
|
501
|
+
catch (metricsError) {
|
|
502
|
+
// No-op
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
throw error;
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
}
|
|
372
509
|
}
|
|
373
510
|
export default EnclaveSigner;
|
package/lib/esm/signers/mpc.js
CHANGED
|
@@ -8,16 +8,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { PortalCurve } from '@portal-hq/core';
|
|
11
|
-
import { PortalMpcError, getClientPlatformVersion,
|
|
11
|
+
import { DEFAULT_HOSTS, PortalMpcError, generateTraceId, getClientPlatformVersion, sdkLogger, } from '@portal-hq/utils';
|
|
12
12
|
import { NativeModules } from 'react-native';
|
|
13
|
-
import UUID from 'react-native-uuid';
|
|
14
13
|
var Operation;
|
|
15
14
|
(function (Operation) {
|
|
16
15
|
Operation["SIGN"] = "sign";
|
|
17
16
|
Operation["RAW_SIGN"] = "raw_sign";
|
|
18
17
|
})(Operation || (Operation = {}));
|
|
19
18
|
class MpcSigner {
|
|
20
|
-
constructor({ keychain, mpcHost = DEFAULT_HOSTS.MPC, version = 'v6', portalApi, featureFlags = {}, }) {
|
|
19
|
+
constructor({ keychain, mpcHost = DEFAULT_HOSTS.MPC, version = 'v6', portalApi, featureFlags = {}, presignatureSource, }) {
|
|
21
20
|
this.version = 'v6';
|
|
22
21
|
this.buildParams = (method, txParams) => {
|
|
23
22
|
let params = txParams;
|
|
@@ -49,19 +48,21 @@ class MpcSigner {
|
|
|
49
48
|
this.mpcHost = mpcHost;
|
|
50
49
|
this.version = version;
|
|
51
50
|
this.portalApi = portalApi;
|
|
51
|
+
this.presignatureSource = presignatureSource;
|
|
52
52
|
if (!this.mpc) {
|
|
53
53
|
throw new Error(`[Portal.Provider.MpcSigner] The MPC module could not be found by the signer. This is usually an issue with React Native linking. Please verify that the 'PortalReactNative' module is properly linked to this project.`);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
sign(message, provider) {
|
|
57
|
+
var _a;
|
|
57
58
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
59
|
// Always track metrics, but only send if feature flag is enabled
|
|
59
60
|
const shouldSendMetrics = this.featureFlags.enableSdkPerformanceMetrics === true;
|
|
60
61
|
const signStartTime = performance.now();
|
|
61
62
|
const preOperationStartTime = performance.now();
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
// Use traceId from message if available (e.g. options.traceId), otherwise generate a new UUID
|
|
64
|
+
const traceId = (_a = message.traceId) !== null && _a !== void 0 ? _a : generateTraceId();
|
|
65
|
+
sdkLogger.info(`[Portal MPC] sign started | method=${message.method} | traceId=${traceId} | chainId=${message.chainId} | curve=${message.curve}`);
|
|
65
66
|
const metrics = {
|
|
66
67
|
hasError: false,
|
|
67
68
|
operation: Operation.SIGN,
|
|
@@ -121,6 +122,22 @@ class MpcSigner {
|
|
|
121
122
|
if (typeof formattedParams !== 'string') {
|
|
122
123
|
throw new Error(`[Portal.Provider.MpcSigner] The formatted params for the signing request could not be converted to a string. The params were: ${formattedParams}`);
|
|
123
124
|
}
|
|
125
|
+
// Internal presignature handling (gated by feature flag): when usePresignatures is true and a
|
|
126
|
+
// presignature is available for SECP256K1, use signWithPresignature; otherwise normal sign().
|
|
127
|
+
if (curve === PortalCurve.SECP256K1 &&
|
|
128
|
+
this.featureFlags.usePresignatures === true &&
|
|
129
|
+
this.presignatureSource) {
|
|
130
|
+
const presignature = yield this.presignatureSource.consumePresignature(PortalCurve.SECP256K1);
|
|
131
|
+
if (presignature === null || presignature === void 0 ? void 0 : presignature.data) {
|
|
132
|
+
sdkLogger.debug('[Portal] Signing with presignature (portal.request/sendAsset path)', { method: message.method, chainId: message.chainId });
|
|
133
|
+
try {
|
|
134
|
+
return yield this.signWithPresignature(Object.assign(Object.assign({}, message), { presignatureData: presignature.data, traceId }), provider);
|
|
135
|
+
}
|
|
136
|
+
catch (presignError) {
|
|
137
|
+
sdkLogger.warn('[Portal.Provider.MpcSigner] signWithPresignature failed, falling back to normal sign:', presignError);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
124
141
|
// Record pre-operation time
|
|
125
142
|
metrics.sdkPreOperationMs = performance.now() - preOperationStartTime;
|
|
126
143
|
// Measure MPC signing operation time
|
|
@@ -183,7 +200,7 @@ class MpcSigner {
|
|
|
183
200
|
try {
|
|
184
201
|
yield this.sendMetrics(metrics, apiKey);
|
|
185
202
|
}
|
|
186
|
-
catch (
|
|
203
|
+
catch (_b) {
|
|
187
204
|
// No-op
|
|
188
205
|
}
|
|
189
206
|
}
|
|
@@ -210,5 +227,133 @@ class MpcSigner {
|
|
|
210
227
|
}
|
|
211
228
|
});
|
|
212
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Sign a transaction using a pre-generated presignature
|
|
232
|
+
* NOTE: Only supports SECP256K1 curve
|
|
233
|
+
*
|
|
234
|
+
* @param message - Signing request with presignatureData
|
|
235
|
+
* @param provider - Portal provider instance
|
|
236
|
+
* @returns Signed transaction hash
|
|
237
|
+
*/
|
|
238
|
+
signWithPresignature(message, provider) {
|
|
239
|
+
var _a;
|
|
240
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
241
|
+
const { method, chainId, isRaw = false, curve, sponsorGas, signatureApprovalMemo, presignatureData, } = message;
|
|
242
|
+
const targetCurve = curve || PortalCurve.SECP256K1;
|
|
243
|
+
if (targetCurve !== PortalCurve.SECP256K1) {
|
|
244
|
+
throw new Error('[Portal.Provider.MpcSigner] Presignatures are only supported for SECP256K1 curve');
|
|
245
|
+
}
|
|
246
|
+
const shouldSendMetrics = this.featureFlags.enableSdkPerformanceMetrics;
|
|
247
|
+
const traceId = (_a = message.traceId) !== null && _a !== void 0 ? _a : generateTraceId();
|
|
248
|
+
const metrics = {
|
|
249
|
+
hasError: false,
|
|
250
|
+
operation: 'signWithPresignature',
|
|
251
|
+
signingMethod: method,
|
|
252
|
+
traceId,
|
|
253
|
+
};
|
|
254
|
+
if (chainId) {
|
|
255
|
+
metrics.chainId = chainId;
|
|
256
|
+
}
|
|
257
|
+
const requestStartTime = performance.now();
|
|
258
|
+
try {
|
|
259
|
+
const preOperationStartTime = performance.now();
|
|
260
|
+
const apiKey = provider.apiKey;
|
|
261
|
+
if (!apiKey) {
|
|
262
|
+
throw new Error('[Portal.Provider.MpcSigner] The API key is missing.');
|
|
263
|
+
}
|
|
264
|
+
const shares = yield this.keychain.getShares();
|
|
265
|
+
const signingShare = shares.secp256k1.share;
|
|
266
|
+
if (!signingShare) {
|
|
267
|
+
throw new Error('[Portal.Provider.MpcSigner] The SECP256K1 share is missing from the keychain.');
|
|
268
|
+
}
|
|
269
|
+
const metadata = {
|
|
270
|
+
clientPlatform: 'REACT_NATIVE',
|
|
271
|
+
clientPlatformVersion: getClientPlatformVersion(),
|
|
272
|
+
isMultiBackupEnabled: this.featureFlags.isMultiBackupEnabled,
|
|
273
|
+
mpcServerVersion: this.version,
|
|
274
|
+
optimized: true,
|
|
275
|
+
curve: PortalCurve.SECP256K1,
|
|
276
|
+
chainId,
|
|
277
|
+
isRaw,
|
|
278
|
+
reqId: traceId,
|
|
279
|
+
connectionTracingEnabled: shouldSendMetrics,
|
|
280
|
+
sponsorGas,
|
|
281
|
+
signatureApprovalMemo,
|
|
282
|
+
};
|
|
283
|
+
const stringifiedMetadata = JSON.stringify(metadata);
|
|
284
|
+
let formattedParams;
|
|
285
|
+
let rpcUrl;
|
|
286
|
+
if (isRaw) {
|
|
287
|
+
formattedParams = this.buildParams(method, message.params);
|
|
288
|
+
rpcUrl = '';
|
|
289
|
+
metrics.operation = 'raw_signWithPresignature';
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
formattedParams = JSON.stringify(this.buildParams(method, message.params));
|
|
293
|
+
rpcUrl = provider.getGatewayUrl(chainId);
|
|
294
|
+
}
|
|
295
|
+
if (typeof formattedParams !== 'string') {
|
|
296
|
+
throw new Error(`[Portal.Provider.MpcSigner] The formatted params for the signing request could not be converted to a string. The params were: ${formattedParams}`);
|
|
297
|
+
}
|
|
298
|
+
metrics.sdkPreOperationMs = performance.now() - preOperationStartTime;
|
|
299
|
+
const mpcSignStartTime = performance.now();
|
|
300
|
+
const result = yield this.mpc.signWithPresignature(apiKey, this.mpcHost, JSON.stringify(signingShare), presignatureData, method, formattedParams, rpcUrl, chainId, stringifiedMetadata);
|
|
301
|
+
const postOperationStartTime = performance.now();
|
|
302
|
+
metrics.mpcNativeCallMs = performance.now() - mpcSignStartTime;
|
|
303
|
+
const parsedResponse = JSON.parse(String(result));
|
|
304
|
+
const { data, error, meta } = parsedResponse;
|
|
305
|
+
if (meta === null || meta === void 0 ? void 0 : meta.metrics) {
|
|
306
|
+
const binaryMetrics = meta.metrics;
|
|
307
|
+
if (binaryMetrics.wsConnectDurationMs) {
|
|
308
|
+
metrics.sdkBinaryWSConnectMs = binaryMetrics.wsConnectDurationMs;
|
|
309
|
+
}
|
|
310
|
+
if (binaryMetrics.operationDurationMs) {
|
|
311
|
+
metrics.sdkBinaryOperationMs = binaryMetrics.operationDurationMs;
|
|
312
|
+
}
|
|
313
|
+
if (binaryMetrics.tlsHandshakeMs) {
|
|
314
|
+
metrics.sdkBinaryTlsHandshakeMs = binaryMetrics.tlsHandshakeMs;
|
|
315
|
+
}
|
|
316
|
+
if (binaryMetrics.firstResponseMs) {
|
|
317
|
+
metrics.sdkBinaryFirstResponseMs = binaryMetrics.firstResponseMs;
|
|
318
|
+
}
|
|
319
|
+
if (binaryMetrics.dnsLookupMs) {
|
|
320
|
+
metrics.sdkBinaryDnsLookupMs = binaryMetrics.dnsLookupMs;
|
|
321
|
+
}
|
|
322
|
+
if (binaryMetrics.connectMs) {
|
|
323
|
+
metrics.sdkBinaryConnectMs = binaryMetrics.connectMs;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (error === null || error === void 0 ? void 0 : error.id) {
|
|
327
|
+
throw new PortalMpcError(error);
|
|
328
|
+
}
|
|
329
|
+
metrics.sdkPostOperationMs = performance.now() - postOperationStartTime;
|
|
330
|
+
metrics.sdkOperationMs = performance.now() - requestStartTime;
|
|
331
|
+
if (shouldSendMetrics && this.portalApi) {
|
|
332
|
+
try {
|
|
333
|
+
yield this.sendMetrics(metrics, apiKey);
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
// No-op
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return data;
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
sdkLogger.error('[Portal.Provider.MpcSigner] signWithPresignature error:', error);
|
|
343
|
+
metrics.sdkOperationMs = performance.now() - requestStartTime;
|
|
344
|
+
metrics.hasError = true;
|
|
345
|
+
if (shouldSendMetrics && this.portalApi) {
|
|
346
|
+
const apiKey = provider.apiKey;
|
|
347
|
+
try {
|
|
348
|
+
yield this.sendMetrics(metrics, apiKey);
|
|
349
|
+
}
|
|
350
|
+
catch (metricsError) {
|
|
351
|
+
// No-op
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
213
358
|
}
|
|
214
359
|
export default MpcSigner;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portal-hq/provider",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/esm/index",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"test": "jest"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@portal-hq/connect": "^4.
|
|
23
|
-
"@portal-hq/utils": "^4.
|
|
22
|
+
"@portal-hq/connect": "^4.6.0",
|
|
23
|
+
"@portal-hq/utils": "^4.6.0",
|
|
24
24
|
"@types/react-native-uuid": "^2.0.0",
|
|
25
25
|
"react-native-uuid": "^2.0.3"
|
|
26
26
|
},
|
|
@@ -32,5 +32,5 @@
|
|
|
32
32
|
"ts-jest": "^29.0.3",
|
|
33
33
|
"typescript": "^4.8.4"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "81e3ade6164a87aa8fc8942af4c770d04f73bc55"
|
|
36
36
|
}
|
package/src/providers/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import PortalConnect from '@portal-hq/connect'
|
|
2
2
|
import { PortalCurve } from '@portal-hq/core'
|
|
3
3
|
import {
|
|
4
|
+
CHAIN_NAMESPACES,
|
|
5
|
+
DEFAULT_CHAIN_ID_CAIP2,
|
|
6
|
+
DEFAULT_HOSTS,
|
|
4
7
|
Events,
|
|
5
8
|
HttpRequester,
|
|
6
9
|
IPortalProvider,
|
|
@@ -11,9 +14,7 @@ import {
|
|
|
11
14
|
ProviderRpcError,
|
|
12
15
|
type RequestArguments,
|
|
13
16
|
RpcErrorCodes,
|
|
14
|
-
|
|
15
|
-
CHAIN_NAMESPACES,
|
|
16
|
-
DEFAULT_HOSTS,
|
|
17
|
+
generateTraceId,
|
|
17
18
|
sdkLogger,
|
|
18
19
|
} from '@portal-hq/utils'
|
|
19
20
|
import { AddressesByNamespace, RpcErrorOptions } from '@portal-hq/utils/types'
|
|
@@ -25,7 +26,8 @@ import {
|
|
|
25
26
|
type RegisteredEventHandler,
|
|
26
27
|
SwitchEthereumChainParameter,
|
|
27
28
|
} from '../../types'
|
|
28
|
-
import { MpcSigner, Signer
|
|
29
|
+
import { EnclaveSigner, MpcSigner, Signer } from '../signers'
|
|
30
|
+
|
|
29
31
|
const passiveSignerMethods = [
|
|
30
32
|
'eth_accounts',
|
|
31
33
|
'eth_chainId',
|
|
@@ -84,6 +86,7 @@ class Provider implements IPortalProvider {
|
|
|
84
86
|
version = 'v6',
|
|
85
87
|
chainId = DEFAULT_CHAIN_ID_CAIP2,
|
|
86
88
|
featureFlags = {},
|
|
89
|
+
presignatureSource,
|
|
87
90
|
}: ProviderOptions) {
|
|
88
91
|
const finalApiHost = apiHost ?? DEFAULT_HOSTS.API
|
|
89
92
|
const finalMpcHost = mpcHost ?? DEFAULT_HOSTS.MPC
|
|
@@ -128,6 +131,11 @@ class Provider implements IPortalProvider {
|
|
|
128
131
|
version,
|
|
129
132
|
portalApi: this.portalApi,
|
|
130
133
|
featureFlags,
|
|
134
|
+
// Only pass presignatureSource when usePresignatures is enabled (same as MpcSigner).
|
|
135
|
+
presignatureSource:
|
|
136
|
+
featureFlags.usePresignatures === true
|
|
137
|
+
? presignatureSource
|
|
138
|
+
: undefined,
|
|
131
139
|
})
|
|
132
140
|
} else {
|
|
133
141
|
this.signer = new MpcSigner({
|
|
@@ -136,6 +144,11 @@ class Provider implements IPortalProvider {
|
|
|
136
144
|
version,
|
|
137
145
|
portalApi: this.portalApi,
|
|
138
146
|
featureFlags,
|
|
147
|
+
// Only pass presignatureSource when usePresignatures is enabled; otherwise signer always uses normal sign().
|
|
148
|
+
presignatureSource:
|
|
149
|
+
featureFlags.usePresignatures === true
|
|
150
|
+
? presignatureSource
|
|
151
|
+
: undefined,
|
|
139
152
|
})
|
|
140
153
|
}
|
|
141
154
|
}
|
|
@@ -281,6 +294,7 @@ class Provider implements IPortalProvider {
|
|
|
281
294
|
params,
|
|
282
295
|
chainId,
|
|
283
296
|
connect,
|
|
297
|
+
options,
|
|
284
298
|
}: RequestArguments): Promise<any> {
|
|
285
299
|
chainId = chainId ?? this.chainId
|
|
286
300
|
if (!chainId) {
|
|
@@ -339,6 +353,7 @@ class Provider implements IPortalProvider {
|
|
|
339
353
|
params,
|
|
340
354
|
chainId,
|
|
341
355
|
connect,
|
|
356
|
+
options,
|
|
342
357
|
})
|
|
343
358
|
|
|
344
359
|
if (transactionHash) {
|
|
@@ -545,6 +560,7 @@ class Provider implements IPortalProvider {
|
|
|
545
560
|
params,
|
|
546
561
|
chainId,
|
|
547
562
|
connect,
|
|
563
|
+
options,
|
|
548
564
|
}: RequestArguments): Promise<any> {
|
|
549
565
|
const isApproved = passiveSignerMethods.includes(method)
|
|
550
566
|
? true
|
|
@@ -556,6 +572,7 @@ class Provider implements IPortalProvider {
|
|
|
556
572
|
)
|
|
557
573
|
return
|
|
558
574
|
}
|
|
575
|
+
const traceId = options?.traceId ?? generateTraceId()
|
|
559
576
|
let namespace: string = CHAIN_NAMESPACES.EIP155
|
|
560
577
|
let reference: string | number | undefined = chainId
|
|
561
578
|
if (typeof chainId == 'string' && chainId.includes(':')) {
|
|
@@ -591,6 +608,9 @@ class Provider implements IPortalProvider {
|
|
|
591
608
|
params,
|
|
592
609
|
curve,
|
|
593
610
|
isRaw: false,
|
|
611
|
+
sponsorGas: options?.sponsorGas,
|
|
612
|
+
signatureApprovalMemo: options?.signatureApprovalMemo,
|
|
613
|
+
traceId,
|
|
594
614
|
},
|
|
595
615
|
this,
|
|
596
616
|
)
|
|
@@ -600,11 +620,14 @@ class Provider implements IPortalProvider {
|
|
|
600
620
|
case 'raw_sign': {
|
|
601
621
|
const result = await this.signer?.sign(
|
|
602
622
|
{
|
|
603
|
-
chainId: '',
|
|
604
|
-
method: '',
|
|
623
|
+
chainId: chainId ?? '',
|
|
624
|
+
method: 'raw_sign',
|
|
605
625
|
params,
|
|
606
626
|
curve,
|
|
607
627
|
isRaw: true,
|
|
628
|
+
sponsorGas: options?.sponsorGas,
|
|
629
|
+
signatureApprovalMemo: options?.signatureApprovalMemo,
|
|
630
|
+
traceId,
|
|
608
631
|
},
|
|
609
632
|
this,
|
|
610
633
|
)
|