@portal-hq/provider 4.3.1 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,7 +44,7 @@ class Provider {
44
44
  // Required
45
45
  apiKey, keychain, gatewayConfig,
46
46
  // Optional
47
- autoApprove = false, apiHost, mpcHost, enclaveMPCHost, version = 'v6', chainId = utils_1.DEFAULT_CHAIN_ID_CAIP2, featureFlags = {}, }) {
47
+ autoApprove = false, apiHost, mpcHost, enclaveMPCHost, version = 'v6', chainId = utils_1.DEFAULT_CHAIN_ID_CAIP2, featureFlags = {}, presignatureSource, }) {
48
48
  const finalApiHost = apiHost !== null && apiHost !== void 0 ? apiHost : utils_1.DEFAULT_HOSTS.API;
49
49
  const finalMpcHost = mpcHost !== null && mpcHost !== void 0 ? mpcHost : utils_1.DEFAULT_HOSTS.MPC;
50
50
  const finalEnclaveMPCHost = enclaveMPCHost !== null && enclaveMPCHost !== void 0 ? enclaveMPCHost : utils_1.DEFAULT_HOSTS.ENCLAVE_MPC;
@@ -81,6 +81,10 @@ class Provider {
81
81
  version,
82
82
  portalApi: this.portalApi,
83
83
  featureFlags,
84
+ // Only pass presignatureSource when usePresignatures is enabled (same as MpcSigner).
85
+ presignatureSource: featureFlags.usePresignatures === true
86
+ ? presignatureSource
87
+ : undefined,
84
88
  });
85
89
  }
86
90
  else {
@@ -90,6 +94,10 @@ class Provider {
90
94
  version,
91
95
  portalApi: this.portalApi,
92
96
  featureFlags,
97
+ // Only pass presignatureSource when usePresignatures is enabled; otherwise signer always uses normal sign().
98
+ presignatureSource: featureFlags.usePresignatures === true
99
+ ? presignatureSource
100
+ : undefined,
93
101
  });
94
102
  }
95
103
  }
