@portal-hq/web 0.0.1-beta-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/README.md +297 -0
- package/lib/commonjs/index.js +201 -0
- package/lib/commonjs/mpc/index.js +353 -0
- package/lib/commonjs/provider/index.js +259 -0
- package/lib/commonjs/storage/index.js +17 -0
- package/lib/esm/index.js +196 -0
- package/lib/esm/mpc/index.js +351 -0
- package/lib/esm/provider/index.js +257 -0
- package/lib/esm/storage/index.js +15 -0
- package/package.json +46 -0
- package/src/index.ts +232 -0
- package/src/mpc/index.ts +443 -0
- package/src/provider/index.ts +314 -0
- package/src/storage/index.ts +29 -0
- package/types.d.ts +341 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const utils_1 = require("@portal-hq/utils");
|
|
13
|
+
const WEB_SDK_VERSION = '0.0.1-beta-1';
|
|
14
|
+
class Mpc {
|
|
15
|
+
constructor({ apiKey, chainId, portal, rpcUrl,
|
|
16
|
+
// Optional
|
|
17
|
+
apiHost = 'api.portalhq.io', autoApprove = false, mpcHost = 'mpc.portalhq.io', webHost = 'web.portalhq.io', }) {
|
|
18
|
+
this.apiHost = apiHost;
|
|
19
|
+
this.apiKey = apiKey;
|
|
20
|
+
this.autoApprove = autoApprove;
|
|
21
|
+
this.chainId = chainId;
|
|
22
|
+
this.mpcHost = mpcHost;
|
|
23
|
+
this.portal = portal;
|
|
24
|
+
this.rpcUrl = rpcUrl;
|
|
25
|
+
this.webHost = webHost;
|
|
26
|
+
// Handle scoping of certain functions
|
|
27
|
+
this.configureIframe = this.configureIframe.bind(this);
|
|
28
|
+
// Create the iFrame for MPC operations
|
|
29
|
+
this.appendIframe();
|
|
30
|
+
}
|
|
31
|
+
// In Progress
|
|
32
|
+
backup(data) {
|
|
33
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
+
const message = {
|
|
35
|
+
type: 'portal:wasm:backup',
|
|
36
|
+
data,
|
|
37
|
+
};
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
// Create a function to be bound when backup is triggered
|
|
40
|
+
const handleBackup = (event) => {
|
|
41
|
+
const { type, data: result } = event;
|
|
42
|
+
// Check that the message is the one we're looking for
|
|
43
|
+
if (type === 'portal:wasm:backupResult') {
|
|
44
|
+
// Check if the result is an error
|
|
45
|
+
if (result.error && result.error.code > 0) {
|
|
46
|
+
// Remove the event listener
|
|
47
|
+
window.removeEventListener('message', handleBackup);
|
|
48
|
+
// Reject the promise with the error
|
|
49
|
+
return reject(new utils_1.PortalMpcError(result.error));
|
|
50
|
+
}
|
|
51
|
+
// Remove the event listener
|
|
52
|
+
window.removeEventListener('message', handleBackup);
|
|
53
|
+
// Resolve the promise with the result
|
|
54
|
+
resolve(result);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
// Bind the function to the message event
|
|
58
|
+
window.addEventListener('message', handleBackup);
|
|
59
|
+
// Send the request to the iframe
|
|
60
|
+
this.postMessage(message);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// In Progress
|
|
65
|
+
decrypt(data) {
|
|
66
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
const message = {
|
|
68
|
+
type: 'portal:wasm:decrypt',
|
|
69
|
+
data,
|
|
70
|
+
};
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const handleDecrypt = (event) => {
|
|
73
|
+
const { type, data: result } = event;
|
|
74
|
+
// Check that the message is the one we're looking for
|
|
75
|
+
if (type === 'portal:wasm:decryptResult') {
|
|
76
|
+
// Check if the result is an error
|
|
77
|
+
if (result.error && result.error.code > 0) {
|
|
78
|
+
// Remove the event listener
|
|
79
|
+
window.removeEventListener('message', handleDecrypt);
|
|
80
|
+
// Reject the promise with the error
|
|
81
|
+
return reject(new utils_1.PortalMpcError(result.error));
|
|
82
|
+
}
|
|
83
|
+
// Remove the event listener
|
|
84
|
+
window.removeEventListener('message', handleDecrypt);
|
|
85
|
+
// Resolve the promise with the result
|
|
86
|
+
resolve(result);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
// Bind the function to the message event
|
|
90
|
+
window.addEventListener('message', handleDecrypt);
|
|
91
|
+
// Send the request to the iframe
|
|
92
|
+
this.postMessage(message);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// In Progress
|
|
97
|
+
encrypt(data) {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
const message = {
|
|
100
|
+
type: 'portal:wasm:encrypt',
|
|
101
|
+
data,
|
|
102
|
+
};
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const handleEncrypt = (event) => {
|
|
105
|
+
const { type, data: result } = event;
|
|
106
|
+
// Check that the message is the one we're looking for
|
|
107
|
+
if (type === 'portal:wasm:encryptResult') {
|
|
108
|
+
// Check if the result is an error
|
|
109
|
+
if (result.error && result.error.code > 0) {
|
|
110
|
+
// Remove the event listener
|
|
111
|
+
window.removeEventListener('message', handleEncrypt);
|
|
112
|
+
// Reject the promise with the error
|
|
113
|
+
return reject(new utils_1.PortalMpcError(result.error));
|
|
114
|
+
}
|
|
115
|
+
// Remove the event listener
|
|
116
|
+
window.removeEventListener('message', handleEncrypt);
|
|
117
|
+
// Resolve the promise with the result
|
|
118
|
+
resolve(result);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
// Bind the function to the message event
|
|
122
|
+
window.addEventListener('message', handleEncrypt);
|
|
123
|
+
// Send the request to the iframe
|
|
124
|
+
this.postMessage(message);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
generate(data) {
|
|
129
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
130
|
+
const message = {
|
|
131
|
+
type: 'portal:wasm:generate',
|
|
132
|
+
data,
|
|
133
|
+
};
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
// Create a function to be bound when generate is triggered
|
|
136
|
+
const handleGenerate = (event) => {
|
|
137
|
+
console.log(`[MPC] Temporary listener received event: `, event);
|
|
138
|
+
const { type, data: result } = event.data;
|
|
139
|
+
// Handle errors
|
|
140
|
+
if (type === 'portal:wasm:generateError') {
|
|
141
|
+
// Remove the event listener
|
|
142
|
+
window.removeEventListener('message', handleGenerate);
|
|
143
|
+
// Reject the promise with the error
|
|
144
|
+
return reject(new utils_1.PortalMpcError(result));
|
|
145
|
+
}
|
|
146
|
+
else if (type === 'portal:wasm:generateResult') {
|
|
147
|
+
// Remove the event listener
|
|
148
|
+
window.removeEventListener('message', handleGenerate);
|
|
149
|
+
// Resolve the promise with the result
|
|
150
|
+
resolve(result);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
// Bind the function to the message event
|
|
154
|
+
window.addEventListener('message', handleGenerate);
|
|
155
|
+
// Send the request to the iframe
|
|
156
|
+
this.postMessage(message);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
getAddress() {
|
|
161
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
162
|
+
const message = {
|
|
163
|
+
type: 'portal:address',
|
|
164
|
+
data: {},
|
|
165
|
+
};
|
|
166
|
+
return new Promise((resolve) => {
|
|
167
|
+
// Create a function to be bound when getAddress is triggered
|
|
168
|
+
const handleGetAddress = (event) => {
|
|
169
|
+
const { type, data: result } = event.data;
|
|
170
|
+
// Check that the message is the one we're looking for
|
|
171
|
+
if (type === 'portal:addressResult') {
|
|
172
|
+
// Remove the event listener
|
|
173
|
+
window.removeEventListener('message', handleGetAddress);
|
|
174
|
+
// Resolve the promise with the result
|
|
175
|
+
resolve(result);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
// Bind the function to the message event
|
|
179
|
+
window.addEventListener('message', handleGetAddress);
|
|
180
|
+
// Send the request to the iframe
|
|
181
|
+
this.postMessage(message);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// In Progress
|
|
186
|
+
recover(data) {
|
|
187
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
188
|
+
yield this.recoverBackup(data);
|
|
189
|
+
// TODO: Write the DKG Result to local storage
|
|
190
|
+
const cipherText = yield this.recoverSigning(data);
|
|
191
|
+
return JSON.stringify(cipherText);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
// In Progress
|
|
195
|
+
recoverBackup(data) {
|
|
196
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
197
|
+
const message = {
|
|
198
|
+
type: 'portal:wasm:recoverBackup',
|
|
199
|
+
data,
|
|
200
|
+
};
|
|
201
|
+
return new Promise((resolve, reject) => {
|
|
202
|
+
// Create a function to be bound when recoverSigning is triggered
|
|
203
|
+
const handleRecovery = (event) => {
|
|
204
|
+
const { type, data: result } = event;
|
|
205
|
+
// Check that the message is the one we're looking for
|
|
206
|
+
if (type === 'portal:wasm:recoverBackupResult') {
|
|
207
|
+
// Check if the result is an error
|
|
208
|
+
if (result.error && result.error.code > 0) {
|
|
209
|
+
// Remove the event listener
|
|
210
|
+
window.removeEventListener('message', handleRecovery);
|
|
211
|
+
// Reject the promise with the error
|
|
212
|
+
return reject(new utils_1.PortalMpcError(result.error));
|
|
213
|
+
}
|
|
214
|
+
// Remove the event listener
|
|
215
|
+
window.removeEventListener('message', handleRecovery);
|
|
216
|
+
// Resolve the promise with the result
|
|
217
|
+
resolve(result);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
// Bind the function to the message event
|
|
221
|
+
window.addEventListener('message', handleRecovery);
|
|
222
|
+
// Send the request to the iframe
|
|
223
|
+
this.postMessage(message);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
// In Progress
|
|
228
|
+
recoverSigning(data) {
|
|
229
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
230
|
+
const message = {
|
|
231
|
+
type: 'portal:wasm:recoverSigning',
|
|
232
|
+
data,
|
|
233
|
+
};
|
|
234
|
+
return new Promise((resolve, reject) => {
|
|
235
|
+
// Create a function to be bound when recoverSigning is triggered
|
|
236
|
+
const handleRecovery = (event) => {
|
|
237
|
+
const { type, data: result } = event;
|
|
238
|
+
// Check that the message is the one we're looking for
|
|
239
|
+
if (type === 'portal:wasm:recoverSigningResult') {
|
|
240
|
+
// Check if the result is an error
|
|
241
|
+
if (result.error && result.error.code > 0) {
|
|
242
|
+
// Remove the event listener
|
|
243
|
+
window.removeEventListener('message', handleRecovery);
|
|
244
|
+
// Reject the promise with the error
|
|
245
|
+
return reject(new utils_1.PortalMpcError(result.error));
|
|
246
|
+
}
|
|
247
|
+
// Remove the event listener
|
|
248
|
+
window.removeEventListener('message', handleRecovery);
|
|
249
|
+
// Resolve the promise with the result
|
|
250
|
+
resolve(result);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
// Bind the function to the message event
|
|
254
|
+
window.addEventListener('message', handleRecovery);
|
|
255
|
+
// Send the request to the iframe
|
|
256
|
+
this.postMessage(message);
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
sign(data) {
|
|
261
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
262
|
+
const message = {
|
|
263
|
+
type: 'portal:wasm:sign',
|
|
264
|
+
data,
|
|
265
|
+
};
|
|
266
|
+
return new Promise((resolve, reject) => {
|
|
267
|
+
// Create a function to be bound when sign is triggered
|
|
268
|
+
const handleSign = (event) => {
|
|
269
|
+
const { type, data: result } = event.data;
|
|
270
|
+
if (type === 'portal:wasm:signError') {
|
|
271
|
+
// Remove the event listener
|
|
272
|
+
window.removeEventListener('message', handleSign);
|
|
273
|
+
// Reject the promise with the error
|
|
274
|
+
return reject(new utils_1.PortalMpcError(result));
|
|
275
|
+
}
|
|
276
|
+
else if (type === 'portal:wasm:signResult') {
|
|
277
|
+
// Remove the event listener
|
|
278
|
+
window.removeEventListener('message', handleSign);
|
|
279
|
+
// Resolve the promise with the result
|
|
280
|
+
resolve(result);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
// Bind the function to the message event
|
|
284
|
+
window.addEventListener('message', handleSign);
|
|
285
|
+
// Send the request to the iframe
|
|
286
|
+
this.postMessage(message);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
/***************************
|
|
291
|
+
* Private Methods
|
|
292
|
+
***************************/
|
|
293
|
+
/**
|
|
294
|
+
* Appends the iframe to the document body
|
|
295
|
+
*/
|
|
296
|
+
appendIframe() {
|
|
297
|
+
const source = this.webHost.startsWith('locahost:')
|
|
298
|
+
? `http://${this.webHost}/${WEB_SDK_VERSION}/iframe/index.html?t=${Date.now()}`
|
|
299
|
+
: `https://${this.webHost}/${WEB_SDK_VERSION}/iframe/index.html?t=${Date.now()}`;
|
|
300
|
+
const iframe = document.createElement('iframe');
|
|
301
|
+
iframe.height = '0';
|
|
302
|
+
iframe.width = '0';
|
|
303
|
+
iframe.src = source;
|
|
304
|
+
iframe.addEventListener('load', this.configureIframe);
|
|
305
|
+
document.body.appendChild(iframe);
|
|
306
|
+
this.iframe = iframe;
|
|
307
|
+
}
|
|
308
|
+
configureIframe() {
|
|
309
|
+
const config = {
|
|
310
|
+
apiHost: this.apiHost,
|
|
311
|
+
apiKey: this.apiKey,
|
|
312
|
+
autoApprove: this.autoApprove,
|
|
313
|
+
chainId: this.chainId,
|
|
314
|
+
mpcHost: this.mpcHost,
|
|
315
|
+
rpcUrl: this.rpcUrl,
|
|
316
|
+
};
|
|
317
|
+
const message = {
|
|
318
|
+
type: 'portal:configure',
|
|
319
|
+
data: config
|
|
320
|
+
};
|
|
321
|
+
this.postMessage(message);
|
|
322
|
+
this.waitForReadyMessage();
|
|
323
|
+
}
|
|
324
|
+
getOrigin() {
|
|
325
|
+
const origin = this.webHost.startsWith('localhost:')
|
|
326
|
+
? `http://${this.webHost}`
|
|
327
|
+
: `https://${this.webHost}`;
|
|
328
|
+
return origin;
|
|
329
|
+
}
|
|
330
|
+
postMessage(event) {
|
|
331
|
+
var _a, _b, _c;
|
|
332
|
+
console.log(`[MpcProxy] Sending new message: `, event, (_a = this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow);
|
|
333
|
+
(_c = (_b = this.iframe) === null || _b === void 0 ? void 0 : _b.contentWindow) === null || _c === void 0 ? void 0 : _c.postMessage(event, this.getOrigin());
|
|
334
|
+
}
|
|
335
|
+
waitForReadyMessage() {
|
|
336
|
+
const handleReady = (message) => __awaiter(this, void 0, void 0, function* () {
|
|
337
|
+
const { type, data } = message.data;
|
|
338
|
+
if (type === 'portal:wasm:ready' && data === true) {
|
|
339
|
+
// Unbind the event listener
|
|
340
|
+
window.removeEventListener('message', handleReady);
|
|
341
|
+
// Update ready state
|
|
342
|
+
this.portal.ready = true;
|
|
343
|
+
// Update the address
|
|
344
|
+
const address = yield this.getAddress();
|
|
345
|
+
this.portal.address = address;
|
|
346
|
+
// Trigger the ready callback
|
|
347
|
+
this.portal.triggerReady();
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
window.addEventListener('message', handleReady);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
exports.default = Mpc;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const utils_1 = require("@portal-hq/utils");
|
|
13
|
+
const passiveSignerMethods = [
|
|
14
|
+
'eth_accounts',
|
|
15
|
+
'eth_chainId',
|
|
16
|
+
'eth_requestAccounts',
|
|
17
|
+
];
|
|
18
|
+
const signerMethods = [
|
|
19
|
+
'eth_accounts',
|
|
20
|
+
'eth_chainId',
|
|
21
|
+
'eth_requestAccounts',
|
|
22
|
+
'eth_sendTransaction',
|
|
23
|
+
'eth_sign',
|
|
24
|
+
'eth_signTransaction',
|
|
25
|
+
'eth_signTypedData_v3',
|
|
26
|
+
'eth_signTypedData_v4',
|
|
27
|
+
'personal_sign',
|
|
28
|
+
];
|
|
29
|
+
class Provider {
|
|
30
|
+
constructor({ autoApprove = false, portal, }) {
|
|
31
|
+
this.autoApprove = autoApprove;
|
|
32
|
+
this.events = {};
|
|
33
|
+
this.portal = portal;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Invokes all registered event handlers with the data provided
|
|
37
|
+
* - If any `once` handlers exist, they are removed after all handlers are invoked
|
|
38
|
+
*
|
|
39
|
+
* @param event The name of the event to be handled
|
|
40
|
+
* @param data The data to be passed to registered event handlers
|
|
41
|
+
* @returns BaseProvider
|
|
42
|
+
*/
|
|
43
|
+
emit(event, data) {
|
|
44
|
+
// Grab the registered event handlers if any are available
|
|
45
|
+
const handlers = this.events[event] || [];
|
|
46
|
+
// Execute every event handler
|
|
47
|
+
for (const registeredEventHandler of handlers) {
|
|
48
|
+
registeredEventHandler.handler(data);
|
|
49
|
+
}
|
|
50
|
+
// Remove any registered event handlers with the `once` flag
|
|
51
|
+
this.events[event] = handlers.filter((handler) => !handler.once);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Registers an event handler for the provided event
|
|
56
|
+
*
|
|
57
|
+
* @param event The event name to add a handler to
|
|
58
|
+
* @param callback The callback to be invoked when the event is emitted
|
|
59
|
+
* @returns BaseProvider
|
|
60
|
+
*/
|
|
61
|
+
on(event, callback) {
|
|
62
|
+
// If no handlers are registered for this event, create an entry for the event
|
|
63
|
+
if (!this.events[event]) {
|
|
64
|
+
this.events[event] = [];
|
|
65
|
+
}
|
|
66
|
+
// Register event handler with the rudimentary event bus
|
|
67
|
+
if (typeof callback !== 'undefined') {
|
|
68
|
+
this.events[event].push({
|
|
69
|
+
handler: callback,
|
|
70
|
+
once: false,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
removeEventListener(event, listenerToRemove) {
|
|
76
|
+
if (!this.events[event]) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (!listenerToRemove) {
|
|
80
|
+
this.events[event] = [];
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const filterEventHandlers = (registeredEventHandler) => {
|
|
84
|
+
return registeredEventHandler.handler !== listenerToRemove;
|
|
85
|
+
};
|
|
86
|
+
this.events[event] = this.events[event].filter(filterEventHandlers);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Handles request routing in compliance with the EIP-1193 Ethereum Javascript Provider API
|
|
91
|
+
* - See here for more info: https://eips.ethereum.org/EIPS/eip-1193
|
|
92
|
+
*
|
|
93
|
+
* @param args The arguments of the request being made
|
|
94
|
+
* @returns Promise<any>
|
|
95
|
+
*/
|
|
96
|
+
request({ method, params }) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
if (method === 'eth_chainId') {
|
|
99
|
+
return this.portal.chainId;
|
|
100
|
+
}
|
|
101
|
+
const isSignerMethod = signerMethods.includes(method);
|
|
102
|
+
let result;
|
|
103
|
+
if (!isSignerMethod && !method.startsWith('wallet_')) {
|
|
104
|
+
// Send to Gateway for RPC calls
|
|
105
|
+
const response = yield this.handleGatewayRequest({ method, params });
|
|
106
|
+
this.emit('portal_signatureReceived', {
|
|
107
|
+
method,
|
|
108
|
+
params,
|
|
109
|
+
signature: response,
|
|
110
|
+
});
|
|
111
|
+
if (response.error) {
|
|
112
|
+
throw new utils_1.ProviderRpcError(response.error);
|
|
113
|
+
}
|
|
114
|
+
result = response.result;
|
|
115
|
+
}
|
|
116
|
+
else if (isSignerMethod) {
|
|
117
|
+
// Handle signing
|
|
118
|
+
const transactionHash = yield this.handleSigningRequest({
|
|
119
|
+
method,
|
|
120
|
+
params,
|
|
121
|
+
});
|
|
122
|
+
if (transactionHash) {
|
|
123
|
+
this.emit('portal_signatureReceived', {
|
|
124
|
+
method,
|
|
125
|
+
params,
|
|
126
|
+
signature: transactionHash,
|
|
127
|
+
});
|
|
128
|
+
result = transactionHash;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Unsupported method
|
|
133
|
+
throw new utils_1.ProviderRpcError({
|
|
134
|
+
code: utils_1.RpcErrorCodes.UnsupportedMethod,
|
|
135
|
+
data: {
|
|
136
|
+
method,
|
|
137
|
+
params,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/************************
|
|
145
|
+
* Private Methods
|
|
146
|
+
************************/
|
|
147
|
+
/**
|
|
148
|
+
* Kicks off the approval flow for a given request
|
|
149
|
+
*
|
|
150
|
+
* @param args The arguments of the request being made
|
|
151
|
+
*/
|
|
152
|
+
getApproval({ method, params, }) {
|
|
153
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
154
|
+
// If autoApprove is enabled, just resolve to true
|
|
155
|
+
if (this.autoApprove) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
const signingHandlers = this.events['portal_signingRequested'];
|
|
159
|
+
if (!signingHandlers || signingHandlers.length === 0) {
|
|
160
|
+
throw new Error(`[PortalProvider] Auto-approve is disabled. Cannot perform signing requests without an event handler for the 'portal_signingRequested' event.`);
|
|
161
|
+
}
|
|
162
|
+
return new Promise((resolve) => {
|
|
163
|
+
// Remove already used listeners
|
|
164
|
+
this.removeEventListener('portal_signingApproved');
|
|
165
|
+
this.removeEventListener('portal_signingRejected');
|
|
166
|
+
const handleApproval = ({ method: approvedMethod, params: approvedParams }) => {
|
|
167
|
+
// Remove already used listeners
|
|
168
|
+
this.removeEventListener('portal_signingApproved');
|
|
169
|
+
this.removeEventListener('portal_signingRejected');
|
|
170
|
+
// First verify that this is the same signing request
|
|
171
|
+
if (method === approvedMethod &&
|
|
172
|
+
JSON.stringify(params) === JSON.stringify(approvedParams)) {
|
|
173
|
+
resolve(true);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const handleRejection = ({ method: rejectedMethod, params: rejectedParams }) => {
|
|
177
|
+
// Remove already used listeners
|
|
178
|
+
this.removeEventListener('portal_signingApproved');
|
|
179
|
+
this.removeEventListener('portal_signingRejected');
|
|
180
|
+
// First verify that this is the same signing request
|
|
181
|
+
if (method === rejectedMethod &&
|
|
182
|
+
JSON.stringify(params) === JSON.stringify(rejectedParams)) {
|
|
183
|
+
resolve(false);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
// If the signing has been approved, resolve to true
|
|
187
|
+
this.on('portal_signingApproved', handleApproval);
|
|
188
|
+
// If the signing request has been rejected, resolve to false
|
|
189
|
+
this.on('portal_signingRejected', handleRejection);
|
|
190
|
+
// Tell any listening clients that signing has been requested
|
|
191
|
+
this.emit('portal_signingRequested', {
|
|
192
|
+
method,
|
|
193
|
+
params,
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Sends the provided request payload along to the RPC HttpRequester
|
|
200
|
+
*
|
|
201
|
+
* @param args The arguments of the request being made
|
|
202
|
+
* @returns Promise<any>
|
|
203
|
+
*/
|
|
204
|
+
handleGatewayRequest({ method, params, }) {
|
|
205
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
206
|
+
// Pass request off to the gateway
|
|
207
|
+
const result = yield fetch(this.portal.getRpcUrl(), {
|
|
208
|
+
body: JSON.stringify({
|
|
209
|
+
jsonrpc: '2.0',
|
|
210
|
+
id: this.portal.chainId,
|
|
211
|
+
method,
|
|
212
|
+
params,
|
|
213
|
+
}),
|
|
214
|
+
method: 'POST',
|
|
215
|
+
});
|
|
216
|
+
return result.json();
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Sends the provided request payload along to the Signer
|
|
221
|
+
*
|
|
222
|
+
* @param args The arguments of the request being made
|
|
223
|
+
* @returns Promise<any>
|
|
224
|
+
*/
|
|
225
|
+
handleSigningRequest({ method, params, }) {
|
|
226
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
227
|
+
const isApproved = passiveSignerMethods.includes(method)
|
|
228
|
+
? true
|
|
229
|
+
: yield this.getApproval({ method, params });
|
|
230
|
+
if (!isApproved) {
|
|
231
|
+
console.info(`[PortalProvider] Request for signing method '${method}' could not be completed because it was not approved by the user.`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
switch (method) {
|
|
235
|
+
case 'eth_chainId':
|
|
236
|
+
return `0x${this.portal.chainId.toString(16)}`;
|
|
237
|
+
case 'eth_accounts':
|
|
238
|
+
case 'eth_requestAccounts':
|
|
239
|
+
return [this.portal.address];
|
|
240
|
+
case 'eth_sendTransaction':
|
|
241
|
+
case 'eth_sign':
|
|
242
|
+
case 'eth_signTransaction':
|
|
243
|
+
case 'eth_signTypedData_v3':
|
|
244
|
+
case 'eth_signTypedData_v4':
|
|
245
|
+
case 'personal_sign':
|
|
246
|
+
const result = yield this.portal.mpc.sign({
|
|
247
|
+
host: this.portal.mpcHost,
|
|
248
|
+
method,
|
|
249
|
+
mpcVersion: this.portal.mpcVersion,
|
|
250
|
+
params,
|
|
251
|
+
});
|
|
252
|
+
return result;
|
|
253
|
+
default:
|
|
254
|
+
throw new Error('[PortalProvider] Method "' + method + '" not supported');
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
exports.default = Provider;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class DefaultBackupStorage {
|
|
4
|
+
delete() {
|
|
5
|
+
throw new Error('[Portal] Storage method delete cannot be called directly. Please extend Storage.');
|
|
6
|
+
}
|
|
7
|
+
read() {
|
|
8
|
+
throw new Error('[Portal] Storage method read cannot be called directly. Please extend Storage.');
|
|
9
|
+
}
|
|
10
|
+
write(privateKey) {
|
|
11
|
+
throw new Error(`[Portal] Storage method write(${privateKey}) cannot be called directly. Please extend Storage.`);
|
|
12
|
+
}
|
|
13
|
+
validateOperations() {
|
|
14
|
+
throw new Error('[Portal] Storage method validateOperations cannot be called directly. Please extend Storage.');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.default = DefaultBackupStorage;
|