@portal-hq/provider 0.2.16 → 0.2.18
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 +66 -70
- package/lib/commonjs/signers/abstract.js +6 -1
- package/lib/commonjs/signers/index.js +1 -3
- package/lib/commonjs/signers/mpc.js +8 -10
- package/lib/esm/providers/index.js +65 -69
- package/lib/esm/signers/abstract.js +6 -1
- package/lib/esm/signers/index.js +0 -1
- package/lib/esm/signers/mpc.js +8 -10
- package/package.json +9 -3
- package/src/providers/index.ts +93 -97
- package/src/signers/abstract.ts +6 -1
- package/src/signers/index.ts +0 -1
- package/src/signers/mpc.ts +13 -21
- package/types.d.ts +1 -10
- package/src/requesters/http.ts +0 -61
- package/src/requesters/index.ts +0 -1
- package/src/signers/http.ts +0 -77
|
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const utils_1 = require("@portal-hq/utils");
|
|
13
|
-
const requesters_1 = require("../requesters");
|
|
14
13
|
const signers_1 = require("../signers");
|
|
15
14
|
const passiveSignerMethods = [
|
|
16
15
|
'eth_accounts',
|
|
@@ -32,8 +31,7 @@ class Provider {
|
|
|
32
31
|
// Required options
|
|
33
32
|
apiKey, chainId, keychain,
|
|
34
33
|
// Optional options
|
|
35
|
-
apiUrl = 'api.portalhq.io', autoApprove = false,
|
|
36
|
-
this._address = '';
|
|
34
|
+
apiUrl = 'api.portalhq.io', autoApprove = false, mpcUrl = 'mpc.portalhq.io', gatewayConfig = {}, }) {
|
|
37
35
|
// Handle required fields
|
|
38
36
|
if (!apiKey || apiKey.length === 0) {
|
|
39
37
|
throw new utils_1.InvalidApiKeyError();
|
|
@@ -49,47 +47,33 @@ class Provider {
|
|
|
49
47
|
this.apiUrl = apiUrl;
|
|
50
48
|
this.autoApprove = autoApprove;
|
|
51
49
|
this.chainId = chainId;
|
|
50
|
+
this.connected = false;
|
|
52
51
|
this.events = {};
|
|
53
|
-
this.
|
|
52
|
+
this.gatewayConfig = gatewayConfig;
|
|
53
|
+
this.isMPC = true;
|
|
54
54
|
this.keychain = keychain;
|
|
55
|
-
this.log = console;
|
|
56
55
|
this.mpcUrl = mpcUrl;
|
|
57
|
-
this.
|
|
56
|
+
this.rpcUrl = this.getRpcUrl();
|
|
57
|
+
// Add a logger
|
|
58
|
+
this.log = console;
|
|
59
|
+
// Initialize Portal API HttpRequester
|
|
60
|
+
this.portal = new utils_1.HttpRequester({
|
|
58
61
|
baseUrl: this.apiUrl,
|
|
59
62
|
});
|
|
60
|
-
//
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
// Initialize Gateway HttpRequester
|
|
64
|
+
this.rpc = new utils_1.HttpRequester({
|
|
65
|
+
baseUrl: this.rpcUrl,
|
|
66
|
+
});
|
|
67
|
+
// Initialize an MpcSigner
|
|
68
|
+
this.signer = new signers_1.MpcSigner({
|
|
69
|
+
mpcUrl: this.mpcUrl,
|
|
70
|
+
keychain: this.keychain,
|
|
71
|
+
});
|
|
72
|
+
this.signer.getAddress().then((address) => {
|
|
73
|
+
if (typeof address !== 'undefined' && address.length) {
|
|
74
|
+
this.address = address;
|
|
75
|
+
}
|
|
64
76
|
});
|
|
65
|
-
if (this.isMPC) {
|
|
66
|
-
// If MPC is enabled, initialize an MpcSigner
|
|
67
|
-
this.signer = new signers_1.MpcSigner({
|
|
68
|
-
mpcUrl: this.mpcUrl,
|
|
69
|
-
keychain: this.keychain,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
// If MPC is disabled, initialize an HttpSigner, talking to whatever httpHost was provided
|
|
74
|
-
this.signer = new signers_1.HttpSigner({
|
|
75
|
-
keychain: this.keychain,
|
|
76
|
-
portal: this.portal,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
this.dispatchConnect();
|
|
80
|
-
}
|
|
81
|
-
get address() {
|
|
82
|
-
return this._address;
|
|
83
|
-
}
|
|
84
|
-
set address(value) {
|
|
85
|
-
this._address = value;
|
|
86
|
-
if (this.signer && this.isMPC) {
|
|
87
|
-
;
|
|
88
|
-
this.signer._address = value;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
get rpcUrl() {
|
|
92
|
-
return this.getRpcUrl();
|
|
93
77
|
}
|
|
94
78
|
/**
|
|
95
79
|
* Invokes all registered event handlers with the data provided
|
|
@@ -110,6 +94,29 @@ class Provider {
|
|
|
110
94
|
this.events[event] = handlers.filter((handler) => !handler.once);
|
|
111
95
|
return this;
|
|
112
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Determines the RPC URL to be used for the current chain
|
|
99
|
+
*
|
|
100
|
+
* @returns string
|
|
101
|
+
*/
|
|
102
|
+
getRpcUrl() {
|
|
103
|
+
if (typeof this.gatewayConfig === 'string') {
|
|
104
|
+
// If the gatewayConfig is just a static URL, return that
|
|
105
|
+
return this.gatewayConfig;
|
|
106
|
+
}
|
|
107
|
+
else if (typeof this.gatewayConfig === 'object' &&
|
|
108
|
+
!this.gatewayConfig.hasOwnProperty(this.chainId)) {
|
|
109
|
+
// If there's no explicit mapping for the current chainId, error out
|
|
110
|
+
throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`);
|
|
111
|
+
}
|
|
112
|
+
// Get the entry for the current chainId from the gatewayConfig
|
|
113
|
+
const config = this.gatewayConfig[this.chainId];
|
|
114
|
+
if (typeof config === 'string') {
|
|
115
|
+
return config;
|
|
116
|
+
}
|
|
117
|
+
// If we got this far, there's no way to support the chain with the current config
|
|
118
|
+
throw new Error(`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}`);
|
|
119
|
+
}
|
|
113
120
|
/**
|
|
114
121
|
* Registers an event handler for the provided event
|
|
115
122
|
*
|
|
@@ -154,7 +161,6 @@ class Provider {
|
|
|
154
161
|
}
|
|
155
162
|
removeEventListener(event, listenerToRemove) {
|
|
156
163
|
if (!this.events[event]) {
|
|
157
|
-
this.log.info(`[PortalProvider] Attempted to remove a listener from unregistered event '${event}'. Ignoring.`);
|
|
158
164
|
return;
|
|
159
165
|
}
|
|
160
166
|
if (!listenerToRemove) {
|
|
@@ -201,7 +207,6 @@ class Provider {
|
|
|
201
207
|
params,
|
|
202
208
|
});
|
|
203
209
|
if (transactionHash) {
|
|
204
|
-
console.log(`Received transaction hash: `, transactionHash);
|
|
205
210
|
this.emit('portal_signatureReceived', {
|
|
206
211
|
method,
|
|
207
212
|
params,
|
|
@@ -223,6 +228,12 @@ class Provider {
|
|
|
223
228
|
return result;
|
|
224
229
|
});
|
|
225
230
|
}
|
|
231
|
+
setAddress(address) {
|
|
232
|
+
this.address = address;
|
|
233
|
+
if (!this.connected) {
|
|
234
|
+
this.dispatchConnect();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
226
237
|
/**
|
|
227
238
|
* Updates the chainId of this instance and builds a new RPC HttpRequester for
|
|
228
239
|
* the gateway used for the new chain
|
|
@@ -230,13 +241,22 @@ class Provider {
|
|
|
230
241
|
* @param chainId A hex string of the chainId to use for this connection
|
|
231
242
|
* @returns BaseProvider
|
|
232
243
|
*/
|
|
233
|
-
|
|
244
|
+
setChainId(chainId) {
|
|
234
245
|
return __awaiter(this, void 0, void 0, function* () {
|
|
246
|
+
// Disconnect from the current chain
|
|
247
|
+
this.connected = false;
|
|
248
|
+
// Update the chainId
|
|
235
249
|
this.chainId = Number(`${chainId}`);
|
|
236
|
-
|
|
250
|
+
// Re-initialize the Gateway HttpRequester
|
|
251
|
+
this.rpc = new utils_1.HttpRequester({
|
|
237
252
|
baseUrl: this.getRpcUrl(),
|
|
238
253
|
});
|
|
239
|
-
|
|
254
|
+
// Emit event for update
|
|
255
|
+
this.emit('chainChanged', {
|
|
256
|
+
chainId: this.chainId,
|
|
257
|
+
});
|
|
258
|
+
// Dispatch 'connect' event
|
|
259
|
+
this.dispatchConnect();
|
|
240
260
|
return this;
|
|
241
261
|
});
|
|
242
262
|
}
|
|
@@ -251,7 +271,8 @@ class Provider {
|
|
|
251
271
|
if (this.autoApprove) {
|
|
252
272
|
return true;
|
|
253
273
|
}
|
|
254
|
-
|
|
274
|
+
const signingHandlers = this.events['portal_signingRequested'];
|
|
275
|
+
if (!signingHandlers || signingHandlers.length === 0) {
|
|
255
276
|
throw new Error(`[PortalProvider] Auto-approve is disabled. Cannot perform signing requests without an event handler for the 'portal_signingRequested' event.`);
|
|
256
277
|
}
|
|
257
278
|
return new Promise((resolve) => {
|
|
@@ -260,7 +281,6 @@ class Provider {
|
|
|
260
281
|
this.removeEventListener('portal_signingRejected');
|
|
261
282
|
// If the signing has been approved, resolve to true
|
|
262
283
|
this.once('portal_signingApproved', ({ method: approvedMethod, params: approvedParams }) => {
|
|
263
|
-
console.log(`[PortalProvider] Signing Approved`, method, params);
|
|
264
284
|
// Remove already used listeners
|
|
265
285
|
this.removeEventListener('portal_signingApproved');
|
|
266
286
|
this.removeEventListener('portal_signingRejected');
|
|
@@ -272,7 +292,6 @@ class Provider {
|
|
|
272
292
|
});
|
|
273
293
|
// If the signing request has been rejected, resolve to false
|
|
274
294
|
this.once('portal_signingRejected', ({ method: rejectedMethod, params: rejectedParams }) => {
|
|
275
|
-
console.log(`[PortalProvider] Signing Approved`, method, params);
|
|
276
295
|
// Remove already used listeners
|
|
277
296
|
this.removeEventListener('portal_signingApproved');
|
|
278
297
|
this.removeEventListener('portal_signingRejected');
|
|
@@ -292,35 +311,12 @@ class Provider {
|
|
|
292
311
|
}
|
|
293
312
|
dispatchConnect() {
|
|
294
313
|
return __awaiter(this, void 0, void 0, function* () {
|
|
295
|
-
|
|
314
|
+
this.connected = true;
|
|
296
315
|
this.emit('connect', {
|
|
297
316
|
chainId: `0x${this.chainId.toString(16)}`,
|
|
298
317
|
});
|
|
299
318
|
});
|
|
300
319
|
}
|
|
301
|
-
/**
|
|
302
|
-
* Determines the RPC URL to be used for the current chain
|
|
303
|
-
*
|
|
304
|
-
* @returns string
|
|
305
|
-
*/
|
|
306
|
-
getRpcUrl() {
|
|
307
|
-
if (typeof this.gatewayConfig === 'string') {
|
|
308
|
-
// If the gatewayConfig is just a static URL, return that
|
|
309
|
-
return this.gatewayConfig;
|
|
310
|
-
}
|
|
311
|
-
else if (typeof this.gatewayConfig === 'object' &&
|
|
312
|
-
!this.gatewayConfig.hasOwnProperty(this.chainId)) {
|
|
313
|
-
// If there's no explicit mapping for the current chainId, error out
|
|
314
|
-
throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`);
|
|
315
|
-
}
|
|
316
|
-
// Get the entry for the current chainId from the gatewayConfig
|
|
317
|
-
const config = this.gatewayConfig[this.chainId];
|
|
318
|
-
if (typeof config === 'string') {
|
|
319
|
-
return config;
|
|
320
|
-
}
|
|
321
|
-
// If we got this far, there's no way to support the chain with the current config
|
|
322
|
-
throw new Error(`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}`);
|
|
323
|
-
}
|
|
324
320
|
/**
|
|
325
321
|
* Sends the provided request payload along to the RPC HttpRequester
|
|
326
322
|
*
|
|
@@ -10,9 +10,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
class Signer {
|
|
13
|
+
getAddress() {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
throw new Error(`[Portal] getAddress() method must be implemented as a subclass of Signer`);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
13
18
|
sign(_, __) {
|
|
14
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
throw new Error('[Portal] sign() method must be implemented in a
|
|
20
|
+
throw new Error('[Portal] sign() method must be implemented in a subclass of Signer');
|
|
16
21
|
});
|
|
17
22
|
}
|
|
18
23
|
}
|
|
@@ -3,10 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.MpcSigner = exports.
|
|
6
|
+
exports.MpcSigner = exports.Signer = void 0;
|
|
7
7
|
var abstract_1 = require("./abstract");
|
|
8
8
|
Object.defineProperty(exports, "Signer", { enumerable: true, get: function () { return __importDefault(abstract_1).default; } });
|
|
9
|
-
var http_1 = require("./http");
|
|
10
|
-
Object.defineProperty(exports, "HttpSigner", { enumerable: true, get: function () { return __importDefault(http_1).default; } });
|
|
11
9
|
var mpc_1 = require("./mpc");
|
|
12
10
|
Object.defineProperty(exports, "MpcSigner", { enumerable: true, get: function () { return __importDefault(mpc_1).default; } });
|
|
@@ -13,7 +13,6 @@ const react_native_1 = require("react-native");
|
|
|
13
13
|
const utils_1 = require("@portal-hq/utils");
|
|
14
14
|
class MpcSigner {
|
|
15
15
|
constructor(opts) {
|
|
16
|
-
this._address = '';
|
|
17
16
|
this.buildParams = (method, txParams) => {
|
|
18
17
|
let params = txParams;
|
|
19
18
|
switch (method) {
|
|
@@ -37,15 +36,17 @@ class MpcSigner {
|
|
|
37
36
|
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.`);
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
|
-
|
|
41
|
-
return
|
|
42
|
-
if (this.
|
|
43
|
-
return this.
|
|
39
|
+
getAddress() {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
if (this.address) {
|
|
42
|
+
return this.address;
|
|
44
43
|
}
|
|
45
44
|
const address = yield this.keychain.getAddress();
|
|
46
|
-
|
|
45
|
+
if (typeof address !== 'undefined' && address.length) {
|
|
46
|
+
this.address = address;
|
|
47
|
+
}
|
|
47
48
|
return address;
|
|
48
|
-
})
|
|
49
|
+
});
|
|
49
50
|
}
|
|
50
51
|
sign(message, provider) {
|
|
51
52
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -60,11 +61,8 @@ class MpcSigner {
|
|
|
60
61
|
default:
|
|
61
62
|
break;
|
|
62
63
|
}
|
|
63
|
-
console.log(`[Portal:MpcSigner] Requesting signature from PortalMobileMpc for:`, JSON.stringify(message, null, 2));
|
|
64
64
|
const dkg = yield this.keychain.getDkgResult();
|
|
65
|
-
console.log(`[PortalMpcSigner] RPC URL: ${provider.rpcUrl}`);
|
|
66
65
|
const result = yield this.mpc.sign(apiKey, this.mpcUrl, dkg, message.method, JSON.stringify(this.buildParams(method, params)), provider.rpcUrl, provider.chainId.toString());
|
|
67
|
-
console.log(`[PortalMpcSigner] Result: `, result);
|
|
68
66
|
const { data, error } = JSON.parse(String(result));
|
|
69
67
|
if (error && error.length) {
|
|
70
68
|
throw new utils_1.MpcSigningError(error);
|
|
@@ -7,9 +7,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { InvalidApiKeyError, InvalidChainIdError, InvalidGatewayConfigError, ProviderRpcError, RpcErrorCodes, } from '@portal-hq/utils';
|
|
11
|
-
import {
|
|
12
|
-
import { HttpSigner, MpcSigner } from '../signers';
|
|
10
|
+
import { HttpRequester, InvalidApiKeyError, InvalidChainIdError, InvalidGatewayConfigError, ProviderRpcError, RpcErrorCodes, } from '@portal-hq/utils';
|
|
11
|
+
import { MpcSigner } from '../signers';
|
|
13
12
|
const passiveSignerMethods = [
|
|
14
13
|
'eth_accounts',
|
|
15
14
|
'eth_chainId',
|
|
@@ -30,8 +29,7 @@ class Provider {
|
|
|
30
29
|
// Required options
|
|
31
30
|
apiKey, chainId, keychain,
|
|
32
31
|
// Optional options
|
|
33
|
-
apiUrl = 'api.portalhq.io', autoApprove = false,
|
|
34
|
-
this._address = '';
|
|
32
|
+
apiUrl = 'api.portalhq.io', autoApprove = false, mpcUrl = 'mpc.portalhq.io', gatewayConfig = {}, }) {
|
|
35
33
|
// Handle required fields
|
|
36
34
|
if (!apiKey || apiKey.length === 0) {
|
|
37
35
|
throw new InvalidApiKeyError();
|
|
@@ -47,47 +45,33 @@ class Provider {
|
|
|
47
45
|
this.apiUrl = apiUrl;
|
|
48
46
|
this.autoApprove = autoApprove;
|
|
49
47
|
this.chainId = chainId;
|
|
48
|
+
this.connected = false;
|
|
50
49
|
this.events = {};
|
|
51
|
-
this.
|
|
50
|
+
this.gatewayConfig = gatewayConfig;
|
|
51
|
+
this.isMPC = true;
|
|
52
52
|
this.keychain = keychain;
|
|
53
|
-
this.log = console;
|
|
54
53
|
this.mpcUrl = mpcUrl;
|
|
54
|
+
this.rpcUrl = this.getRpcUrl();
|
|
55
|
+
// Add a logger
|
|
56
|
+
this.log = console;
|
|
57
|
+
// Initialize Portal API HttpRequester
|
|
55
58
|
this.portal = new HttpRequester({
|
|
56
59
|
baseUrl: this.apiUrl,
|
|
57
60
|
});
|
|
58
|
-
//
|
|
59
|
-
this.gatewayConfig = gatewayConfig;
|
|
61
|
+
// Initialize Gateway HttpRequester
|
|
60
62
|
this.rpc = new HttpRequester({
|
|
61
|
-
baseUrl: this.
|
|
63
|
+
baseUrl: this.rpcUrl,
|
|
64
|
+
});
|
|
65
|
+
// Initialize an MpcSigner
|
|
66
|
+
this.signer = new MpcSigner({
|
|
67
|
+
mpcUrl: this.mpcUrl,
|
|
68
|
+
keychain: this.keychain,
|
|
69
|
+
});
|
|
70
|
+
this.signer.getAddress().then((address) => {
|
|
71
|
+
if (typeof address !== 'undefined' && address.length) {
|
|
72
|
+
this.address = address;
|
|
73
|
+
}
|
|
62
74
|
});
|
|
63
|
-
if (this.isMPC) {
|
|
64
|
-
// If MPC is enabled, initialize an MpcSigner
|
|
65
|
-
this.signer = new MpcSigner({
|
|
66
|
-
mpcUrl: this.mpcUrl,
|
|
67
|
-
keychain: this.keychain,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
// If MPC is disabled, initialize an HttpSigner, talking to whatever httpHost was provided
|
|
72
|
-
this.signer = new HttpSigner({
|
|
73
|
-
keychain: this.keychain,
|
|
74
|
-
portal: this.portal,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
this.dispatchConnect();
|
|
78
|
-
}
|
|
79
|
-
get address() {
|
|
80
|
-
return this._address;
|
|
81
|
-
}
|
|
82
|
-
set address(value) {
|
|
83
|
-
this._address = value;
|
|
84
|
-
if (this.signer && this.isMPC) {
|
|
85
|
-
;
|
|
86
|
-
this.signer._address = value;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
get rpcUrl() {
|
|
90
|
-
return this.getRpcUrl();
|
|
91
75
|
}
|
|
92
76
|
/**
|
|
93
77
|
* Invokes all registered event handlers with the data provided
|
|
@@ -108,6 +92,29 @@ class Provider {
|
|
|
108
92
|
this.events[event] = handlers.filter((handler) => !handler.once);
|
|
109
93
|
return this;
|
|
110
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Determines the RPC URL to be used for the current chain
|
|
97
|
+
*
|
|
98
|
+
* @returns string
|
|
99
|
+
*/
|
|
100
|
+
getRpcUrl() {
|
|
101
|
+
if (typeof this.gatewayConfig === 'string') {
|
|
102
|
+
// If the gatewayConfig is just a static URL, return that
|
|
103
|
+
return this.gatewayConfig;
|
|
104
|
+
}
|
|
105
|
+
else if (typeof this.gatewayConfig === 'object' &&
|
|
106
|
+
!this.gatewayConfig.hasOwnProperty(this.chainId)) {
|
|
107
|
+
// If there's no explicit mapping for the current chainId, error out
|
|
108
|
+
throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`);
|
|
109
|
+
}
|
|
110
|
+
// Get the entry for the current chainId from the gatewayConfig
|
|
111
|
+
const config = this.gatewayConfig[this.chainId];
|
|
112
|
+
if (typeof config === 'string') {
|
|
113
|
+
return config;
|
|
114
|
+
}
|
|
115
|
+
// If we got this far, there's no way to support the chain with the current config
|
|
116
|
+
throw new Error(`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}`);
|
|
117
|
+
}
|
|
111
118
|
/**
|
|
112
119
|
* Registers an event handler for the provided event
|
|
113
120
|
*
|
|
@@ -152,7 +159,6 @@ class Provider {
|
|
|
152
159
|
}
|
|
153
160
|
removeEventListener(event, listenerToRemove) {
|
|
154
161
|
if (!this.events[event]) {
|
|
155
|
-
this.log.info(`[PortalProvider] Attempted to remove a listener from unregistered event '${event}'. Ignoring.`);
|
|
156
162
|
return;
|
|
157
163
|
}
|
|
158
164
|
if (!listenerToRemove) {
|
|
@@ -199,7 +205,6 @@ class Provider {
|
|
|
199
205
|
params,
|
|
200
206
|
});
|
|
201
207
|
if (transactionHash) {
|
|
202
|
-
console.log(`Received transaction hash: `, transactionHash);
|
|
203
208
|
this.emit('portal_signatureReceived', {
|
|
204
209
|
method,
|
|
205
210
|
params,
|
|
@@ -221,6 +226,12 @@ class Provider {
|
|
|
221
226
|
return result;
|
|
222
227
|
});
|
|
223
228
|
}
|
|
229
|
+
setAddress(address) {
|
|
230
|
+
this.address = address;
|
|
231
|
+
if (!this.connected) {
|
|
232
|
+
this.dispatchConnect();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
224
235
|
/**
|
|
225
236
|
* Updates the chainId of this instance and builds a new RPC HttpRequester for
|
|
226
237
|
* the gateway used for the new chain
|
|
@@ -228,13 +239,22 @@ class Provider {
|
|
|
228
239
|
* @param chainId A hex string of the chainId to use for this connection
|
|
229
240
|
* @returns BaseProvider
|
|
230
241
|
*/
|
|
231
|
-
|
|
242
|
+
setChainId(chainId) {
|
|
232
243
|
return __awaiter(this, void 0, void 0, function* () {
|
|
244
|
+
// Disconnect from the current chain
|
|
245
|
+
this.connected = false;
|
|
246
|
+
// Update the chainId
|
|
233
247
|
this.chainId = Number(`${chainId}`);
|
|
248
|
+
// Re-initialize the Gateway HttpRequester
|
|
234
249
|
this.rpc = new HttpRequester({
|
|
235
250
|
baseUrl: this.getRpcUrl(),
|
|
236
251
|
});
|
|
237
|
-
|
|
252
|
+
// Emit event for update
|
|
253
|
+
this.emit('chainChanged', {
|
|
254
|
+
chainId: this.chainId,
|
|
255
|
+
});
|
|
256
|
+
// Dispatch 'connect' event
|
|
257
|
+
this.dispatchConnect();
|
|
238
258
|
return this;
|
|
239
259
|
});
|
|
240
260
|
}
|
|
@@ -249,7 +269,8 @@ class Provider {
|
|
|
249
269
|
if (this.autoApprove) {
|
|
250
270
|
return true;
|
|
251
271
|
}
|
|
252
|
-
|
|
272
|
+
const signingHandlers = this.events['portal_signingRequested'];
|
|
273
|
+
if (!signingHandlers || signingHandlers.length === 0) {
|
|
253
274
|
throw new Error(`[PortalProvider] Auto-approve is disabled. Cannot perform signing requests without an event handler for the 'portal_signingRequested' event.`);
|
|
254
275
|
}
|
|
255
276
|
return new Promise((resolve) => {
|
|
@@ -258,7 +279,6 @@ class Provider {
|
|
|
258
279
|
this.removeEventListener('portal_signingRejected');
|
|
259
280
|
// If the signing has been approved, resolve to true
|
|
260
281
|
this.once('portal_signingApproved', ({ method: approvedMethod, params: approvedParams }) => {
|
|
261
|
-
console.log(`[PortalProvider] Signing Approved`, method, params);
|
|
262
282
|
// Remove already used listeners
|
|
263
283
|
this.removeEventListener('portal_signingApproved');
|
|
264
284
|
this.removeEventListener('portal_signingRejected');
|
|
@@ -270,7 +290,6 @@ class Provider {
|
|
|
270
290
|
});
|
|
271
291
|
// If the signing request has been rejected, resolve to false
|
|
272
292
|
this.once('portal_signingRejected', ({ method: rejectedMethod, params: rejectedParams }) => {
|
|
273
|
-
console.log(`[PortalProvider] Signing Approved`, method, params);
|
|
274
293
|
// Remove already used listeners
|
|
275
294
|
this.removeEventListener('portal_signingApproved');
|
|
276
295
|
this.removeEventListener('portal_signingRejected');
|
|
@@ -290,35 +309,12 @@ class Provider {
|
|
|
290
309
|
}
|
|
291
310
|
dispatchConnect() {
|
|
292
311
|
return __awaiter(this, void 0, void 0, function* () {
|
|
293
|
-
|
|
312
|
+
this.connected = true;
|
|
294
313
|
this.emit('connect', {
|
|
295
314
|
chainId: `0x${this.chainId.toString(16)}`,
|
|
296
315
|
});
|
|
297
316
|
});
|
|
298
317
|
}
|
|
299
|
-
/**
|
|
300
|
-
* Determines the RPC URL to be used for the current chain
|
|
301
|
-
*
|
|
302
|
-
* @returns string
|
|
303
|
-
*/
|
|
304
|
-
getRpcUrl() {
|
|
305
|
-
if (typeof this.gatewayConfig === 'string') {
|
|
306
|
-
// If the gatewayConfig is just a static URL, return that
|
|
307
|
-
return this.gatewayConfig;
|
|
308
|
-
}
|
|
309
|
-
else if (typeof this.gatewayConfig === 'object' &&
|
|
310
|
-
!this.gatewayConfig.hasOwnProperty(this.chainId)) {
|
|
311
|
-
// If there's no explicit mapping for the current chainId, error out
|
|
312
|
-
throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`);
|
|
313
|
-
}
|
|
314
|
-
// Get the entry for the current chainId from the gatewayConfig
|
|
315
|
-
const config = this.gatewayConfig[this.chainId];
|
|
316
|
-
if (typeof config === 'string') {
|
|
317
|
-
return config;
|
|
318
|
-
}
|
|
319
|
-
// If we got this far, there's no way to support the chain with the current config
|
|
320
|
-
throw new Error(`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}`);
|
|
321
|
-
}
|
|
322
318
|
/**
|
|
323
319
|
* Sends the provided request payload along to the RPC HttpRequester
|
|
324
320
|
*
|
|
@@ -8,9 +8,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
class Signer {
|
|
11
|
+
getAddress() {
|
|
12
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
13
|
+
throw new Error(`[Portal] getAddress() method must be implemented as a subclass of Signer`);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
11
16
|
sign(_, __) {
|
|
12
17
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13
|
-
throw new Error('[Portal] sign() method must be implemented in a
|
|
18
|
+
throw new Error('[Portal] sign() method must be implemented in a subclass of Signer');
|
|
14
19
|
});
|
|
15
20
|
}
|
|
16
21
|
}
|
package/lib/esm/signers/index.js
CHANGED
package/lib/esm/signers/mpc.js
CHANGED
|
@@ -11,7 +11,6 @@ import { NativeModules } from 'react-native';
|
|
|
11
11
|
import { MpcSigningError, } from '@portal-hq/utils';
|
|
12
12
|
class MpcSigner {
|
|
13
13
|
constructor(opts) {
|
|
14
|
-
this._address = '';
|
|
15
14
|
this.buildParams = (method, txParams) => {
|
|
16
15
|
let params = txParams;
|
|
17
16
|
switch (method) {
|
|
@@ -35,15 +34,17 @@ class MpcSigner {
|
|
|
35
34
|
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.`);
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
|
-
|
|
39
|
-
return
|
|
40
|
-
if (this.
|
|
41
|
-
return this.
|
|
37
|
+
getAddress() {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
if (this.address) {
|
|
40
|
+
return this.address;
|
|
42
41
|
}
|
|
43
42
|
const address = yield this.keychain.getAddress();
|
|
44
|
-
|
|
43
|
+
if (typeof address !== 'undefined' && address.length) {
|
|
44
|
+
this.address = address;
|
|
45
|
+
}
|
|
45
46
|
return address;
|
|
46
|
-
})
|
|
47
|
+
});
|
|
47
48
|
}
|
|
48
49
|
sign(message, provider) {
|
|
49
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -58,11 +59,8 @@ class MpcSigner {
|
|
|
58
59
|
default:
|
|
59
60
|
break;
|
|
60
61
|
}
|
|
61
|
-
console.log(`[Portal:MpcSigner] Requesting signature from PortalMobileMpc for:`, JSON.stringify(message, null, 2));
|
|
62
62
|
const dkg = yield this.keychain.getDkgResult();
|
|
63
|
-
console.log(`[PortalMpcSigner] RPC URL: ${provider.rpcUrl}`);
|
|
64
63
|
const result = yield this.mpc.sign(apiKey, this.mpcUrl, dkg, message.method, JSON.stringify(this.buildParams(method, params)), provider.rpcUrl, provider.chainId.toString());
|
|
65
|
-
console.log(`[PortalMpcSigner] Result: `, result);
|
|
66
64
|
const { data, error } = JSON.parse(String(result));
|
|
67
65
|
if (error && error.length) {
|
|
68
66
|
throw new MpcSigningError(error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portal-hq/provider",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.18",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/esm/index",
|
|
@@ -14,12 +14,18 @@
|
|
|
14
14
|
"scripts": {
|
|
15
15
|
"prepare": "yarn prepare:cjs && yarn prepare:esm",
|
|
16
16
|
"prepare:cjs": "tsc --outDir lib/commonjs --module commonjs",
|
|
17
|
-
"prepare:esm": "tsc --outDir lib/esm --module es2015 --target es2015"
|
|
17
|
+
"prepare:esm": "tsc --outDir lib/esm --module es2015 --target es2015",
|
|
18
|
+
"test": "jest"
|
|
18
19
|
},
|
|
19
20
|
"dependencies": {
|
|
20
|
-
"@portal-hq/utils": "^0.2.
|
|
21
|
+
"@portal-hq/utils": "^0.2.17"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
24
|
+
"@babel/preset-typescript": "^7.18.6",
|
|
25
|
+
"@types/jest": "^29.2.0",
|
|
26
|
+
"jest": "^29.2.1",
|
|
27
|
+
"jest-environment-jsdom": "^29.2.2",
|
|
28
|
+
"ts-jest": "^29.0.3",
|
|
23
29
|
"typescript": "^4.8.4"
|
|
24
30
|
}
|
|
25
31
|
}
|
package/src/providers/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
HttpRequester,
|
|
2
3
|
InvalidApiKeyError,
|
|
3
4
|
InvalidChainIdError,
|
|
4
5
|
InvalidGatewayConfigError,
|
|
@@ -7,8 +8,7 @@ import {
|
|
|
7
8
|
RpcErrorCodes,
|
|
8
9
|
} from '@portal-hq/utils'
|
|
9
10
|
|
|
10
|
-
import {
|
|
11
|
-
import { HttpSigner, MpcSigner, Signer } from '../signers'
|
|
11
|
+
import { MpcSigner, Signer } from '../signers'
|
|
12
12
|
import {
|
|
13
13
|
type EventHandler,
|
|
14
14
|
type GatewayLike,
|
|
@@ -38,21 +38,21 @@ const signerMethods = [
|
|
|
38
38
|
class Provider {
|
|
39
39
|
public readonly mpcUrl: string
|
|
40
40
|
public readonly portal: HttpRequester
|
|
41
|
-
public apiKey: string
|
|
42
41
|
|
|
42
|
+
public address?: string
|
|
43
|
+
public apiKey: string
|
|
44
|
+
public apiUrl: string
|
|
45
|
+
public autoApprove?: boolean
|
|
43
46
|
public chainId: number
|
|
44
|
-
public
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
private rpc: HttpRequester
|
|
54
|
-
|
|
55
|
-
public signer?: Signer
|
|
47
|
+
public connected: boolean
|
|
48
|
+
public events: Record<string, RegisteredEventHandler[]>
|
|
49
|
+
public gatewayConfig: GatewayLike
|
|
50
|
+
public isMPC: boolean
|
|
51
|
+
public keychain: KeychainAdapter
|
|
52
|
+
public log: Console
|
|
53
|
+
public rpc: HttpRequester
|
|
54
|
+
public rpcUrl: string
|
|
55
|
+
public signer: Signer
|
|
56
56
|
|
|
57
57
|
constructor({
|
|
58
58
|
// Required options
|
|
@@ -63,7 +63,6 @@ class Provider {
|
|
|
63
63
|
// Optional options
|
|
64
64
|
apiUrl = 'api.portalhq.io',
|
|
65
65
|
autoApprove = false,
|
|
66
|
-
enableMpc = true,
|
|
67
66
|
mpcUrl = 'mpc.portalhq.io',
|
|
68
67
|
gatewayConfig = {},
|
|
69
68
|
}: ProviderOptions) {
|
|
@@ -83,53 +82,38 @@ class Provider {
|
|
|
83
82
|
this.apiUrl = apiUrl
|
|
84
83
|
this.autoApprove = autoApprove
|
|
85
84
|
this.chainId = chainId
|
|
85
|
+
this.connected = false
|
|
86
86
|
this.events = {}
|
|
87
|
-
this.
|
|
87
|
+
this.gatewayConfig = gatewayConfig
|
|
88
|
+
this.isMPC = true
|
|
88
89
|
this.keychain = keychain
|
|
89
|
-
this.log = console
|
|
90
90
|
this.mpcUrl = mpcUrl
|
|
91
|
+
this.rpcUrl = this.getRpcUrl()
|
|
92
|
+
|
|
93
|
+
// Add a logger
|
|
94
|
+
this.log = console
|
|
95
|
+
|
|
96
|
+
// Initialize Portal API HttpRequester
|
|
91
97
|
this.portal = new HttpRequester({
|
|
92
98
|
baseUrl: this.apiUrl,
|
|
93
99
|
})
|
|
94
100
|
|
|
95
|
-
//
|
|
96
|
-
this.gatewayConfig = gatewayConfig
|
|
97
|
-
|
|
101
|
+
// Initialize Gateway HttpRequester
|
|
98
102
|
this.rpc = new HttpRequester({
|
|
99
|
-
baseUrl: this.
|
|
103
|
+
baseUrl: this.rpcUrl,
|
|
100
104
|
})
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
})
|
|
108
|
-
} else {
|
|
109
|
-
// If MPC is disabled, initialize an HttpSigner, talking to whatever httpHost was provided
|
|
110
|
-
this.signer = new HttpSigner({
|
|
111
|
-
keychain: this.keychain,
|
|
112
|
-
portal: this.portal,
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
this.dispatchConnect()
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
get address(): string {
|
|
120
|
-
return this._address
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
set address(value: string) {
|
|
124
|
-
this._address = value
|
|
125
|
-
|
|
126
|
-
if (this.signer && this.isMPC) {
|
|
127
|
-
;(this.signer as MpcSigner)._address = value
|
|
128
|
-
}
|
|
129
|
-
}
|
|
106
|
+
// Initialize an MpcSigner
|
|
107
|
+
this.signer = new MpcSigner({
|
|
108
|
+
mpcUrl: this.mpcUrl,
|
|
109
|
+
keychain: this.keychain,
|
|
110
|
+
})
|
|
130
111
|
|
|
131
|
-
|
|
132
|
-
|
|
112
|
+
this.signer.getAddress().then((address) => {
|
|
113
|
+
if (typeof address !== 'undefined' && address.length) {
|
|
114
|
+
this.address = address
|
|
115
|
+
}
|
|
116
|
+
})
|
|
133
117
|
}
|
|
134
118
|
|
|
135
119
|
/**
|
|
@@ -155,6 +139,38 @@ class Provider {
|
|
|
155
139
|
return this
|
|
156
140
|
}
|
|
157
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Determines the RPC URL to be used for the current chain
|
|
144
|
+
*
|
|
145
|
+
* @returns string
|
|
146
|
+
*/
|
|
147
|
+
public getRpcUrl(): string {
|
|
148
|
+
if (typeof this.gatewayConfig === 'string') {
|
|
149
|
+
// If the gatewayConfig is just a static URL, return that
|
|
150
|
+
return this.gatewayConfig
|
|
151
|
+
} else if (
|
|
152
|
+
typeof this.gatewayConfig === 'object' &&
|
|
153
|
+
!this.gatewayConfig.hasOwnProperty(this.chainId)
|
|
154
|
+
) {
|
|
155
|
+
// If there's no explicit mapping for the current chainId, error out
|
|
156
|
+
throw new Error(
|
|
157
|
+
`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`,
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Get the entry for the current chainId from the gatewayConfig
|
|
162
|
+
const config = this.gatewayConfig[this.chainId]
|
|
163
|
+
|
|
164
|
+
if (typeof config === 'string') {
|
|
165
|
+
return config
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// If we got this far, there's no way to support the chain with the current config
|
|
169
|
+
throw new Error(
|
|
170
|
+
`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}`,
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
158
174
|
/**
|
|
159
175
|
* Registers an event handler for the provided event
|
|
160
176
|
*
|
|
@@ -208,9 +224,6 @@ class Provider {
|
|
|
208
224
|
listenerToRemove?: EventHandler,
|
|
209
225
|
): void {
|
|
210
226
|
if (!this.events[event]) {
|
|
211
|
-
this.log.info(
|
|
212
|
-
`[PortalProvider] Attempted to remove a listener from unregistered event '${event}'. Ignoring.`,
|
|
213
|
-
)
|
|
214
227
|
return
|
|
215
228
|
}
|
|
216
229
|
|
|
@@ -265,8 +278,6 @@ class Provider {
|
|
|
265
278
|
})
|
|
266
279
|
|
|
267
280
|
if (transactionHash) {
|
|
268
|
-
console.log(`Received transaction hash: `, transactionHash)
|
|
269
|
-
|
|
270
281
|
this.emit('portal_signatureReceived', {
|
|
271
282
|
method,
|
|
272
283
|
params,
|
|
@@ -289,6 +300,14 @@ class Provider {
|
|
|
289
300
|
return result
|
|
290
301
|
}
|
|
291
302
|
|
|
303
|
+
public setAddress(address: string): void {
|
|
304
|
+
this.address = address
|
|
305
|
+
|
|
306
|
+
if (!this.connected) {
|
|
307
|
+
this.dispatchConnect()
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
292
311
|
/**
|
|
293
312
|
* Updates the chainId of this instance and builds a new RPC HttpRequester for
|
|
294
313
|
* the gateway used for the new chain
|
|
@@ -296,14 +315,25 @@ class Provider {
|
|
|
296
315
|
* @param chainId A hex string of the chainId to use for this connection
|
|
297
316
|
* @returns BaseProvider
|
|
298
317
|
*/
|
|
299
|
-
public async
|
|
318
|
+
public async setChainId(chainId: string): Promise<Provider> {
|
|
319
|
+
// Disconnect from the current chain
|
|
320
|
+
this.connected = false
|
|
321
|
+
|
|
322
|
+
// Update the chainId
|
|
300
323
|
this.chainId = Number(`${chainId}`)
|
|
301
324
|
|
|
325
|
+
// Re-initialize the Gateway HttpRequester
|
|
302
326
|
this.rpc = new HttpRequester({
|
|
303
327
|
baseUrl: this.getRpcUrl(),
|
|
304
328
|
})
|
|
305
329
|
|
|
306
|
-
|
|
330
|
+
// Emit event for update
|
|
331
|
+
this.emit('chainChanged', {
|
|
332
|
+
chainId: this.chainId,
|
|
333
|
+
} as SwitchEthereumChainParameter)
|
|
334
|
+
|
|
335
|
+
// Dispatch 'connect' event
|
|
336
|
+
this.dispatchConnect()
|
|
307
337
|
|
|
308
338
|
return this
|
|
309
339
|
}
|
|
@@ -322,7 +352,9 @@ class Provider {
|
|
|
322
352
|
return true
|
|
323
353
|
}
|
|
324
354
|
|
|
325
|
-
|
|
355
|
+
const signingHandlers = this.events['portal_signingRequested']
|
|
356
|
+
|
|
357
|
+
if (!signingHandlers || signingHandlers.length === 0) {
|
|
326
358
|
throw new Error(
|
|
327
359
|
`[PortalProvider] Auto-approve is disabled. Cannot perform signing requests without an event handler for the 'portal_signingRequested' event.`,
|
|
328
360
|
)
|
|
@@ -337,7 +369,6 @@ class Provider {
|
|
|
337
369
|
this.once(
|
|
338
370
|
'portal_signingApproved',
|
|
339
371
|
({ method: approvedMethod, params: approvedParams }) => {
|
|
340
|
-
console.log(`[PortalProvider] Signing Approved`, method, params)
|
|
341
372
|
// Remove already used listeners
|
|
342
373
|
this.removeEventListener('portal_signingApproved')
|
|
343
374
|
this.removeEventListener('portal_signingRejected')
|
|
@@ -356,7 +387,6 @@ class Provider {
|
|
|
356
387
|
this.once(
|
|
357
388
|
'portal_signingRejected',
|
|
358
389
|
({ method: rejectedMethod, params: rejectedParams }) => {
|
|
359
|
-
console.log(`[PortalProvider] Signing Approved`, method, params)
|
|
360
390
|
// Remove already used listeners
|
|
361
391
|
this.removeEventListener('portal_signingApproved')
|
|
362
392
|
this.removeEventListener('portal_signingRejected')
|
|
@@ -380,46 +410,12 @@ class Provider {
|
|
|
380
410
|
}
|
|
381
411
|
|
|
382
412
|
private async dispatchConnect(): Promise<void> {
|
|
383
|
-
|
|
384
|
-
`[PortalProvider] Connected on chainId: 0x${this.chainId.toString(16)}`,
|
|
385
|
-
)
|
|
413
|
+
this.connected = true
|
|
386
414
|
this.emit('connect', {
|
|
387
415
|
chainId: `0x${this.chainId.toString(16)}`,
|
|
388
416
|
})
|
|
389
417
|
}
|
|
390
418
|
|
|
391
|
-
/**
|
|
392
|
-
* Determines the RPC URL to be used for the current chain
|
|
393
|
-
*
|
|
394
|
-
* @returns string
|
|
395
|
-
*/
|
|
396
|
-
private getRpcUrl(): string {
|
|
397
|
-
if (typeof this.gatewayConfig === 'string') {
|
|
398
|
-
// If the gatewayConfig is just a static URL, return that
|
|
399
|
-
return this.gatewayConfig
|
|
400
|
-
} else if (
|
|
401
|
-
typeof this.gatewayConfig === 'object' &&
|
|
402
|
-
!this.gatewayConfig.hasOwnProperty(this.chainId)
|
|
403
|
-
) {
|
|
404
|
-
// If there's no explicit mapping for the current chainId, error out
|
|
405
|
-
throw new Error(
|
|
406
|
-
`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`,
|
|
407
|
-
)
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Get the entry for the current chainId from the gatewayConfig
|
|
411
|
-
const config = this.gatewayConfig[this.chainId]
|
|
412
|
-
|
|
413
|
-
if (typeof config === 'string') {
|
|
414
|
-
return config
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// If we got this far, there's no way to support the chain with the current config
|
|
418
|
-
throw new Error(
|
|
419
|
-
`[PortalProvider] Could not find a valid gatewayConfig entry for chainId: ${this.chainId}`,
|
|
420
|
-
)
|
|
421
|
-
}
|
|
422
|
-
|
|
423
419
|
/**
|
|
424
420
|
* Sends the provided request payload along to the RPC HttpRequester
|
|
425
421
|
*
|
package/src/signers/abstract.ts
CHANGED
|
@@ -2,9 +2,14 @@ import { SigningRequestArguments } from '@portal-hq/utils'
|
|
|
2
2
|
import { type SignResult } from '../../types'
|
|
3
3
|
|
|
4
4
|
abstract class Signer {
|
|
5
|
+
public async getAddress(): Promise<string> {
|
|
6
|
+
throw new Error(
|
|
7
|
+
`[Portal] getAddress() method must be implemented as a subclass of Signer`,
|
|
8
|
+
)
|
|
9
|
+
}
|
|
5
10
|
public async sign(_: SigningRequestArguments, __?: any): Promise<SignResult> {
|
|
6
11
|
throw new Error(
|
|
7
|
-
'[Portal] sign() method must be implemented in a
|
|
12
|
+
'[Portal] sign() method must be implemented in a subclass of Signer',
|
|
8
13
|
)
|
|
9
14
|
}
|
|
10
15
|
}
|
package/src/signers/index.ts
CHANGED
package/src/signers/mpc.ts
CHANGED
|
@@ -15,10 +15,11 @@ import {
|
|
|
15
15
|
} from '../../types'
|
|
16
16
|
|
|
17
17
|
class MpcSigner implements Signer {
|
|
18
|
-
public _address: string = ''
|
|
19
|
-
private keychain: KeychainAdapter
|
|
20
18
|
private mpc: PortalMobileMpc
|
|
21
|
-
|
|
19
|
+
|
|
20
|
+
public address?: string
|
|
21
|
+
public keychain: KeychainAdapter
|
|
22
|
+
public mpcUrl: string
|
|
22
23
|
|
|
23
24
|
constructor(opts: MpcSignerOptions) {
|
|
24
25
|
this.keychain = opts.keychain
|
|
@@ -32,18 +33,18 @@ class MpcSigner implements Signer {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
public
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
36
|
+
public async getAddress(): Promise<string> {
|
|
37
|
+
if (this.address) {
|
|
38
|
+
return this.address
|
|
39
|
+
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const address = await this.keychain.getAddress()
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
if (typeof address !== 'undefined' && address.length) {
|
|
44
|
+
this.address = address
|
|
45
|
+
}
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
})()
|
|
47
|
+
return address
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
public async sign(
|
|
@@ -64,15 +65,8 @@ class MpcSigner implements Signer {
|
|
|
64
65
|
break
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
console.log(
|
|
68
|
-
`[Portal:MpcSigner] Requesting signature from PortalMobileMpc for:`,
|
|
69
|
-
JSON.stringify(message, null, 2),
|
|
70
|
-
)
|
|
71
|
-
|
|
72
68
|
const dkg = await this.keychain.getDkgResult()
|
|
73
69
|
|
|
74
|
-
console.log(`[PortalMpcSigner] RPC URL: ${provider.rpcUrl}`)
|
|
75
|
-
|
|
76
70
|
const result = await this.mpc.sign(
|
|
77
71
|
apiKey,
|
|
78
72
|
this.mpcUrl,
|
|
@@ -83,8 +77,6 @@ class MpcSigner implements Signer {
|
|
|
83
77
|
provider.chainId.toString(),
|
|
84
78
|
)
|
|
85
79
|
|
|
86
|
-
console.log(`[PortalMpcSigner] Result: `, result)
|
|
87
|
-
|
|
88
80
|
const { data, error } = JSON.parse(String(result)) as SigningResponse
|
|
89
81
|
|
|
90
82
|
if (error && error.length) {
|
package/types.d.ts
CHANGED
|
@@ -14,15 +14,6 @@ export interface GatewayConfig {
|
|
|
14
14
|
[key: number]: string
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export interface HttpRequesterOptions {
|
|
18
|
-
baseUrl: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface HttpSignerOptions extends SignerOptions {
|
|
22
|
-
keychain: KeychainAdapter
|
|
23
|
-
portal: HttpRequester
|
|
24
|
-
}
|
|
25
|
-
|
|
26
17
|
export interface MpcSignerOptions extends SignerOptions {
|
|
27
18
|
keychain: KeychainAdapter
|
|
28
19
|
mpcUrl: string
|
|
@@ -88,5 +79,5 @@ export interface SigningResponse {
|
|
|
88
79
|
}
|
|
89
80
|
|
|
90
81
|
export interface SwitchEthereumChainParameter {
|
|
91
|
-
chainId:
|
|
82
|
+
chainId: number
|
|
92
83
|
}
|
package/src/requesters/http.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
HttpRequest,
|
|
3
|
-
type HttpRequestOptions,
|
|
4
|
-
type HttpOptions,
|
|
5
|
-
type HttpRequesterOptions,
|
|
6
|
-
} from '@portal-hq/utils'
|
|
7
|
-
|
|
8
|
-
class HttpRequester {
|
|
9
|
-
private baseUrl: string
|
|
10
|
-
|
|
11
|
-
constructor({ baseUrl }: HttpRequesterOptions) {
|
|
12
|
-
this.baseUrl = baseUrl.startsWith('https://')
|
|
13
|
-
? baseUrl
|
|
14
|
-
: `https://${baseUrl}`
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
public async get<T>(path: string, options?: HttpOptions): Promise<T> {
|
|
18
|
-
const requestOptions = {
|
|
19
|
-
method: 'GET',
|
|
20
|
-
url: `${this.baseUrl}${path}`,
|
|
21
|
-
} as HttpRequestOptions
|
|
22
|
-
|
|
23
|
-
if (options && options.headers) {
|
|
24
|
-
requestOptions.headers = this.buildHeaders(options.headers)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const request = new HttpRequest(requestOptions)
|
|
28
|
-
const response = (await request.send()) as T
|
|
29
|
-
|
|
30
|
-
return response
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public async post<T>(path: string, options?: HttpOptions): Promise<T> {
|
|
34
|
-
const requestOptions = {
|
|
35
|
-
method: 'POST',
|
|
36
|
-
url: `${this.baseUrl}${path}`,
|
|
37
|
-
} as HttpRequestOptions
|
|
38
|
-
|
|
39
|
-
requestOptions.headers = this.buildHeaders(
|
|
40
|
-
options && options.headers ? options.headers : {},
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
if (options && options.body) {
|
|
44
|
-
requestOptions.body = options.body
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const request = new HttpRequest(requestOptions)
|
|
48
|
-
const response = (await request.send()) as T
|
|
49
|
-
|
|
50
|
-
return response
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private buildHeaders(headers: Record<string, any>): Record<string, any> {
|
|
54
|
-
return {
|
|
55
|
-
'Content-Type': 'application/json',
|
|
56
|
-
...headers,
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export default HttpRequester
|
package/src/requesters/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as HttpRequester } from './http'
|
package/src/signers/http.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
KeychainAdapter,
|
|
3
|
-
MissingOptionError,
|
|
4
|
-
SigningRequestArguments,
|
|
5
|
-
} from '@portal-hq/utils'
|
|
6
|
-
|
|
7
|
-
import { type HttpSignerOptions, type SignResult } from '../../types'
|
|
8
|
-
|
|
9
|
-
import Signer from './abstract'
|
|
10
|
-
import { Provider } from '../index'
|
|
11
|
-
import HttpRequester from '../requesters/http'
|
|
12
|
-
|
|
13
|
-
class HttpSigner implements Signer {
|
|
14
|
-
private portal: HttpRequester
|
|
15
|
-
private keychain: KeychainAdapter
|
|
16
|
-
|
|
17
|
-
constructor(opts: HttpSignerOptions) {
|
|
18
|
-
if (!opts.portal) {
|
|
19
|
-
throw new MissingOptionError({
|
|
20
|
-
className: 'HttpSigner',
|
|
21
|
-
option: 'portal',
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
this.keychain = opts.keychain
|
|
26
|
-
this.portal = opts.portal
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public async sign(
|
|
30
|
-
message: SigningRequestArguments,
|
|
31
|
-
provider: Provider,
|
|
32
|
-
): Promise<any> {
|
|
33
|
-
const address = await this.keychain.getAddress()
|
|
34
|
-
const { chainId, method, params } = message
|
|
35
|
-
|
|
36
|
-
switch (method) {
|
|
37
|
-
case 'eth_requestAccounts':
|
|
38
|
-
return [address]
|
|
39
|
-
case 'eth_accounts':
|
|
40
|
-
return [address]
|
|
41
|
-
default:
|
|
42
|
-
break
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
console.log(
|
|
46
|
-
`[Portal:HttpSigner] Requesting signature from exchange for:`,
|
|
47
|
-
JSON.stringify(
|
|
48
|
-
{
|
|
49
|
-
chainId,
|
|
50
|
-
method,
|
|
51
|
-
params: JSON.stringify([params]),
|
|
52
|
-
},
|
|
53
|
-
null,
|
|
54
|
-
2,
|
|
55
|
-
),
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
const signatureResponse = await this.portal.post<SignResult>(
|
|
59
|
-
'/api/v1/clients/transactions/sign',
|
|
60
|
-
{
|
|
61
|
-
body: {
|
|
62
|
-
chainId,
|
|
63
|
-
method,
|
|
64
|
-
params: JSON.stringify([params]),
|
|
65
|
-
},
|
|
66
|
-
headers: {
|
|
67
|
-
Authorization: `Bearer ${provider.apiKey}`,
|
|
68
|
-
'Content-Type': 'application/json',
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
return signatureResponse
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export default HttpSigner
|