@portal-hq/provider 3.0.6 → 4.0.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.
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ const core_1 = require("@portal-hq/core");
12
13
  const utils_1 = require("@portal-hq/utils");
13
14
  const signers_1 = require("../signers");
14
15
  const passiveSignerMethods = [
@@ -26,26 +27,28 @@ const signerMethods = [
26
27
  'eth_signTypedData_v3',
27
28
  'eth_signTypedData_v4',
28
29
  'personal_sign',
30
+ 'sol_signAndConfirmTransaction',
31
+ 'sol_signAndSendTransaction',
32
+ 'sol_signMessage',
33
+ 'sol_signTransaction',
34
+ 'raw_sign',
29
35
  ];
30
36
  class Provider {
31
- get address() {
32
- return this.keychain.getAddress(this.isSimulator);
37
+ get addresses() {
38
+ return this.keychain.getAddresses();
33
39
  }
34
- get gatewayUrl() {
35
- return this.getGatewayUrl();
40
+ get address() {
41
+ return this.keychain.getAddress();
36
42
  }
37
43
  constructor({
38
44
  // Required
39
- apiKey, chainId, keychain, gatewayConfig,
45
+ apiKey, keychain, gatewayConfig,
40
46
  // Optional
41
- isSimulator = false, autoApprove = false, apiHost = 'api.portalhq.io', mpcHost = 'mpc.portalhq.io', version = 'v6', featureFlags = { optimized: false }, }) {
47
+ autoApprove = false, apiHost = 'api.portalhq.io', mpcHost = 'mpc.portalhq.io', version = 'v6', chainId = 'eip155:11155111', featureFlags = {}, }) {
42
48
  // Handle required fields
43
49
  if (!apiKey || apiKey.length === 0) {
44
50
  throw new utils_1.InvalidApiKeyError();
45
51
  }
46
- if (!chainId) {
47
- throw new utils_1.InvalidChainIdError();
48
- }
49
52
  if (!gatewayConfig) {
50
53
  throw new utils_1.InvalidGatewayConfigError();
51
54
  }
@@ -55,7 +58,6 @@ class Provider {
55
58
  this.chainId = chainId;
56
59
  this.events = {};
57
60
  this.gatewayConfig = gatewayConfig;
58
- this.isSimulator = isSimulator;
59
61
  this.keychain = keychain;
60
62
  // Add a logger
61
63
  this.log = console;
@@ -66,9 +68,7 @@ class Provider {
66
68
  : `https://${apiHost}`,
67
69
  });
68
70
  // Initialize Gateway HttpRequester
69
- this.gateway = new utils_1.HttpRequester({
70
- baseUrl: this.getGatewayUrl(),
71
- });
71
+ this.gateway = new utils_1.PortalRequests();
72
72
  // Initialize an MpcSigner
73
73
  this.signer = new signers_1.MpcSigner({
74
74
  mpcHost,
@@ -101,24 +101,28 @@ class Provider {
101
101
  *
102
102
  * @returns string
103
103
  */
104
- getGatewayUrl() {
104
+ getGatewayUrl(chainId) {
105
+ chainId = chainId !== null && chainId !== void 0 ? chainId : this.chainId;
106
+ if (!chainId) {
107
+ throw new Error('[PortalProvider] No chainId provided');
108
+ }
105
109
  if (typeof this.gatewayConfig === 'string') {
106
110
  // If the gatewayConfig is just a static URL, return that
107
111
  return this.gatewayConfig;
108
112
  }
109
113
  else if (typeof this.gatewayConfig === 'object' &&
110
114
  // eslint-disable-next-line no-prototype-builtins
111
- !this.gatewayConfig.hasOwnProperty(this.chainId)) {
115
+ !this.gatewayConfig.hasOwnProperty(chainId)) {
112
116
  // If there's no explicit mapping for the current chainId, error out
113
- throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`);
117
+ throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${chainId}`);
114
118
  }
115
119
  // Get the entry for the current chainId from the gatewayConfig
116
- const config = this.gatewayConfig[this.chainId];
120
+ const config = this.gatewayConfig[chainId];
117
121
  if (typeof config === 'string') {
118
122
  return config;
119
123
  }
120
124
  // If we got this far, there's no way to support the chain with the current config
121
- throw new Error(`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}`);
125
+ throw new Error(`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${chainId}`);
122
126
  }
123
127
  /**
124
128
  * Registers an event handler for the provided event
@@ -185,14 +189,23 @@ class Provider {
185
189
  */
186
190
  request({ method, params, chainId, connect, }) {
187
191
  return __awaiter(this, void 0, void 0, function* () {
192
+ chainId = chainId !== null && chainId !== void 0 ? chainId : this.chainId;
193
+ if (!chainId) {
194
+ throw new Error('[PortalProvider] No chainId provided');
195
+ }
188
196
  if (method === 'eth_chainId') {
189
- return this.chainId;
197
+ if (typeof chainId === 'string' && chainId.includes(':')) {
198
+ return chainId.split(':')[1];
199
+ }
200
+ else {
201
+ throw new Error("[PortalProvider] Invalid chainId format. Must be 'namespace:reference'");
202
+ }
190
203
  }
191
204
  // Handle changing chains
192
205
  if (method == 'wallet_switchEthereumChain') {
193
206
  const param = params[0];
194
207
  const chainId = parseInt(param.chainId, 16);
195
- this.chainId = chainId;
208
+ this.chainId = `eip155:${String(chainId)}`;
196
209
  this.emit('portal_signatureReceived', {
197
210
  method,
198
211
  params,
@@ -203,7 +216,11 @@ class Provider {
203
216
  let result;
204
217
  if (!isSignerMethod && !method.startsWith('wallet_')) {
205
218
  // Send to Gateway for RPC calls
206
- const response = yield this.handleGatewayRequests({ method, params });
219
+ const response = yield this.handleGatewayRequests({
220
+ method,
221
+ params,
222
+ chainId,
223
+ });
207
224
  this.emit('portal_signatureReceived', {
208
225
  method,
209
226
  params,
@@ -222,6 +239,25 @@ class Provider {
222
239
  chainId,
223
240
  connect,
224
241
  });
242
+ if (transactionHash) {
243
+ try {
244
+ yield this.portalApi.post('/api/v1/analytics/track', {
245
+ headers: {
246
+ Authentication: `Bearer ${this.apiKey}`,
247
+ },
248
+ body: {
249
+ event: utils_1.Events.TransactionSigned,
250
+ properties: {
251
+ method,
252
+ },
253
+ },
254
+ });
255
+ }
256
+ catch (error) {
257
+ // Do nothing, because we don't want metrics gathering
258
+ // to block the SDK
259
+ }
260
+ }
225
261
  if (transactionHash) {
226
262
  this.emit('portal_signatureReceived', {
227
263
  method,
@@ -253,23 +289,29 @@ class Provider {
253
289
  */
254
290
  setChainId(chainId, connect) {
255
291
  return __awaiter(this, void 0, void 0, function* () {
292
+ if (typeof chainId === 'number') {
293
+ chainId = `eip155:${String(chainId)}`;
294
+ }
256
295
  // Update the chainId
257
296
  this.chainId = chainId;
258
- // Re-initialize the Gateway HttpRequester
259
- this.gateway = new utils_1.HttpRequester({
260
- baseUrl: this.getGatewayUrl(),
261
- });
262
- // Emit event for update
263
- this.emit('chainChanged', {
264
- chainId: this.chainId,
265
- });
266
- if (connect && connect.connected) {
267
- connect.emit('portalConnect_chainChanged', {
268
- chainId: this.chainId,
297
+ if (chainId.includes(':')) {
298
+ const chainIdParts = chainId.split(':');
299
+ const reference = parseInt(chainIdParts[1]);
300
+ // Emit event for update
301
+ this.emit('chainChanged', {
302
+ chainId: reference,
269
303
  });
304
+ if (connect && connect.connected) {
305
+ connect.emit('portalConnect_chainChanged', {
306
+ chainId: reference,
307
+ });
308
+ }
309
+ // Dispatch 'connect' event
310
+ this.dispatchConnect(chainId);
311
+ }
312
+ else {
313
+ console.error(`[PortalProvider] Invalid chainId format. Must be 'namespace:reference', but got ${chainId}`);
270
314
  }
271
- // Dispatch 'connect' event
272
- this.dispatchConnect();
273
315
  return new Promise((resolve) => resolve(this));
274
316
  });
275
317
  }
@@ -332,9 +374,10 @@ class Provider {
332
374
  });
333
375
  });
334
376
  }
335
- dispatchConnect() {
377
+ dispatchConnect(chainId) {
378
+ const reference = chainId.split(':')[1];
336
379
  this.emit('connect', {
337
- chainId: `0x${this.chainId.toString(16)}`,
380
+ chainId: `0x${Number(reference).toString(16)}`,
338
381
  });
339
382
  }
340
383
  /**
@@ -343,13 +386,15 @@ class Provider {
343
386
  * @param args The arguments of the request being made
344
387
  * @returns Promise<any>
345
388
  */
346
- handleGatewayRequests({ method, params, }) {
389
+ handleGatewayRequests({ method, params, chainId, }) {
347
390
  return __awaiter(this, void 0, void 0, function* () {
391
+ const gatewayUrl = this.getGatewayUrl(chainId);
348
392
  // Pass request off to the gateway
349
- return yield this.gateway.post('', {
393
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
394
+ return yield this.gateway.post(gatewayUrl, '', {
350
395
  body: {
351
396
  jsonrpc: '2.0',
352
- id: this.chainId,
397
+ id: chainId,
353
398
  method,
354
399
  params,
355
400
  },
@@ -363,7 +408,7 @@ class Provider {
363
408
  * @returns Promise<any>
364
409
  */
365
410
  handleSigningRequests({ method, params, chainId, connect, }) {
366
- var _a;
411
+ var _a, _b;
367
412
  return __awaiter(this, void 0, void 0, function* () {
368
413
  const isApproved = passiveSignerMethods.includes(method)
369
414
  ? true
@@ -372,9 +417,17 @@ class Provider {
372
417
  this.log.info(`[PortalProvider] Request for signing method '${method}' could not be completed because it was not approved by the user.`);
373
418
  return;
374
419
  }
420
+ let namespace = 'eip155';
421
+ let reference = chainId;
422
+ if (typeof chainId == 'string' && chainId.includes(':')) {
423
+ const tmp = chainId.split(':');
424
+ namespace = tmp[0];
425
+ reference = tmp[1];
426
+ }
427
+ const curve = namespace == 'eip155' ? core_1.PortalCurve.SECP256K1 : core_1.PortalCurve.ED25519;
375
428
  switch (method) {
376
429
  case 'eth_chainId':
377
- return `0x${this.chainId.toString(16)}`;
430
+ return `0x${Number(reference).toString(16)}`;
378
431
  case 'eth_accounts':
379
432
  case 'eth_requestAccounts':
380
433
  case 'eth_sendTransaction':
@@ -382,27 +435,28 @@ class Provider {
382
435
  case 'eth_signTransaction':
383
436
  case 'eth_signTypedData_v3':
384
437
  case 'eth_signTypedData_v4':
385
- case 'personal_sign': {
386
- const result = yield ((_a = this.signer) === null || _a === void 0 ? void 0 : _a.sign({ chainId: this.chainId, method, params }, this));
387
- if (result) {
388
- try {
389
- yield this.portalApi.post('/api/v1/analytics/track', {
390
- headers: {
391
- Authentication: `Bearer ${this.apiKey}`,
392
- },
393
- body: {
394
- event: utils_1.Events.TransactionSigned,
395
- properties: {
396
- method,
397
- },
398
- },
399
- });
400
- }
401
- catch (error) {
402
- // Do nothing, because we don't want metrics gathering
403
- // to block the SDK
404
- }
405
- }
438
+ case 'personal_sign':
439
+ case 'sol_signAndConfirmTransaction':
440
+ case 'sol_signAndSendTransaction':
441
+ case 'sol_signMessage':
442
+ case 'sol_signTransaction': {
443
+ const result = yield ((_a = this.signer) === null || _a === void 0 ? void 0 : _a.sign({
444
+ chainId: `${namespace}:${reference}`,
445
+ method,
446
+ params,
447
+ curve,
448
+ isRaw: false,
449
+ }, this));
450
+ return result;
451
+ }
452
+ case 'raw_sign': {
453
+ const result = yield ((_b = this.signer) === null || _b === void 0 ? void 0 : _b.sign({
454
+ chainId: '',
455
+ method: '',
456
+ params,
457
+ curve,
458
+ isRaw: true,
459
+ }, this));
406
460
  return result;
407
461
  }
408
462
  default:
@@ -9,16 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ const core_1 = require("@portal-hq/core");
12
13
  const utils_1 = require("@portal-hq/utils");
13
14
  const react_native_1 = require("react-native");
14
15
  class MpcSigner {
15
- get address() {
16
- return this.keychain.getAddress(this.isSimulator);
17
- }
18
- get signingShare() {
19
- return this.keychain.getDkgResult(this.isSimulator);
20
- }
21
- constructor({ keychain, isSimulator = false, mpcHost = 'mpc.portalhq.io', version = 'v6', featureFlags = { optimized: false }, }) {
16
+ constructor({ keychain, mpcHost = 'mpc.portalhq.io', version = 'v6', featureFlags = {}, }) {
22
17
  this.version = 'v6';
23
18
  this.buildParams = (method, txParams) => {
24
19
  let params = txParams;
@@ -27,18 +22,23 @@ class MpcSigner {
27
22
  case 'personal_sign':
28
23
  case 'eth_signTypedData_v3':
29
24
  case 'eth_signTypedData_v4':
25
+ case 'sol_signMessage':
26
+ case 'sol_signTransaction':
27
+ case 'sol_signAndSendTransaction':
28
+ case 'sol_signAndConfirmTransaction':
30
29
  if (!Array.isArray(txParams)) {
31
30
  params = [txParams];
32
31
  }
33
32
  break;
34
33
  default:
35
34
  if (Array.isArray(txParams)) {
36
- params = txParams[0];
35
+ if (txParams.length === 1) {
36
+ params = txParams[0];
37
+ }
37
38
  }
38
39
  }
39
40
  return params;
40
41
  };
41
- this.isSimulator = isSimulator;
42
42
  this.keychain = keychain;
43
43
  this.mpc = react_native_1.NativeModules.PortalMobileMpc;
44
44
  this.mpcHost = mpcHost;
@@ -50,26 +50,49 @@ class MpcSigner {
50
50
  }
51
51
  sign(message, provider) {
52
52
  return __awaiter(this, void 0, void 0, function* () {
53
- const address = yield this.address;
53
+ const eip155Address = yield this.keychain.getEip155Address();
54
54
  const apiKey = provider.apiKey;
55
- const { method, params } = message;
55
+ const { method, chainId, curve, isRaw } = message;
56
56
  switch (method) {
57
57
  case 'eth_requestAccounts':
58
- return [address];
58
+ return [eip155Address];
59
59
  case 'eth_accounts':
60
- return [address];
60
+ return [eip155Address];
61
61
  default:
62
62
  break;
63
63
  }
64
- const signingShare = yield this.signingShare;
64
+ const shares = yield this.keychain.getShares();
65
+ let signingShare = shares.secp256k1.share;
66
+ if (curve === core_1.PortalCurve.ED25519) {
67
+ if (!shares.ed25519) {
68
+ throw new Error('[Portal.Provider.MpcSigner] The ED25519 share is missing from the keychain.');
69
+ }
70
+ signingShare = shares.ed25519.share;
71
+ }
65
72
  const metadata = {
66
73
  clientPlatform: 'REACT_NATIVE',
67
74
  isMultiBackupEnabled: this.featureFlags.isMultiBackupEnabled,
68
75
  mpcServerVersion: this.version,
69
- optimized: this.featureFlags.optimized,
76
+ optimized: true,
77
+ curve,
78
+ chainId,
79
+ isRaw,
70
80
  };
71
81
  const stringifiedMetadata = JSON.stringify(metadata);
72
- const result = yield this.mpc.sign(apiKey, this.mpcHost, signingShare, message.method, JSON.stringify(this.buildParams(method, params)), provider.gatewayUrl, provider.chainId.toString(), stringifiedMetadata);
82
+ let formattedParams;
83
+ let rpcUrl;
84
+ if (isRaw) {
85
+ formattedParams = this.buildParams(method, message.params);
86
+ rpcUrl = '';
87
+ }
88
+ else {
89
+ formattedParams = JSON.stringify(this.buildParams(method, message.params));
90
+ rpcUrl = provider.getGatewayUrl(chainId);
91
+ }
92
+ if (typeof formattedParams !== 'string') {
93
+ throw new Error(`[Portal.Provider.MpcSigner] The formatted params for the signing request could not be converted to a string. The params were: ${formattedParams}`);
94
+ }
95
+ const result = yield this.mpc.sign(apiKey, this.mpcHost, JSON.stringify(signingShare), message.method, formattedParams, rpcUrl, chainId, stringifiedMetadata);
73
96
  const { data, error } = JSON.parse(String(result));
74
97
  if (error && error.code > 0) {
75
98
  throw new utils_1.PortalMpcError(error);