@@ -203,7 +211,7 @@ class Provider {
203
211
  * @param args The arguments of the request being made
204
212
  * @returns Promise<any>
205
213
  */
206
- request({ method, params, chainId, connect, }) {
214
+ request({ method, params, chainId, connect, options, }) {
207
215
  return __awaiter(this, void 0, void 0, function* () {
208
216
  chainId = chainId !== null && chainId !== void 0 ? chainId : this.chainId;
209
217
  if (!chainId) {
@@ -254,6 +262,7 @@ class Provider {
254
262
  params,
255
263
  chainId,
256
264
  connect,
265
+ options,
257
266
  });
258
267
  if (transactionHash) {
259
268
  try {
@@ -325,7 +334,7 @@ class Provider {
325
334
  this.dispatchConnect(chainId);
326
335
  }
327
336
  else {
328
- console.error(`[PortalProvider] Invalid chainId format. Must be 'namespace:reference', but got ${chainId}`);
337
+ utils_1.sdkLogger.error(`[PortalProvider] Invalid chainId format. Must be 'namespace:reference', but got ${chainId}`);
329
338
  }
330
339
  return new Promise((resolve) => resolve(this));
331
340
  });
@@ -422,8 +431,8 @@ class Provider {
422
431
  * @param args The arguments of the request being made
423
432
  * @returns Promise<any>
424
433
  */
425
- handleSigningRequests({ method, params, chainId, connect, }) {
426
- var _a, _b;
434
+ handleSigningRequests({ method, params, chainId, connect, options, }) {
435
+ var _a, _b, _c;
427
436
  return __awaiter(this, void 0, void 0, function* () {
428
437
  const isApproved = passiveSignerMethods.includes(method)
429
438
  ? true
@@ -432,6 +441,7 @@ class Provider {
432
441
  this.log.info(`[PortalProvider] Request for signing method '${method}' could not be completed because it was not approved by the user.`);
433
442
  return;
434
443
  }
444
+ const traceId = (_a = options === null || options === void 0 ? void 0 : options.traceId) !== null && _a !== void 0 ? _a : (0, utils_1.generateTraceId)();
435
445
  let namespace = utils_1.CHAIN_NAMESPACES.EIP155;
436
446
  let reference = chainId;
437
447
  if (typeof chainId == 'string' && chainId.includes(':')) {
@@ -458,22 +468,28 @@ class Provider {
458
468
  case 'sol_signAndSendTransaction':
459
469
  case 'sol_signMessage':
460
470
  case 'sol_signTransaction': {
461
- const result = yield ((_a = this.signer) === null || _a === void 0 ? void 0 : _a.sign({
471
+ const result = yield ((_b = this.signer) === null || _b === void 0 ? void 0 : _b.sign({
462
472
  chainId: `${namespace}:${reference}`,
463
473
  method,
464
474
  params,
465
475
  curve,
466
476
  isRaw: false,
477
+ sponsorGas: options === null || options === void 0 ? void 0 : options.sponsorGas,
478
+ signatureApprovalMemo: options === null || options === void 0 ? void 0 : options.signatureApprovalMemo,
479
+ traceId,
467
480
  }, this));
468
481
  return result;
469
482
  }
470
483
  case 'raw_sign': {
471
- const result = yield ((_b = this.signer) === null || _b === void 0 ? void 0 : _b.sign({
472
- chainId: '',
473
- method: '',
484
+ const result = yield ((_c = this.signer) === null || _c === void 0 ? void 0 : _c.sign({
485
+ chainId: chainId !== null && chainId !== void 0 ? chainId : '',
486
+ method: 'raw_sign',
474
487
  params,
475
488
  curve,
476
489
  isRaw: true,
490
+ sponsorGas: options === null || options === void 0 ? void 0 : options.sponsorGas,
491
+ signatureApprovalMemo: options === null || options === void 0 ? void 0 : options.signatureApprovalMemo,
492
+ traceId,
477
493
  }, this));
478
494
  return result;
479
495
  }
@@ -8,20 +8,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
12
  const core_1 = require("@portal-hq/core");
16
13
  const utils_1 = require("@portal-hq/utils");
17
- const react_native_uuid_1 = __importDefault(require("react-native-uuid"));
18
14
  var Operation;
19
15
  (function (Operation) {
20
16
  Operation["SIGN"] = "sign";
21
17
  Operation["RAW_SIGN"] = "raw_sign";
22
18
  })(Operation || (Operation = {}));
23
19
  class EnclaveSigner {
24
- constructor({ keychain, enclaveMPCHost, version = 'v6', portalApi, featureFlags = {}, }) {
20
+ constructor({ keychain, enclaveMPCHost, version = 'v6', portalApi, featureFlags = {}, presignatureSource, }) {
25
21
  this.version = 'v6';
26
22
  this.buildParams = (method, txParams) => {
27
23
  let params = txParams;
@@ -52,19 +48,21 @@ class EnclaveSigner {
52
48
  this.enclaveMPCHost = enclaveMPCHost !== null && enclaveMPCHost !== void 0 ? enclaveMPCHost : utils_1.DEFAULT_HOSTS.ENCLAVE_MPC;
53
49
  this.version = version;
54
50
  this.portalApi = portalApi;
51
+ this.presignatureSource = presignatureSource;
55
52
  this.requests = new utils_1.HttpRequester({
56
53
  baseUrl: `https://${this.enclaveMPCHost}`,
57
54
  });
58
55
  }
59
56
  sign(message, provider) {
57
+ var _a;
60
58
  return __awaiter(this, void 0, void 0, function* () {
61
59
  // Always track metrics, but only send if feature flag is enabled
62
60
  const shouldSendMetrics = this.featureFlags.enableSdkPerformanceMetrics === true;
63
61
  const signStartTime = performance.now();
64
62
  const preOperationStartTime = performance.now();
65
- // Generate a traceId for this operation
66
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
67
- const traceId = react_native_uuid_1.default.v4();
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 : (0, utils_1.generateTraceId)();
65
+ utils_1.sdkLogger.info(`[Portal MPC] enclave sign started | method=${message.method} | traceId=${traceId} | chainId=${message.chainId} | curve=${message.curve}`);
68
66
  const metrics = {
69
67
  hasError: false,
70
68
  operation: Operation.SIGN,
@@ -119,6 +117,21 @@ class EnclaveSigner {
119
117
  reqId: traceId,
120
118
  connectionTracingEnabled: shouldSendMetrics,
121
119
  };
120
+ // Presignature path (SECP256K1 only): try consume before building params; fallback to normal sign.
121
+ if (curve === core_1.PortalCurve.SECP256K1 &&
122
+ this.featureFlags.usePresignatures === true &&
123
+ this.presignatureSource) {
124
+ const presignature = yield this.presignatureSource.consumePresignature(core_1.PortalCurve.SECP256K1);
125
+ if (presignature === null || presignature === void 0 ? void 0 : presignature.data) {
126
+ utils_1.sdkLogger.debug('[Portal] Signing with presignature (EnclaveSigner)', { method: message.method, chainId: message.chainId });
127
+ try {
128
+ return yield this.signWithPresignature(Object.assign(Object.assign({}, message), { presignatureData: presignature.data, traceId }), provider);
129
+ }
130
+ catch (presignError) {
131
+ utils_1.sdkLogger.warn('[Portal.Provider.EnclaveSigner] signWithPresignature failed, falling back to normal sign:', presignError);
132
+ }
133
+ }
134
+ }
122
135
  // Build params
123
136
  // Avoid double JSON encoding: if params is already a string (e.g. a hex message), pass it directly; otherwise stringify objects/arrays.
124
137
  const params = this.buildParams(method, message.params);
@@ -172,7 +185,7 @@ class EnclaveSigner {
172
185
  // Make API request and process response
173
186
  let result;
174
187
  try {
175
- const response = yield this.makeEnclaveRequest(endpoint, apiKey, requestBody);
188
+ const response = yield this.makeEnclaveRequest(endpoint, apiKey, requestBody, traceId);
176
189
  result = this.processEnclaveResponse(response);
177
190
  }
178
191
  catch (error) {
@@ -223,7 +236,7 @@ class EnclaveSigner {
223
236
  try {
224
237
  yield this.sendMetrics(metrics, apiKey);
225
238
  }
226
- catch (_a) {
239
+ catch (_b) {
227
240
  // No-op
228
241
  }
229
242
  }
@@ -268,15 +281,12 @@ class EnclaveSigner {
268
281
  * Make HTTP request to Enclave API
269
282
  * Returns raw response without processing
270
283
  */
271
- makeEnclaveRequest(endpoint, apiKey, body) {
284
+ makeEnclaveRequest(endpoint, apiKey, body, traceId) {
272
285
  return __awaiter(this, void 0, void 0, function* () {
273
- return yield this.requests.post(endpoint, {
274
- headers: {
286
+ return yield this.requests.post(endpoint, Object.assign({ headers: {
275
287
  Authorization: `Bearer ${apiKey}`,
276
288
  'Content-Type': 'application/json',
277
- },
278
- body,
279
- });
289
+ }, body }, (traceId ? { traceId } : {})));
280
290
  });
281
291
  }
282
292
  /**
@@ -374,5 +384,127 @@ class EnclaveSigner {
374
384
  }
375
385
  });
376
386
  }
387
+ /**
388
+ * Sign using a pre-generated presignature via the Enclave REST API.
389
+ * Uses the same endpoints as normal signing (/v1/sign, /v1/raw/sign/:curve)
390
+ * but includes the optional `presignature` field in the request body.
391
+ * NOTE: Only supports SECP256K1 curve.
392
+ */
393
+ signWithPresignature(message, provider) {
394
+ var _a;
395
+ return __awaiter(this, void 0, void 0, function* () {
396
+ const { method, chainId, isRaw = false, curve, presignatureData } = message;
397
+ const targetCurve = curve || core_1.PortalCurve.SECP256K1;
398
+ if (targetCurve !== core_1.PortalCurve.SECP256K1) {
399
+ throw new Error('[Portal.Provider.EnclaveSigner] Presignatures are only supported for SECP256K1 curve');
400
+ }
401
+ const shouldSendMetrics = this.featureFlags.enableSdkPerformanceMetrics;
402
+ const traceId = (_a = message.traceId) !== null && _a !== void 0 ? _a : (0, utils_1.generateTraceId)();
403
+ const metrics = {
404
+ hasError: false,
405
+ operation: 'signWithPresignature',
406
+ signingMethod: method,
407
+ traceId,
408
+ };
409
+ if (chainId) {
410
+ metrics.chainId = chainId;
411
+ }
412
+ const requestStartTime = performance.now();
413
+ try {
414
+ const preOperationStartTime = performance.now();
415
+ const apiKey = provider.apiKey;
416
+ if (!apiKey) {
417
+ throw new Error('[Portal.Provider.EnclaveSigner] The API key is missing.');
418
+ }
419
+ const shares = yield this.keychain.getShares();
420
+ const signingShare = shares.secp256k1.share;
421
+ if (!signingShare) {
422
+ throw new Error('[Portal.Provider.EnclaveSigner] The SECP256K1 share is missing from the keychain.');
423
+ }
424
+ const metadata = {
425
+ clientPlatform: 'REACT_NATIVE',
426
+ clientPlatformVersion: (0, utils_1.getClientPlatformVersion)(),
427
+ isMultiBackupEnabled: this.featureFlags.isMultiBackupEnabled,
428
+ mpcServerVersion: this.version,
429
+ optimized: true,
430
+ curve: core_1.PortalCurve.SECP256K1,
431
+ chainId,
432
+ isRaw,
433
+ reqId: traceId,
434
+ connectionTracingEnabled: shouldSendMetrics,
435
+ };
436
+ let endpoint;
437
+ let requestBody;
438
+ if (isRaw) {
439
+ const params = this.buildParams(method, message.params);
440
+ if (typeof params !== 'string') {
441
+ throw new Error('[Portal.Provider.EnclaveSigner] For raw signing with presignature, params must be a string (e.g., a hex-encoded message).');
442
+ }
443
+ endpoint = `/v1/raw/sign/${targetCurve}`;
444
+ requestBody = {
445
+ params,
446
+ share: JSON.stringify(signingShare),
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: (0, utils_1.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
+ utils_1.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
+ }
377
509
  }
378
510
  exports.default = EnclaveSigner;
@@ -8,21 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
12
  const core_1 = require("@portal-hq/core");
16
13
  const utils_1 = require("@portal-hq/utils");
17
14
  const react_native_1 = require("react-native");
18
- const react_native_uuid_1 = __importDefault(require("react-native-uuid"));
19
15
  var Operation;
20
16
  (function (Operation) {
21
17
  Operation["SIGN"] = "sign";
22
18
  Operation["RAW_SIGN"] = "raw_sign";
23
19
  })(Operation || (Operation = {}));
24
20
  class MpcSigner {
25
- constructor({ keychain, mpcHost = utils_1.DEFAULT_HOSTS.MPC, version = 'v6', portalApi, featureFlags = {}, }) {
21
+ constructor({ keychain, mpcHost = utils_1.DEFAULT_HOSTS.MPC, version = 'v6', portalApi, featureFlags = {}, presignatureSource, }) {
26
22
  this.version = 'v6';
27
23
  this.buildParams = (method, txParams) => {
28
24
  let params = txParams;
@@ -54,19 +50,21 @@ class MpcSigner {
54
50
  this.mpcHost = mpcHost;
55
51
  this.version = version;
56
52
  this.portalApi = portalApi;
53
+ this.presignatureSource = presignatureSource;
57
54
  if (!this.mpc) {
58
55
  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.`);
59
56
  }
60
57
  }
61
58
  sign(message, provider) {
59
+ var _a;
62
60
  return __awaiter(this, void 0, void 0, function* () {
63
61
  // Always track metrics, but only send if feature flag is enabled
64
62
  const shouldSendMetrics = this.featureFlags.enableSdkPerformanceMetrics === true;
65
63
  const signStartTime = performance.now();
66
64
  const preOperationStartTime = performance.now();
67
- // Generate a traceId for this operation
68
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
69
- const traceId = react_native_uuid_1.default.v4();
65
+ // Use traceId from message if available (e.g. options.traceId), otherwise generate a new UUID
66
+ const traceId = (_a = message.traceId) !== null && _a !== void 0 ? _a : (0, utils_1.generateTraceId)();
67
+ utils_1.sdkLogger.info(`[Portal MPC] sign started | method=${message.method} | traceId=${traceId} | chainId=${message.chainId} | curve=${message.curve}`);
70
68
  const metrics = {
71
69
  hasError: false,
72
70
  operation: Operation.SIGN,
@@ -126,6 +124,22 @@ class MpcSigner {
126
124
  if (typeof formattedParams !== 'string') {
127
125
  throw new Error(`[Portal.Provider.MpcSigner] The formatted params for the signing request could not be converted to a string. The params were: ${formattedParams}`);
128
126
  }
127
+ // Internal presignature handling (gated by feature flag): when usePresignatures is true and a
128
+ // presignature is available for SECP256K1, use signWithPresignature; otherwise normal sign().
129
+ if (curve === core_1.PortalCurve.SECP256K1 &&
130
+ this.featureFlags.usePresignatures === true &&
131
+ this.presignatureSource) {
132
+ const presignature = yield this.presignatureSource.consumePresignature(core_1.PortalCurve.SECP256K1);
133
+ if (presignature === null || presignature === void 0 ? void 0 : presignature.data) {
134
+ utils_1.sdkLogger.debug('[Portal] Signing with presignature (portal.request/sendAsset path)', { method: message.method, chainId: message.chainId });
135
+ try {
136
+ return yield this.signWithPresignature(Object.assign(Object.assign({}, message), { presignatureData: presignature.data, traceId }), provider);
137
+ }
138
+ catch (presignError) {
139
+ utils_1.sdkLogger.warn('[Portal.Provider.MpcSigner] signWithPresignature failed, falling back to normal sign:', presignError);
140
+ }
141
+ }
142
+ }
129
143
  // Record pre-operation time
130
144
  metrics.sdkPreOperationMs = performance.now() - preOperationStartTime;
131
145
  // Measure MPC signing operation time
@@ -188,7 +202,7 @@ class MpcSigner {
188
202
  try {
189
203
  yield this.sendMetrics(metrics, apiKey);
190
204
  }
191
- catch (_a) {
205
+ catch (_b) {
192
206
  // No-op
193
207
  }
194
208
  }
@@ -215,5 +229,133 @@ class MpcSigner {
215
229
  }
216
230
  });
217
231
  }
232
+ /**
233
+ * Sign a transaction using a pre-generated presignature
234
+ * NOTE: Only supports SECP256K1 curve
235
+ *
236
+ * @param message - Signing request with presignatureData
237
+ * @param provider - Portal provider instance
238
+ * @returns Signed transaction hash
239
+ */
240
+ signWithPresignature(message, provider) {
241
+ var _a;
242
+ return __awaiter(this, void 0, void 0, function* () {
243
+ const { method, chainId, isRaw = false, curve, sponsorGas, signatureApprovalMemo, presignatureData, } = message;
244
+ const targetCurve = curve || core_1.PortalCurve.SECP256K1;
245
+ if (targetCurve !== core_1.PortalCurve.SECP256K1) {
246
+ throw new Error('[Portal.Provider.MpcSigner] Presignatures are only supported for SECP256K1 curve');
247
+ }
248
+ const shouldSendMetrics = this.featureFlags.enableSdkPerformanceMetrics;
249
+ const traceId = (_a = message.traceId) !== null && _a !== void 0 ? _a : (0, utils_1.generateTraceId)();
250
+ const metrics = {
251
+ hasError: false,
252
+ operation: 'signWithPresignature',
253
+ signingMethod: method,
254
+ traceId,
255
+ };
256
+ if (chainId) {
257
+ metrics.chainId = chainId;
258
+ }
259
+ const requestStartTime = performance.now();
260
+ try {
261
+ const preOperationStartTime = performance.now();
262
+ const apiKey = provider.apiKey;
263
+ if (!apiKey) {
264
+ throw new Error('[Portal.Provider.MpcSigner] The API key is missing.');
265
+ }
266
+ const shares = yield this.keychain.getShares();
267
+ const signingShare = shares.secp256k1.share;
268
+ if (!signingShare) {
269
+ throw new Error('[Portal.Provider.MpcSigner] The SECP256K1 share is missing from the keychain.');
270
+ }
271
+ const metadata = {
272
+ clientPlatform: 'REACT_NATIVE',
273
+ clientPlatformVersion: (0, utils_1.getClientPlatformVersion)(),
274
+ isMultiBackupEnabled: this.featureFlags.isMultiBackupEnabled,
275
+ mpcServerVersion: this.version,
276
+ optimized: true,
277
+ curve: core_1.PortalCurve.SECP256K1,
278
+ chainId,
279
+ isRaw,
280
+ reqId: traceId,
281
+ connectionTracingEnabled: shouldSendMetrics,
282
+ sponsorGas,
283
+ signatureApprovalMemo,
284
+ };
285
+ const stringifiedMetadata = JSON.stringify(metadata);
286
+ let formattedParams;
287
+ let rpcUrl;
288
+ if (isRaw) {
289
+ formattedParams = this.buildParams(method, message.params);
290
+ rpcUrl = '';
291
+ metrics.operation = 'raw_signWithPresignature';
292
+ }
293
+ else {
294
+ formattedParams = JSON.stringify(this.buildParams(method, message.params));
295
+ rpcUrl = provider.getGatewayUrl(chainId);
296
+ }
297
+ if (typeof formattedParams !== 'string') {
298
+ throw new Error(`[Portal.Provider.MpcSigner] The formatted params for the signing request could not be converted to a string. The params were: ${formattedParams}`);
299
+ }
300
+ metrics.sdkPreOperationMs = performance.now() - preOperationStartTime;
301
+ const mpcSignStartTime = performance.now();
302
+ const result = yield this.mpc.signWithPresignature(apiKey, this.mpcHost, JSON.stringify(signingShare), presignatureData, method, formattedParams, rpcUrl, chainId, stringifiedMetadata);
303
+ const postOperationStartTime = performance.now();
304
+ metrics.mpcNativeCallMs = performance.now() - mpcSignStartTime;
305
+ const parsedResponse = JSON.parse(String(result));
306
+ const { data, error, meta } = parsedResponse;
307
+ if (meta === null || meta === void 0 ? void 0 : meta.metrics) {
308
+ const binaryMetrics = meta.metrics;
309
+ if (binaryMetrics.wsConnectDurationMs) {
310
+ metrics.sdkBinaryWSConnectMs = binaryMetrics.wsConnectDurationMs;
311
+ }
312
+ if (binaryMetrics.operationDurationMs) {
313
+ metrics.sdkBinaryOperationMs = binaryMetrics.operationDurationMs;
314
+ }
315
+ if (binaryMetrics.tlsHandshakeMs) {
316
+ metrics.sdkBinaryTlsHandshakeMs = binaryMetrics.tlsHandshakeMs;
317
+ }
318
+ if (binaryMetrics.firstResponseMs) {
319
+ metrics.sdkBinaryFirstResponseMs = binaryMetrics.firstResponseMs;
320
+ }
321
+ if (binaryMetrics.dnsLookupMs) {
322
+ metrics.sdkBinaryDnsLookupMs = binaryMetrics.dnsLookupMs;
323
+ }
324
+ if (binaryMetrics.connectMs) {
325
+ metrics.sdkBinaryConnectMs = binaryMetrics.connectMs;
326
+ }
327
+ }
328
+ if (error === null || error === void 0 ? void 0 : error.id) {
329
+ throw new utils_1.PortalMpcError(error);
330
+ }
331
+ metrics.sdkPostOperationMs = performance.now() - postOperationStartTime;
332
+ metrics.sdkOperationMs = performance.now() - requestStartTime;
333
+ if (shouldSendMetrics && this.portalApi) {
334
+ try {
335
+ yield this.sendMetrics(metrics, apiKey);
336
+ }
337
+ catch (error) {
338
+ // No-op
339
+ }
340
+ }
341
+ return data;
342
+ }
343
+ catch (error) {
344
+ utils_1.sdkLogger.error('[Portal.Provider.MpcSigner] signWithPresignature error:', error);
345
+ metrics.sdkOperationMs = performance.now() - requestStartTime;
346
+ metrics.hasError = true;
347
+ if (shouldSendMetrics && this.portalApi) {
348
+ const apiKey = provider.apiKey;
349
+ try {
350
+ yield this.sendMetrics(metrics, apiKey);
351
+ }
352
+ catch (metricsError) {
353
+ // No-op
354
+ }
355
+ }
356
+ throw error;
357
+ }
358
+ });
359
+ }
218
360
  }
219
361
  exports.default = MpcSigner;
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { PortalCurve } from '@portal-hq/core';
11
- import { Events, HttpRequester, InvalidApiKeyError, InvalidGatewayConfigError, PortalRequests, ProviderRpcError, RpcErrorCodes, DEFAULT_CHAIN_ID_CAIP2, CHAIN_NAMESPACES, DEFAULT_HOSTS, } from '@portal-hq/utils';
11
+ import { Events, HttpRequester, InvalidApiKeyError, InvalidGatewayConfigError, PortalRequests, ProviderRpcError, RpcErrorCodes, DEFAULT_CHAIN_ID_CAIP2, CHAIN_NAMESPACES, DEFAULT_HOSTS, generateTraceId, sdkLogger, } from '@portal-hq/utils';
12
12
  import { MpcSigner, EnclaveSigner } from '../signers';
13
13
  const passiveSignerMethods = [
14
14
  'eth_accounts',
@@ -42,7 +42,7 @@ class Provider {
42
42
  // Required
43
43
  apiKey, keychain, gatewayConfig,
44
44
  // Optional
45
- autoApprove = false, apiHost, mpcHost, enclaveMPCHost, version = 'v6', chainId = DEFAULT_CHAIN_ID_CAIP2, featureFlags = {}, }) {
45
+ autoApprove = false, apiHost, mpcHost, enclaveMPCHost, version = 'v6', chainId = DEFAULT_CHAIN_ID_CAIP2, featureFlags = {}, presignatureSource, }) {
46
46
  const finalApiHost = apiHost !== null && apiHost !== void 0 ? apiHost : DEFAULT_HOSTS.API;
47
47
  const finalMpcHost = mpcHost !== null && mpcHost !== void 0 ? mpcHost : DEFAULT_HOSTS.MPC;
48
48
  const finalEnclaveMPCHost = enclaveMPCHost !== null && enclaveMPCHost !== void 0 ? enclaveMPCHost : DEFAULT_HOSTS.ENCLAVE_MPC;
@@ -79,6 +79,10 @@ class Provider {
79
79
  version,
80
80
  portalApi: this.portalApi,
81
81
  featureFlags,
82
+ // Only pass presignatureSource when usePresignatures is enabled (same as MpcSigner).
83
+ presignatureSource: featureFlags.usePresignatures === true
84
+ ? presignatureSource
85
+ : undefined,
82
86
  });
83
87
  }
84
88
  else {
@@ -88,6 +92,10 @@ class Provider {
88
92
  version,
89
93
  portalApi: this.portalApi,
90
94
  featureFlags,
95
+ // Only pass presignatureSource when usePresignatures is enabled; otherwise signer always uses normal sign().
96
+ presignatureSource: featureFlags.usePresignatures === true
97
+ ? presignatureSource
98
+ : undefined,
91
99
  });
92
100
  }
93
101
  }
@@ -201,7 +209,7 @@ class Provider {
201
209
  * @param args The arguments of the request being made
202
210
  * @returns Promise<any>
203
211
  */
204
- request({ method, params, chainId, connect, }) {
212
+ request({ method, params, chainId, connect, options, }) {
205
213
  return __awaiter(this, void 0, void 0, function* () {
206
214
  chainId = chainId !== null && chainId !== void 0 ? chainId : this.chainId;
207
215
  if (!chainId) {
@@ -252,6 +260,7 @@ class Provider {
252
260
  params,
253
261
  chainId,
254
262
  connect,
263
+ options,
255
264
  });
256
265
  if (transactionHash) {
257
266
  try {
@@ -323,7 +332,7 @@ class Provider {
323
332
  this.dispatchConnect(chainId);
324
333
  }
325
334
  else {
326
- console.error(`[PortalProvider] Invalid chainId format. Must be 'namespace:reference', but got ${chainId}`);
335
+ sdkLogger.error(`[PortalProvider] Invalid chainId format. Must be 'namespace:reference', but got ${chainId}`);
327
336
  }
328
337
  return new Promise((resolve) => resolve(this));
329
338
  });
@@ -420,8 +429,8 @@ class Provider {
420
429
  * @param args The arguments of the request being made
421
430
  * @returns Promise<any>
422
431
  */
423
- handleSigningRequests({ method, params, chainId, connect, }) {
424
- var _a, _b;
432
+ handleSigningRequests({ method, params, chainId, connect, options, }) {
433
+ var _a, _b, _c;
425
434
  return __awaiter(this, void 0, void 0, function* () {
426
435
  const isApproved = passiveSignerMethods.includes(method)
427
436
  ? true
@@ -430,6 +439,7 @@ class Provider {
430
439
  this.log.info(`[PortalProvider] Request for signing method '${method}' could not be completed because it was not approved by the user.`);
431
440
  return;
432
441
  }
442
+ const traceId = (_a = options === null || options === void 0 ? void 0 : options.traceId) !== null && _a !== void 0 ? _a : generateTraceId();
433
443
  let namespace = CHAIN_NAMESPACES.EIP155;
434
444
  let reference = chainId;
435
445
  if (typeof chainId == 'string' && chainId.includes(':')) {
@@ -456,22 +466,28 @@ class Provider {
456
466
  case 'sol_signAndSendTransaction':
457
467
  case 'sol_signMessage':
458
468
  case 'sol_signTransaction': {
459
- const result = yield ((_a = this.signer) === null || _a === void 0 ? void 0 : _a.sign({
469
+ const result = yield ((_b = this.signer) === null || _b === void 0 ? void 0 : _b.sign({
460
470
  chainId: `${namespace}:${reference}`,
461
471
  method,
462
472
  params,
463
473
  curve,
464
474
  isRaw: false,
475
+ sponsorGas: options === null || options === void 0 ? void 0 : options.sponsorGas,
476
+ signatureApprovalMemo: options === null || options === void 0 ? void 0 : options.signatureApprovalMemo,
477
+ traceId,
465
478
  }, this));
466
479
  return result;
467
480
  }
468
481
  case 'raw_sign': {
469
- const result = yield ((_b = this.signer) === null || _b === void 0 ? void 0 : _b.sign({
470
- chainId: '',
471
- method: '',
482
+ const result = yield ((_c = this.signer) === null || _c === void 0 ? void 0 : _c.sign({
483
+ chainId: chainId !== null && chainId !== void 0 ? chainId : '',
484
+ method: 'raw_sign',
472
485
  params,
473
486
  curve,
474
487
  isRaw: true,
488
+ sponsorGas: options === null || options === void 0 ? void 0 : options.sponsorGas,
489
+ signatureApprovalMemo: options === null || options === void 0 ? void 0 : options.signatureApprovalMemo,
490
+ traceId,
475
491
  }, this));
476
492
  return result;
477
493
  }