@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.
- package/lib/commonjs/providers/index.js +116 -62
- package/lib/commonjs/signers/mpc.js +39 -16
- package/lib/esm/providers/index.js +117 -63
- package/lib/esm/signers/mpc.js +39 -16
- package/package.json +4 -4
- package/src/providers/index.ts +129 -71
- package/src/signers/mpc.ts +53 -24
- package/types.d.ts +6 -3
|
@@ -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
|
|
32
|
-
return this.keychain.
|
|
37
|
+
get addresses() {
|
|
38
|
+
return this.keychain.getAddresses();
|
|
33
39
|
}
|
|
34
|
-
get
|
|
35
|
-
return this.
|
|
40
|
+
get address() {
|
|
41
|
+
return this.keychain.getAddress();
|
|
36
42
|
}
|
|
37
43
|
constructor({
|
|
38
44
|
// Required
|
|
39
|
-
apiKey,
|
|
45
|
+
apiKey, keychain, gatewayConfig,
|
|
40
46
|
// Optional
|
|
41
|
-
|
|
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.
|
|
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(
|
|
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: ${
|
|
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[
|
|
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: ${
|
|
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
|
-
|
|
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({
|
|
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
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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${
|
|
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
|
-
|
|
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:
|
|
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${
|
|
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
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
53
|
+
const eip155Address = yield this.keychain.getEip155Address();
|
|
54
54
|
const apiKey = provider.apiKey;
|
|
55
|
-
const { method,
|
|
55
|
+
const { method, chainId, curve, isRaw } = message;
|
|
56
56
|
switch (method) {
|
|
57
57
|
case 'eth_requestAccounts':
|
|
58
|
-
return [
|
|
58
|
+
return [eip155Address];
|
|
59
59
|
case 'eth_accounts':
|
|
60
|
-
return [
|
|
60
|
+
return [eip155Address];
|
|
61
61
|
default:
|
|
62
62
|
break;
|
|
63
63
|
}
|
|
64
|
-
const
|
|
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:
|
|
76
|
+
optimized: true,
|
|
77
|
+
curve,
|
|
78
|
+
chainId,
|
|
79
|
+
isRaw,
|
|
70
80
|
};
|
|
71
81
|
const stringifiedMetadata = JSON.stringify(metadata);
|
|
72
|
-
|
|
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);
|