@portal-hq/connect 1.0.5 → 1.1.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/index.js +104 -15
- package/lib/esm/index.js +103 -15
- package/package.json +2 -3
- package/src/index.ts +141 -27
- package/types.d.ts +14 -7
package/lib/commonjs/index.js
CHANGED
|
@@ -9,18 +9,54 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ConnectionStates = void 0;
|
|
13
|
+
const provider_1 = require("@portal-hq/provider");
|
|
12
14
|
class PortalConnect {
|
|
13
|
-
constructor({
|
|
14
|
-
|
|
15
|
+
constructor({ apiKey, chainId, keychain, gatewayConfig,
|
|
16
|
+
// Optional
|
|
17
|
+
isSimulator = false, autoApprove = false, version = 'v4', apiHost = 'api.portalhq.io', mpcHost = 'mpc.portalhq.io', webSocketServer = 'connect.portalhq.io', }) {
|
|
18
|
+
this.connectionState = ConnectionStates.DISCONNECTED;
|
|
19
|
+
this.apiKey = apiKey;
|
|
15
20
|
this.events = {};
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
21
|
+
this.websocketServer = webSocketServer;
|
|
22
|
+
this.provider = new provider_1.Provider({
|
|
23
|
+
apiKey,
|
|
24
|
+
chainId,
|
|
25
|
+
gatewayConfig,
|
|
26
|
+
keychain,
|
|
27
|
+
isSimulator,
|
|
28
|
+
autoApprove,
|
|
29
|
+
version,
|
|
30
|
+
apiHost,
|
|
31
|
+
mpcHost,
|
|
32
|
+
});
|
|
33
|
+
// Inbound from the Provider
|
|
34
|
+
this.on('portalConnect_signingRequested', (data) => {
|
|
35
|
+
this.emit('portal_signingRequested', data);
|
|
36
|
+
});
|
|
37
|
+
// Inbound from SDK consumers
|
|
38
|
+
this.on('portal_signingApproved', (data) => {
|
|
39
|
+
this.provider.emit('portal_signingApproved', data);
|
|
40
|
+
});
|
|
41
|
+
this.on('portal_signingRejected', (data) => {
|
|
42
|
+
this.provider.emit('portal_signingRejected', data);
|
|
43
|
+
});
|
|
18
44
|
// Do the OG binding trick to preserve the `this` context
|
|
19
45
|
this.handleSessionApproved = this.handleSessionApproved.bind(this);
|
|
20
46
|
this.handleSessionRejected = this.handleSessionRejected.bind(this);
|
|
21
47
|
this.handleSessionRequest = this.handleSessionRequest.bind(this);
|
|
22
48
|
this.handleSigningRejected = this.handleSigningRejected.bind(this);
|
|
23
49
|
}
|
|
50
|
+
get address() {
|
|
51
|
+
return this.provider.address;
|
|
52
|
+
}
|
|
53
|
+
get chainId() {
|
|
54
|
+
return this.provider.chainId;
|
|
55
|
+
}
|
|
56
|
+
get connected() {
|
|
57
|
+
return (this.connectionState === ConnectionStates.CONNECTED ||
|
|
58
|
+
this.connectionState === ConnectionStates.CONNECTING);
|
|
59
|
+
}
|
|
24
60
|
/**
|
|
25
61
|
* Establishes a websocket connection with the Connect Proxy and dispatches the binding
|
|
26
62
|
* of websocket events for the newly established socket
|
|
@@ -38,15 +74,29 @@ class PortalConnect {
|
|
|
38
74
|
// @ts-ignore
|
|
39
75
|
{
|
|
40
76
|
headers: {
|
|
41
|
-
Authorization: `Bearer ${this.
|
|
77
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
42
78
|
},
|
|
43
79
|
});
|
|
80
|
+
this.uri = uri;
|
|
44
81
|
this.bindToSocketEvents(this.socket, uri);
|
|
45
82
|
});
|
|
46
83
|
}
|
|
47
84
|
deinit() {
|
|
48
85
|
this.events = {};
|
|
49
86
|
}
|
|
87
|
+
disconnect() {
|
|
88
|
+
this.sendFinalMessageAndClose();
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Triggers the chain on the dapp to change to match the chain of the wallet
|
|
92
|
+
*
|
|
93
|
+
* @param chainId The number of the chainId to switch to
|
|
94
|
+
*/
|
|
95
|
+
setChainId(chainId) {
|
|
96
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
97
|
+
this.provider.setChainId(chainId, this);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
50
100
|
/**
|
|
51
101
|
* Invokes all registered event handlers with the data provided
|
|
52
102
|
* - If any `once` handlers exist, they are removed after all handlers are invoked
|
|
@@ -135,7 +185,8 @@ class PortalConnect {
|
|
|
135
185
|
* - Fires a subsequent call over the websocket to notify the proxy of the uri to connect to
|
|
136
186
|
*/
|
|
137
187
|
socket.onopen = () => __awaiter(this, void 0, void 0, function* () {
|
|
138
|
-
const
|
|
188
|
+
const address = yield this.address;
|
|
189
|
+
const { chainId } = this.provider;
|
|
139
190
|
// Tell the proxy server where to connect to downstream
|
|
140
191
|
socket.send(JSON.stringify({
|
|
141
192
|
event: 'connect',
|
|
@@ -146,6 +197,18 @@ class PortalConnect {
|
|
|
146
197
|
},
|
|
147
198
|
}));
|
|
148
199
|
});
|
|
200
|
+
this.on('portalConnect_chainChanged', (data) => {
|
|
201
|
+
var _a;
|
|
202
|
+
// Tell the proxy server where to connect to downstream
|
|
203
|
+
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({
|
|
204
|
+
event: 'portal_chainChanged',
|
|
205
|
+
data: {
|
|
206
|
+
topic: this.topic,
|
|
207
|
+
uri: this.uri,
|
|
208
|
+
chainId: data.chainId,
|
|
209
|
+
},
|
|
210
|
+
}));
|
|
211
|
+
});
|
|
149
212
|
socket.onerror = (event) => __awaiter(this, void 0, void 0, function* () {
|
|
150
213
|
let errorMessage = 'An unexpected error occurred.';
|
|
151
214
|
if (event instanceof ErrorEvent) {
|
|
@@ -168,12 +231,13 @@ class PortalConnect {
|
|
|
168
231
|
this.emit('disconnect', message.data);
|
|
169
232
|
break;
|
|
170
233
|
case 'connected':
|
|
171
|
-
this.
|
|
234
|
+
this.connectionState = ConnectionStates.CONNECTED;
|
|
235
|
+
this.topic = message.data.topic;
|
|
172
236
|
this.emit('connect', message.data);
|
|
173
237
|
break;
|
|
174
238
|
case 'disconnect':
|
|
175
239
|
socket.close();
|
|
176
|
-
this.
|
|
240
|
+
this.connectionState = ConnectionStates.DISCONNECTED;
|
|
177
241
|
this.emit('disconnect', message.data);
|
|
178
242
|
break;
|
|
179
243
|
case 'session_request':
|
|
@@ -203,28 +267,28 @@ class PortalConnect {
|
|
|
203
267
|
handleProviderRequest(method, params, request) {
|
|
204
268
|
return __awaiter(this, void 0, void 0, function* () {
|
|
205
269
|
// Bind to potential signing rejection events
|
|
206
|
-
this.
|
|
270
|
+
this.provider.on('portal_signingRejected', this.handleSigningRejected);
|
|
207
271
|
// Bind to potential signature received events
|
|
208
|
-
this.
|
|
272
|
+
this.provider.on('portal_signatureReceived', ({ method: signedMethod, params: signedParams, signature }) => {
|
|
209
273
|
if (signedMethod === method &&
|
|
210
274
|
JSON.stringify(signedParams) === JSON.stringify(params)) {
|
|
211
275
|
this.handleSignatureReceived(request, signature);
|
|
212
276
|
}
|
|
213
277
|
});
|
|
214
278
|
// Pass the request along to the provider
|
|
215
|
-
yield this.
|
|
279
|
+
yield this.provider.request({ method, params, connect: this });
|
|
216
280
|
});
|
|
217
281
|
}
|
|
218
282
|
handleSessionApproved(data, request) {
|
|
219
283
|
var _a;
|
|
220
284
|
return __awaiter(this, void 0, void 0, function* () {
|
|
221
|
-
const address = yield this.
|
|
285
|
+
const address = yield this.address;
|
|
222
286
|
// Notify the proxy server that the session request was approved
|
|
223
287
|
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({
|
|
224
288
|
event: 'portal_dappSessionApproved',
|
|
225
289
|
data: {
|
|
226
290
|
address,
|
|
227
|
-
chainId: this.
|
|
291
|
+
chainId: this.chainId,
|
|
228
292
|
topic: request.topic,
|
|
229
293
|
id: request.id,
|
|
230
294
|
params: data,
|
|
@@ -235,13 +299,13 @@ class PortalConnect {
|
|
|
235
299
|
handleSessionRejected(data, request) {
|
|
236
300
|
var _a;
|
|
237
301
|
return __awaiter(this, void 0, void 0, function* () {
|
|
238
|
-
const address = yield this.
|
|
302
|
+
const address = yield this.address;
|
|
239
303
|
// Notify the proxy server that the session request was rejected
|
|
240
304
|
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({
|
|
241
305
|
event: 'portal_dappSessionRejected',
|
|
242
306
|
data: {
|
|
243
307
|
address,
|
|
244
|
-
chainId: this.
|
|
308
|
+
chainId: this.chainId,
|
|
245
309
|
topic: request.topic,
|
|
246
310
|
id: request.id,
|
|
247
311
|
params: data,
|
|
@@ -272,6 +336,8 @@ class PortalConnect {
|
|
|
272
336
|
transactionId: id,
|
|
273
337
|
},
|
|
274
338
|
}));
|
|
339
|
+
// Let the SDK consumer know the transaction hash
|
|
340
|
+
this.emit('portal_signgatureReceived', txHash);
|
|
275
341
|
});
|
|
276
342
|
}
|
|
277
343
|
handleSigningRejected(data) {
|
|
@@ -288,5 +354,28 @@ class PortalConnect {
|
|
|
288
354
|
}));
|
|
289
355
|
});
|
|
290
356
|
}
|
|
357
|
+
sendFinalMessageAndClose() {
|
|
358
|
+
var _a;
|
|
359
|
+
if (this.socket) {
|
|
360
|
+
this.connectionState = ConnectionStates.DISCONNECTING;
|
|
361
|
+
this.socket.send(JSON.stringify({
|
|
362
|
+
event: 'disconnect',
|
|
363
|
+
data: {
|
|
364
|
+
id: '',
|
|
365
|
+
topic: this.topic,
|
|
366
|
+
},
|
|
367
|
+
}));
|
|
368
|
+
this.topic = undefined;
|
|
369
|
+
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.close();
|
|
370
|
+
this.connectionState = ConnectionStates.DISCONNECTED;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
291
373
|
}
|
|
374
|
+
var ConnectionStates;
|
|
375
|
+
(function (ConnectionStates) {
|
|
376
|
+
ConnectionStates["CONNECTED"] = "CONNECTED";
|
|
377
|
+
ConnectionStates["CONNECTING"] = "CONNECTING";
|
|
378
|
+
ConnectionStates["DISCONNECTED"] = "DISCONNECTED";
|
|
379
|
+
ConnectionStates["DISCONNECTING"] = "DISCONNECTING";
|
|
380
|
+
})(ConnectionStates = exports.ConnectionStates || (exports.ConnectionStates = {}));
|
|
292
381
|
exports.default = PortalConnect;
|
package/lib/esm/index.js
CHANGED
|
@@ -7,18 +7,53 @@ 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 { Provider } from '@portal-hq/provider';
|
|
10
11
|
class PortalConnect {
|
|
11
|
-
constructor({
|
|
12
|
-
|
|
12
|
+
constructor({ apiKey, chainId, keychain, gatewayConfig,
|
|
13
|
+
// Optional
|
|
14
|
+
isSimulator = false, autoApprove = false, version = 'v4', apiHost = 'api.portalhq.io', mpcHost = 'mpc.portalhq.io', webSocketServer = 'connect.portalhq.io', }) {
|
|
15
|
+
this.connectionState = ConnectionStates.DISCONNECTED;
|
|
16
|
+
this.apiKey = apiKey;
|
|
13
17
|
this.events = {};
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
18
|
+
this.websocketServer = webSocketServer;
|
|
19
|
+
this.provider = new Provider({
|
|
20
|
+
apiKey,
|
|
21
|
+
chainId,
|
|
22
|
+
gatewayConfig,
|
|
23
|
+
keychain,
|
|
24
|
+
isSimulator,
|
|
25
|
+
autoApprove,
|
|
26
|
+
version,
|
|
27
|
+
apiHost,
|
|
28
|
+
mpcHost,
|
|
29
|
+
});
|
|
30
|
+
// Inbound from the Provider
|
|
31
|
+
this.on('portalConnect_signingRequested', (data) => {
|
|
32
|
+
this.emit('portal_signingRequested', data);
|
|
33
|
+
});
|
|
34
|
+
// Inbound from SDK consumers
|
|
35
|
+
this.on('portal_signingApproved', (data) => {
|
|
36
|
+
this.provider.emit('portal_signingApproved', data);
|
|
37
|
+
});
|
|
38
|
+
this.on('portal_signingRejected', (data) => {
|
|
39
|
+
this.provider.emit('portal_signingRejected', data);
|
|
40
|
+
});
|
|
16
41
|
// Do the OG binding trick to preserve the `this` context
|
|
17
42
|
this.handleSessionApproved = this.handleSessionApproved.bind(this);
|
|
18
43
|
this.handleSessionRejected = this.handleSessionRejected.bind(this);
|
|
19
44
|
this.handleSessionRequest = this.handleSessionRequest.bind(this);
|
|
20
45
|
this.handleSigningRejected = this.handleSigningRejected.bind(this);
|
|
21
46
|
}
|
|
47
|
+
get address() {
|
|
48
|
+
return this.provider.address;
|
|
49
|
+
}
|
|
50
|
+
get chainId() {
|
|
51
|
+
return this.provider.chainId;
|
|
52
|
+
}
|
|
53
|
+
get connected() {
|
|
54
|
+
return (this.connectionState === ConnectionStates.CONNECTED ||
|
|
55
|
+
this.connectionState === ConnectionStates.CONNECTING);
|
|
56
|
+
}
|
|
22
57
|
/**
|
|
23
58
|
* Establishes a websocket connection with the Connect Proxy and dispatches the binding
|
|
24
59
|
* of websocket events for the newly established socket
|
|
@@ -36,15 +71,29 @@ class PortalConnect {
|
|
|
36
71
|
// @ts-ignore
|
|
37
72
|
{
|
|
38
73
|
headers: {
|
|
39
|
-
Authorization: `Bearer ${this.
|
|
74
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
40
75
|
},
|
|
41
76
|
});
|
|
77
|
+
this.uri = uri;
|
|
42
78
|
this.bindToSocketEvents(this.socket, uri);
|
|
43
79
|
});
|
|
44
80
|
}
|
|
45
81
|
deinit() {
|
|
46
82
|
this.events = {};
|
|
47
83
|
}
|
|
84
|
+
disconnect() {
|
|
85
|
+
this.sendFinalMessageAndClose();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Triggers the chain on the dapp to change to match the chain of the wallet
|
|
89
|
+
*
|
|
90
|
+
* @param chainId The number of the chainId to switch to
|
|
91
|
+
*/
|
|
92
|
+
setChainId(chainId) {
|
|
93
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
94
|
+
this.provider.setChainId(chainId, this);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
48
97
|
/**
|
|
49
98
|
* Invokes all registered event handlers with the data provided
|
|
50
99
|
* - If any `once` handlers exist, they are removed after all handlers are invoked
|
|
@@ -133,7 +182,8 @@ class PortalConnect {
|
|
|
133
182
|
* - Fires a subsequent call over the websocket to notify the proxy of the uri to connect to
|
|
134
183
|
*/
|
|
135
184
|
socket.onopen = () => __awaiter(this, void 0, void 0, function* () {
|
|
136
|
-
const
|
|
185
|
+
const address = yield this.address;
|
|
186
|
+
const { chainId } = this.provider;
|
|
137
187
|
// Tell the proxy server where to connect to downstream
|
|
138
188
|
socket.send(JSON.stringify({
|
|
139
189
|
event: 'connect',
|
|
@@ -144,6 +194,18 @@ class PortalConnect {
|
|
|
144
194
|
},
|
|
145
195
|
}));
|
|
146
196
|
});
|
|
197
|
+
this.on('portalConnect_chainChanged', (data) => {
|
|
198
|
+
var _a;
|
|
199
|
+
// Tell the proxy server where to connect to downstream
|
|
200
|
+
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({
|
|
201
|
+
event: 'portal_chainChanged',
|
|
202
|
+
data: {
|
|
203
|
+
topic: this.topic,
|
|
204
|
+
uri: this.uri,
|
|
205
|
+
chainId: data.chainId,
|
|
206
|
+
},
|
|
207
|
+
}));
|
|
208
|
+
});
|
|
147
209
|
socket.onerror = (event) => __awaiter(this, void 0, void 0, function* () {
|
|
148
210
|
let errorMessage = 'An unexpected error occurred.';
|
|
149
211
|
if (event instanceof ErrorEvent) {
|
|
@@ -166,12 +228,13 @@ class PortalConnect {
|
|
|
166
228
|
this.emit('disconnect', message.data);
|
|
167
229
|
break;
|
|
168
230
|
case 'connected':
|
|
169
|
-
this.
|
|
231
|
+
this.connectionState = ConnectionStates.CONNECTED;
|
|
232
|
+
this.topic = message.data.topic;
|
|
170
233
|
this.emit('connect', message.data);
|
|
171
234
|
break;
|
|
172
235
|
case 'disconnect':
|
|
173
236
|
socket.close();
|
|
174
|
-
this.
|
|
237
|
+
this.connectionState = ConnectionStates.DISCONNECTED;
|
|
175
238
|
this.emit('disconnect', message.data);
|
|
176
239
|
break;
|
|
177
240
|
case 'session_request':
|
|
@@ -201,28 +264,28 @@ class PortalConnect {
|
|
|
201
264
|
handleProviderRequest(method, params, request) {
|
|
202
265
|
return __awaiter(this, void 0, void 0, function* () {
|
|
203
266
|
// Bind to potential signing rejection events
|
|
204
|
-
this.
|
|
267
|
+
this.provider.on('portal_signingRejected', this.handleSigningRejected);
|
|
205
268
|
// Bind to potential signature received events
|
|
206
|
-
this.
|
|
269
|
+
this.provider.on('portal_signatureReceived', ({ method: signedMethod, params: signedParams, signature }) => {
|
|
207
270
|
if (signedMethod === method &&
|
|
208
271
|
JSON.stringify(signedParams) === JSON.stringify(params)) {
|
|
209
272
|
this.handleSignatureReceived(request, signature);
|
|
210
273
|
}
|
|
211
274
|
});
|
|
212
275
|
// Pass the request along to the provider
|
|
213
|
-
yield this.
|
|
276
|
+
yield this.provider.request({ method, params, connect: this });
|
|
214
277
|
});
|
|
215
278
|
}
|
|
216
279
|
handleSessionApproved(data, request) {
|
|
217
280
|
var _a;
|
|
218
281
|
return __awaiter(this, void 0, void 0, function* () {
|
|
219
|
-
const address = yield this.
|
|
282
|
+
const address = yield this.address;
|
|
220
283
|
// Notify the proxy server that the session request was approved
|
|
221
284
|
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({
|
|
222
285
|
event: 'portal_dappSessionApproved',
|
|
223
286
|
data: {
|
|
224
287
|
address,
|
|
225
|
-
chainId: this.
|
|
288
|
+
chainId: this.chainId,
|
|
226
289
|
topic: request.topic,
|
|
227
290
|
id: request.id,
|
|
228
291
|
params: data,
|
|
@@ -233,13 +296,13 @@ class PortalConnect {
|
|
|
233
296
|
handleSessionRejected(data, request) {
|
|
234
297
|
var _a;
|
|
235
298
|
return __awaiter(this, void 0, void 0, function* () {
|
|
236
|
-
const address = yield this.
|
|
299
|
+
const address = yield this.address;
|
|
237
300
|
// Notify the proxy server that the session request was rejected
|
|
238
301
|
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({
|
|
239
302
|
event: 'portal_dappSessionRejected',
|
|
240
303
|
data: {
|
|
241
304
|
address,
|
|
242
|
-
chainId: this.
|
|
305
|
+
chainId: this.chainId,
|
|
243
306
|
topic: request.topic,
|
|
244
307
|
id: request.id,
|
|
245
308
|
params: data,
|
|
@@ -270,6 +333,8 @@ class PortalConnect {
|
|
|
270
333
|
transactionId: id,
|
|
271
334
|
},
|
|
272
335
|
}));
|
|
336
|
+
// Let the SDK consumer know the transaction hash
|
|
337
|
+
this.emit('portal_signgatureReceived', txHash);
|
|
273
338
|
});
|
|
274
339
|
}
|
|
275
340
|
handleSigningRejected(data) {
|
|
@@ -286,5 +351,28 @@ class PortalConnect {
|
|
|
286
351
|
}));
|
|
287
352
|
});
|
|
288
353
|
}
|
|
354
|
+
sendFinalMessageAndClose() {
|
|
355
|
+
var _a;
|
|
356
|
+
if (this.socket) {
|
|
357
|
+
this.connectionState = ConnectionStates.DISCONNECTING;
|
|
358
|
+
this.socket.send(JSON.stringify({
|
|
359
|
+
event: 'disconnect',
|
|
360
|
+
data: {
|
|
361
|
+
id: '',
|
|
362
|
+
topic: this.topic,
|
|
363
|
+
},
|
|
364
|
+
}));
|
|
365
|
+
this.topic = undefined;
|
|
366
|
+
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.close();
|
|
367
|
+
this.connectionState = ConnectionStates.DISCONNECTED;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
289
370
|
}
|
|
371
|
+
export var ConnectionStates;
|
|
372
|
+
(function (ConnectionStates) {
|
|
373
|
+
ConnectionStates["CONNECTED"] = "CONNECTED";
|
|
374
|
+
ConnectionStates["CONNECTING"] = "CONNECTING";
|
|
375
|
+
ConnectionStates["DISCONNECTED"] = "DISCONNECTED";
|
|
376
|
+
ConnectionStates["DISCONNECTING"] = "DISCONNECTING";
|
|
377
|
+
})(ConnectionStates || (ConnectionStates = {}));
|
|
290
378
|
export default PortalConnect;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portal-hq/connect",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"main": "lib/commonjs/index",
|
|
5
5
|
"module": "lib/esm/index",
|
|
6
6
|
"source": "src/index",
|
|
@@ -31,6 +31,5 @@
|
|
|
31
31
|
"@portal-hq/core": "*",
|
|
32
32
|
"react": "*",
|
|
33
33
|
"react-native": "*"
|
|
34
|
-
}
|
|
35
|
-
"gitHead": "acac6640bcad15621912376d95c0bd09509387e1"
|
|
34
|
+
}
|
|
36
35
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Provider } from '@portal-hq/provider'
|
|
2
2
|
import type {
|
|
3
3
|
EventHandler,
|
|
4
4
|
PortalConnectOptions,
|
|
@@ -8,23 +8,77 @@ import type {
|
|
|
8
8
|
SessionRequest,
|
|
9
9
|
WebsocketMessage,
|
|
10
10
|
} from '../types.d'
|
|
11
|
+
import { SwitchEthereumChainParameter } from '@portal-hq/provider/types'
|
|
11
12
|
|
|
12
13
|
class PortalConnect {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
private apiKey: string
|
|
15
|
+
private connectionState: ConnectionStates = ConnectionStates.DISCONNECTED
|
|
16
|
+
private provider: Provider
|
|
17
|
+
private socket?: WebSocket
|
|
18
|
+
private topic?: string
|
|
19
|
+
private uri?: string
|
|
20
|
+
private websocketServer: string
|
|
17
21
|
|
|
18
22
|
private events: Record<string, RegisteredEventHandler[]>
|
|
19
23
|
|
|
24
|
+
private get address(): Promise<string | undefined> {
|
|
25
|
+
return this.provider.address
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private get chainId(): number {
|
|
29
|
+
return this.provider.chainId
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public get connected(): boolean {
|
|
33
|
+
return (
|
|
34
|
+
this.connectionState === ConnectionStates.CONNECTED ||
|
|
35
|
+
this.connectionState === ConnectionStates.CONNECTING
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
20
39
|
constructor({
|
|
21
|
-
|
|
22
|
-
|
|
40
|
+
apiKey,
|
|
41
|
+
chainId,
|
|
42
|
+
keychain,
|
|
43
|
+
gatewayConfig,
|
|
44
|
+
|
|
45
|
+
// Optional
|
|
46
|
+
isSimulator = false,
|
|
47
|
+
autoApprove = false,
|
|
48
|
+
version = 'v4',
|
|
49
|
+
apiHost = 'api.portalhq.io',
|
|
50
|
+
mpcHost = 'mpc.portalhq.io',
|
|
51
|
+
webSocketServer = 'connect.portalhq.io',
|
|
23
52
|
}: PortalConnectOptions) {
|
|
24
|
-
this.
|
|
53
|
+
this.apiKey = apiKey
|
|
25
54
|
this.events = {}
|
|
26
|
-
this.
|
|
27
|
-
|
|
55
|
+
this.websocketServer = webSocketServer
|
|
56
|
+
|
|
57
|
+
this.provider = new Provider({
|
|
58
|
+
apiKey,
|
|
59
|
+
chainId,
|
|
60
|
+
gatewayConfig,
|
|
61
|
+
keychain,
|
|
62
|
+
isSimulator,
|
|
63
|
+
autoApprove,
|
|
64
|
+
version,
|
|
65
|
+
apiHost,
|
|
66
|
+
mpcHost,
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
// Inbound from the Provider
|
|
70
|
+
this.on('portalConnect_signingRequested', (data) => {
|
|
71
|
+
this.emit('portal_signingRequested', data)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Inbound from SDK consumers
|
|
75
|
+
this.on('portal_signingApproved', (data) => {
|
|
76
|
+
this.provider.emit('portal_signingApproved', data)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
this.on('portal_signingRejected', (data) => {
|
|
80
|
+
this.provider.emit('portal_signingRejected', data)
|
|
81
|
+
})
|
|
28
82
|
|
|
29
83
|
// Do the OG binding trick to preserve the `this` context
|
|
30
84
|
this.handleSessionApproved = this.handleSessionApproved.bind(this)
|
|
@@ -52,16 +106,31 @@ class PortalConnect {
|
|
|
52
106
|
// @ts-ignore
|
|
53
107
|
{
|
|
54
108
|
headers: {
|
|
55
|
-
Authorization: `Bearer ${this.
|
|
109
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
56
110
|
},
|
|
57
111
|
},
|
|
58
112
|
)
|
|
113
|
+
this.uri = uri
|
|
59
114
|
this.bindToSocketEvents(this.socket, uri)
|
|
60
115
|
}
|
|
61
116
|
|
|
62
|
-
public deinit() {
|
|
63
|
-
|
|
64
|
-
}
|
|
117
|
+
public deinit() {
|
|
118
|
+
this.events = {}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public disconnect() {
|
|
122
|
+
this.sendFinalMessageAndClose()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Triggers the chain on the dapp to change to match the chain of the wallet
|
|
127
|
+
*
|
|
128
|
+
* @param chainId The number of the chainId to switch to
|
|
129
|
+
*/
|
|
130
|
+
public async setChainId(chainId: number): Promise<void> {
|
|
131
|
+
this.provider.setChainId(chainId, this)
|
|
132
|
+
}
|
|
133
|
+
|
|
65
134
|
|
|
66
135
|
/**
|
|
67
136
|
* Invokes all registered event handlers with the data provided
|
|
@@ -168,7 +237,8 @@ public deinit() {
|
|
|
168
237
|
* - Fires a subsequent call over the websocket to notify the proxy of the uri to connect to
|
|
169
238
|
*/
|
|
170
239
|
socket.onopen = async () => {
|
|
171
|
-
const
|
|
240
|
+
const address = await this.address
|
|
241
|
+
const { chainId } = this.provider
|
|
172
242
|
|
|
173
243
|
// Tell the proxy server where to connect to downstream
|
|
174
244
|
socket.send(
|
|
@@ -183,6 +253,20 @@ public deinit() {
|
|
|
183
253
|
)
|
|
184
254
|
}
|
|
185
255
|
|
|
256
|
+
this.on('portalConnect_chainChanged', (data) => {
|
|
257
|
+
// Tell the proxy server where to connect to downstream
|
|
258
|
+
this.socket?.send(
|
|
259
|
+
JSON.stringify({
|
|
260
|
+
event: 'portal_chainChanged',
|
|
261
|
+
data: {
|
|
262
|
+
topic: this.topic,
|
|
263
|
+
uri: this.uri,
|
|
264
|
+
chainId: (data as SwitchEthereumChainParameter).chainId,
|
|
265
|
+
},
|
|
266
|
+
}),
|
|
267
|
+
)
|
|
268
|
+
})
|
|
269
|
+
|
|
186
270
|
socket.onerror = async (event: Event) => {
|
|
187
271
|
let errorMessage = 'An unexpected error occurred.'
|
|
188
272
|
|
|
@@ -209,12 +293,13 @@ public deinit() {
|
|
|
209
293
|
this.emit('disconnect', message.data)
|
|
210
294
|
break
|
|
211
295
|
case 'connected':
|
|
212
|
-
this.
|
|
296
|
+
this.connectionState = ConnectionStates.CONNECTED
|
|
297
|
+
this.topic = message.data.topic
|
|
213
298
|
this.emit('connect', message.data)
|
|
214
299
|
break
|
|
215
300
|
case 'disconnect':
|
|
216
301
|
socket.close()
|
|
217
|
-
this.
|
|
302
|
+
this.connectionState = ConnectionStates.DISCONNECTED
|
|
218
303
|
this.emit('disconnect', message.data)
|
|
219
304
|
|
|
220
305
|
break
|
|
@@ -255,13 +340,10 @@ public deinit() {
|
|
|
255
340
|
request: SessionRequest,
|
|
256
341
|
): Promise<void> {
|
|
257
342
|
// Bind to potential signing rejection events
|
|
258
|
-
this.
|
|
259
|
-
'portal_signingRejected',
|
|
260
|
-
this.handleSigningRejected,
|
|
261
|
-
)
|
|
343
|
+
this.provider.on('portal_signingRejected', this.handleSigningRejected)
|
|
262
344
|
|
|
263
345
|
// Bind to potential signature received events
|
|
264
|
-
this.
|
|
346
|
+
this.provider.on(
|
|
265
347
|
'portal_signatureReceived',
|
|
266
348
|
({ method: signedMethod, params: signedParams, signature }) => {
|
|
267
349
|
if (
|
|
@@ -274,14 +356,14 @@ public deinit() {
|
|
|
274
356
|
)
|
|
275
357
|
|
|
276
358
|
// Pass the request along to the provider
|
|
277
|
-
await this.
|
|
359
|
+
await this.provider.request({ method, params, connect: this })
|
|
278
360
|
}
|
|
279
361
|
|
|
280
362
|
private async handleSessionApproved(
|
|
281
363
|
data: SessionProposalOrMetadata,
|
|
282
364
|
request: SessionRequest,
|
|
283
365
|
): Promise<void> {
|
|
284
|
-
const address = await this.
|
|
366
|
+
const address = await this.address
|
|
285
367
|
|
|
286
368
|
// Notify the proxy server that the session request was approved
|
|
287
369
|
this.socket?.send(
|
|
@@ -289,7 +371,7 @@ public deinit() {
|
|
|
289
371
|
event: 'portal_dappSessionApproved',
|
|
290
372
|
data: {
|
|
291
373
|
address,
|
|
292
|
-
chainId: this.
|
|
374
|
+
chainId: this.chainId,
|
|
293
375
|
topic: request.topic,
|
|
294
376
|
id: request.id,
|
|
295
377
|
params: data,
|
|
@@ -302,7 +384,7 @@ public deinit() {
|
|
|
302
384
|
data: SessionProposalOrMetadata,
|
|
303
385
|
request: SessionRequest,
|
|
304
386
|
): Promise<void> {
|
|
305
|
-
const address = await this.
|
|
387
|
+
const address = await this.address
|
|
306
388
|
|
|
307
389
|
// Notify the proxy server that the session request was rejected
|
|
308
390
|
this.socket?.send(
|
|
@@ -310,7 +392,7 @@ public deinit() {
|
|
|
310
392
|
event: 'portal_dappSessionRejected',
|
|
311
393
|
data: {
|
|
312
394
|
address,
|
|
313
|
-
chainId: this.
|
|
395
|
+
chainId: this.chainId,
|
|
314
396
|
topic: request.topic,
|
|
315
397
|
id: request.id,
|
|
316
398
|
params: data,
|
|
@@ -341,6 +423,7 @@ public deinit() {
|
|
|
341
423
|
txHash: any,
|
|
342
424
|
): Promise<void> {
|
|
343
425
|
const { id, topic } = data
|
|
426
|
+
|
|
344
427
|
// Let the server know the transaction hash
|
|
345
428
|
this.socket?.send(
|
|
346
429
|
JSON.stringify({
|
|
@@ -352,6 +435,9 @@ public deinit() {
|
|
|
352
435
|
},
|
|
353
436
|
}),
|
|
354
437
|
)
|
|
438
|
+
|
|
439
|
+
// Let the SDK consumer know the transaction hash
|
|
440
|
+
this.emit('portal_signgatureReceived', txHash)
|
|
355
441
|
}
|
|
356
442
|
|
|
357
443
|
private async handleSigningRejected(data: SessionRequest): Promise<void> {
|
|
@@ -367,6 +453,34 @@ public deinit() {
|
|
|
367
453
|
} as WebsocketMessage),
|
|
368
454
|
)
|
|
369
455
|
}
|
|
456
|
+
|
|
457
|
+
private sendFinalMessageAndClose() {
|
|
458
|
+
if (this.socket) {
|
|
459
|
+
this.connectionState = ConnectionStates.DISCONNECTING
|
|
460
|
+
this.socket.send(
|
|
461
|
+
JSON.stringify({
|
|
462
|
+
event: 'disconnect',
|
|
463
|
+
data: {
|
|
464
|
+
id: '',
|
|
465
|
+
topic: this.topic,
|
|
466
|
+
},
|
|
467
|
+
} as WebsocketMessage),
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
this.topic = undefined
|
|
471
|
+
|
|
472
|
+
this.socket?.close()
|
|
473
|
+
|
|
474
|
+
this.connectionState = ConnectionStates.DISCONNECTED
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export enum ConnectionStates {
|
|
480
|
+
CONNECTED = 'CONNECTED',
|
|
481
|
+
CONNECTING = 'CONNECTING',
|
|
482
|
+
DISCONNECTED = 'DISCONNECTED',
|
|
483
|
+
DISCONNECTING = 'DISCONNECTING',
|
|
370
484
|
}
|
|
371
485
|
|
|
372
486
|
export type {
|
package/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Portal from '@portal-hq/core'
|
|
2
|
+
import { KeychainAdapter } from '@portal-hq/utils'
|
|
2
3
|
|
|
3
4
|
export type EventHandler = (data: any) => void
|
|
4
5
|
export type SessionProposalOrMetadata = SessionProposal | PeerMetadata
|
|
@@ -41,8 +42,18 @@ export interface PeerMetadata {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
export interface PortalConnectOptions {
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
apiKey: string
|
|
46
|
+
chainId: number
|
|
47
|
+
keychain: KeychainAdapter
|
|
48
|
+
gatewayConfig: GatewayLike
|
|
49
|
+
|
|
50
|
+
// Optional
|
|
51
|
+
isSimulator?: boolean
|
|
52
|
+
autoApprove?: boolean
|
|
53
|
+
webSocketServer?: string
|
|
54
|
+
apiHost?: string
|
|
55
|
+
mpcHost?: string
|
|
56
|
+
version?: string
|
|
46
57
|
}
|
|
47
58
|
|
|
48
59
|
export interface ProtocolOptions {
|
|
@@ -103,9 +114,5 @@ export interface SigningResult {
|
|
|
103
114
|
|
|
104
115
|
export interface WebsocketMessage {
|
|
105
116
|
event: string
|
|
106
|
-
data:
|
|
107
|
-
| ConnectResult
|
|
108
|
-
| DisconnectResult
|
|
109
|
-
| SessionRequest
|
|
110
|
-
| SigningResult
|
|
117
|
+
data: ConnectResult | DisconnectResult | SessionRequest | SigningResult
|
|
111
118
|
}
|