@portal-hq/web 2.0.1 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/index.js +254 -58
- package/lib/commonjs/mpc/errors/index.js +2 -2
- package/lib/commonjs/mpc/index.js +43 -79
- package/lib/commonjs/provider/index.js +57 -14
- package/lib/esm/index.js +254 -58
- package/lib/esm/mpc/errors/index.js +2 -2
- package/lib/esm/mpc/index.js +43 -79
- package/lib/esm/provider/index.js +57 -14
- package/package.json +4 -1
- package/src/index.ts +323 -67
- package/src/mpc/errors/index.ts +2 -2
- package/src/mpc/index.ts +54 -99
- package/src/provider/index.ts +66 -16
- package/types.d.ts +17 -27
|
@@ -25,9 +25,29 @@ const signerMethods = [
|
|
|
25
25
|
'eth_signTypedData_v3',
|
|
26
26
|
'eth_signTypedData_v4',
|
|
27
27
|
'personal_sign',
|
|
28
|
+
'sol_signAndConfirmTransaction',
|
|
29
|
+
'sol_signAndSendTransaction',
|
|
30
|
+
'sol_signMessage',
|
|
31
|
+
'sol_signTransaction',
|
|
28
32
|
];
|
|
29
33
|
class Provider {
|
|
30
34
|
constructor({ portal }) {
|
|
35
|
+
this.enforceEip155ChainId = (chainId) => {
|
|
36
|
+
if (!chainId) {
|
|
37
|
+
throw new Error('[PortalProvider] Chain ID is required for the operation');
|
|
38
|
+
}
|
|
39
|
+
if (!chainId.startsWith('eip155:')) {
|
|
40
|
+
throw new Error(`[PortalProvider] Chain ID must be prefixed with "eip155:" for the operation, got ${chainId}`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
this.enforceSolanaChainId = (chainId) => {
|
|
44
|
+
if (!chainId) {
|
|
45
|
+
throw new Error('[PortalProvider] Chain ID is required for the operation');
|
|
46
|
+
}
|
|
47
|
+
if (!chainId.startsWith('solana:')) {
|
|
48
|
+
throw new Error(`[PortalProvider] Chain ID must be prefixed with "solana:" for the operation, got ${chainId}`);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
31
51
|
this.buildParams = (method, txParams) => {
|
|
32
52
|
let params = txParams;
|
|
33
53
|
switch (method) {
|
|
@@ -35,6 +55,10 @@ class Provider {
|
|
|
35
55
|
case 'personal_sign':
|
|
36
56
|
case 'eth_signTypedData_v3':
|
|
37
57
|
case 'eth_signTypedData_v4':
|
|
58
|
+
case 'sol_signAndConfirmTransaction':
|
|
59
|
+
case 'sol_signAndSendTransaction':
|
|
60
|
+
case 'sol_signMessage':
|
|
61
|
+
case 'sol_signTransaction':
|
|
38
62
|
if (!Array.isArray(txParams)) {
|
|
39
63
|
params = [txParams];
|
|
40
64
|
}
|
|
@@ -112,9 +136,6 @@ class Provider {
|
|
|
112
136
|
*/
|
|
113
137
|
request({ chainId, method, params, }) {
|
|
114
138
|
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
-
if (method === 'eth_chainId') {
|
|
116
|
-
return chainId ? parseInt(chainId.split(':')[1]) : this.portal.chainId;
|
|
117
|
-
}
|
|
118
139
|
const isSignerMethod = signerMethods.includes(method);
|
|
119
140
|
if (!isSignerMethod && !method.startsWith('wallet_')) {
|
|
120
141
|
// Send to Gateway for RPC calls
|
|
@@ -225,16 +246,21 @@ class Provider {
|
|
|
225
246
|
*/
|
|
226
247
|
handleGatewayRequest({ chainId, method, params, }) {
|
|
227
248
|
return __awaiter(this, void 0, void 0, function* () {
|
|
228
|
-
//
|
|
229
|
-
const
|
|
249
|
+
// Prepare the request body
|
|
250
|
+
const requestBody = {
|
|
230
251
|
body: JSON.stringify({
|
|
231
252
|
jsonrpc: '2.0',
|
|
232
|
-
id:
|
|
253
|
+
id: '0',
|
|
233
254
|
method,
|
|
234
255
|
params,
|
|
235
256
|
}),
|
|
236
257
|
method: 'POST',
|
|
237
|
-
|
|
258
|
+
headers: {
|
|
259
|
+
'Content-Type': 'application/json',
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
// Pass request off to the gateway
|
|
263
|
+
const result = yield fetch(this.portal.getRpcUrl(chainId), requestBody);
|
|
238
264
|
return result.json();
|
|
239
265
|
});
|
|
240
266
|
}
|
|
@@ -254,24 +280,41 @@ class Provider {
|
|
|
254
280
|
return;
|
|
255
281
|
}
|
|
256
282
|
switch (method) {
|
|
257
|
-
case 'eth_chainId':
|
|
258
|
-
|
|
283
|
+
case 'eth_chainId': {
|
|
284
|
+
this.enforceEip155ChainId(chainId);
|
|
285
|
+
const chainReferenceId = parseInt(chainId.split(':')[1]);
|
|
286
|
+
return `0x${chainReferenceId.toString(16)}`;
|
|
287
|
+
}
|
|
259
288
|
case 'eth_accounts':
|
|
260
|
-
case 'eth_requestAccounts':
|
|
289
|
+
case 'eth_requestAccounts': {
|
|
290
|
+
this.enforceEip155ChainId(chainId);
|
|
261
291
|
return [this.portal.address];
|
|
292
|
+
}
|
|
262
293
|
case 'eth_sendTransaction':
|
|
263
294
|
case 'eth_sign':
|
|
264
295
|
case 'eth_signTransaction':
|
|
265
296
|
case 'eth_signTypedData_v3':
|
|
266
297
|
case 'eth_signTypedData_v4':
|
|
267
298
|
case 'personal_sign': {
|
|
299
|
+
this.enforceEip155ChainId(chainId);
|
|
300
|
+
const result = yield this.portal.mpc.sign({
|
|
301
|
+
chainId: chainId,
|
|
302
|
+
method,
|
|
303
|
+
params: this.buildParams(method, params),
|
|
304
|
+
rpcUrl: this.portal.getRpcUrl(chainId),
|
|
305
|
+
});
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
case 'sol_signAndConfirmTransaction':
|
|
309
|
+
case 'sol_signAndSendTransaction':
|
|
310
|
+
case 'sol_signMessage':
|
|
311
|
+
case 'sol_signTransaction': {
|
|
312
|
+
this.enforceSolanaChainId(chainId);
|
|
268
313
|
const result = yield this.portal.mpc.sign({
|
|
269
|
-
chainId: chainId
|
|
270
|
-
? chainId.split(':')[1]
|
|
271
|
-
: this.portal.chainId.toString(),
|
|
314
|
+
chainId: chainId,
|
|
272
315
|
method,
|
|
273
316
|
params: this.buildParams(method, params),
|
|
274
|
-
rpcUrl: this.portal.getRpcUrl(),
|
|
317
|
+
rpcUrl: this.portal.getRpcUrl(chainId),
|
|
275
318
|
});
|
|
276
319
|
return result;
|
|
277
320
|
}
|
package/lib/esm/index.js
CHANGED
|
@@ -7,25 +7,38 @@ 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 { Connection, PublicKey, Transaction as SolanaTransaction, SystemProgram, } from '@solana/web3.js';
|
|
10
11
|
import Mpc from './mpc';
|
|
11
12
|
import Provider from './provider';
|
|
12
13
|
class Portal {
|
|
13
14
|
constructor({
|
|
14
15
|
// Required
|
|
15
|
-
|
|
16
|
+
rpcConfig,
|
|
16
17
|
// Optional
|
|
17
|
-
apiKey, authToken, authUrl, autoApprove = false,
|
|
18
|
+
apiKey, authToken, authUrl, autoApprove = false, gdrive, passkey, host = 'web.portalhq.io', mpcVersion = 'v6', mpcHost = 'mpc-client.portalhq.io', featureFlags = {
|
|
18
19
|
optimized: false,
|
|
19
20
|
}, }) {
|
|
20
21
|
this.ready = false;
|
|
21
22
|
this.errorCallbacks = [];
|
|
22
23
|
this.readyCallbacks = [];
|
|
24
|
+
this.sendEth = ({ chainId, to, value, }) => __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
return this.provider.request({
|
|
26
|
+
chainId,
|
|
27
|
+
method: 'eth_sendTransaction',
|
|
28
|
+
params: [
|
|
29
|
+
{
|
|
30
|
+
from: this.address,
|
|
31
|
+
to,
|
|
32
|
+
value,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
});
|
|
23
37
|
this.apiKey = apiKey;
|
|
24
38
|
this.authToken = authToken;
|
|
25
39
|
this.authUrl = authUrl;
|
|
26
40
|
this.autoApprove = autoApprove;
|
|
27
|
-
this.
|
|
28
|
-
this.gatewayConfig = gatewayConfig;
|
|
41
|
+
this.rpcConfig = rpcConfig;
|
|
29
42
|
this.host = host;
|
|
30
43
|
this.mpcHost = mpcHost;
|
|
31
44
|
this.mpcVersion = mpcVersion;
|
|
@@ -138,7 +151,7 @@ class Portal {
|
|
|
138
151
|
return this.recoverWallet(cipherText, backupMethod, backupConfigs, progress);
|
|
139
152
|
});
|
|
140
153
|
}
|
|
141
|
-
|
|
154
|
+
eject(clientBackupCipherText, backupMethod, backupConfigs, orgBackupShare) {
|
|
142
155
|
return __awaiter(this, void 0, void 0, function* () {
|
|
143
156
|
if (clientBackupCipherText === '') {
|
|
144
157
|
throw new Error('clientBackupCipherText cannot be empty string.');
|
|
@@ -146,7 +159,7 @@ class Portal {
|
|
|
146
159
|
if (orgBackupShare === '') {
|
|
147
160
|
throw new Error('orgBackupShare cannot be empty string.');
|
|
148
161
|
}
|
|
149
|
-
const
|
|
162
|
+
const { SECP256K1, ED25519 } = yield this.mpc.eject({
|
|
150
163
|
cipherText: clientBackupCipherText,
|
|
151
164
|
backupMethod,
|
|
152
165
|
backupConfigs,
|
|
@@ -155,14 +168,73 @@ class Portal {
|
|
|
155
168
|
mpcVersion: this.mpcVersion,
|
|
156
169
|
featureFlags: this.featureFlags,
|
|
157
170
|
});
|
|
158
|
-
return
|
|
171
|
+
return {
|
|
172
|
+
SECP256K1,
|
|
173
|
+
ED25519,
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
getEip155Address() {
|
|
178
|
+
var _a, _b, _c, _d;
|
|
179
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
180
|
+
const client = yield ((_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getClient());
|
|
181
|
+
const eip155Address = ((_d = (_c = (_b = client === null || client === void 0 ? void 0 : client.metadata) === null || _b === void 0 ? void 0 : _b.namespaces) === null || _c === void 0 ? void 0 : _c.eip155) === null || _d === void 0 ? void 0 : _d.address) || '';
|
|
182
|
+
return eip155Address;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
getSolanaAddress() {
|
|
186
|
+
var _a, _b, _c, _d;
|
|
187
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
188
|
+
const client = yield ((_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getClient());
|
|
189
|
+
const solAddress = ((_d = (_c = (_b = client === null || client === void 0 ? void 0 : client.metadata) === null || _b === void 0 ? void 0 : _b.namespaces) === null || _c === void 0 ? void 0 : _c.solana) === null || _d === void 0 ? void 0 : _d.address) || '';
|
|
190
|
+
return solAddress;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
doesWalletExist(chainId) {
|
|
194
|
+
var _a, _b, _c, _d, _e;
|
|
195
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
196
|
+
const client = yield ((_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getClient());
|
|
197
|
+
if (chainId) {
|
|
198
|
+
const namespace = ((_b = chainId === null || chainId === void 0 ? void 0 : chainId.split(':')) === null || _b === void 0 ? void 0 : _b[0]) || '';
|
|
199
|
+
const namespaceInfo = (_d = (_c = client === null || client === void 0 ? void 0 : client.metadata) === null || _c === void 0 ? void 0 : _c.namespaces) === null || _d === void 0 ? void 0 : _d[namespace];
|
|
200
|
+
return !!namespaceInfo;
|
|
201
|
+
}
|
|
202
|
+
return ((_e = client === null || client === void 0 ? void 0 : client.wallets) === null || _e === void 0 ? void 0 : _e.length) > 0;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
isWalletOnDevice(chainId) {
|
|
206
|
+
var _a, _b, _c, _d, _e, _f;
|
|
207
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
208
|
+
const client = yield ((_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getClient());
|
|
209
|
+
const sharesOnDevice = yield ((_b = this.mpc) === null || _b === void 0 ? void 0 : _b.checkSharesOnDevice());
|
|
210
|
+
if (chainId) {
|
|
211
|
+
const namespace = ((_c = chainId === null || chainId === void 0 ? void 0 : chainId.split(':')) === null || _c === void 0 ? void 0 : _c[0]) || '';
|
|
212
|
+
const curve = ((_f = (_e = (_d = client === null || client === void 0 ? void 0 : client.metadata) === null || _d === void 0 ? void 0 : _d.namespaces) === null || _e === void 0 ? void 0 : _e[namespace]) === null || _f === void 0 ? void 0 : _f.curve) || '';
|
|
213
|
+
return sharesOnDevice[curve] || false;
|
|
214
|
+
}
|
|
215
|
+
return sharesOnDevice.ED25519 && sharesOnDevice.SECP256K1;
|
|
159
216
|
});
|
|
160
217
|
}
|
|
161
218
|
/****************************
|
|
162
219
|
* Provider Methods
|
|
163
220
|
****************************/
|
|
164
|
-
|
|
221
|
+
request(request) {
|
|
165
222
|
return __awaiter(this, void 0, void 0, function* () {
|
|
223
|
+
return this.provider.request(request);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Estimates the amount of gas that will be required to execute an Ethereum transaction.
|
|
228
|
+
*
|
|
229
|
+
* @deprecated This method is deprecated. Use `portal.request` with method 'eth_estimateGas' instead.
|
|
230
|
+
*
|
|
231
|
+
* @param {string} chainId - The chain ID of the Ethereum network.
|
|
232
|
+
* @param {EthereumTransaction} transaction - The transaction object containing the necessary transaction details.
|
|
233
|
+
* @returns {Promise<any>} A Promise that resolves to the gas estimate.
|
|
234
|
+
*/
|
|
235
|
+
ethEstimateGas(chainId, transaction) {
|
|
236
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
237
|
+
console.warn('"portal.ethEstimateGas" is deprecated. Use "portal.request" instead.');
|
|
166
238
|
return this.provider.request({
|
|
167
239
|
chainId,
|
|
168
240
|
method: 'eth_estimateGas',
|
|
@@ -170,8 +242,17 @@ class Portal {
|
|
|
170
242
|
});
|
|
171
243
|
});
|
|
172
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Gets the current gas price for the Ethereum network.
|
|
247
|
+
*
|
|
248
|
+
* @deprecated This method is deprecated. Use `portal.request` with method 'eth_gasPrice' instead.
|
|
249
|
+
*
|
|
250
|
+
* @param {string} chainId - The chain ID of the Ethereum network.
|
|
251
|
+
* @returns {Promise<string>} A Promise that resolves to the current gas price.
|
|
252
|
+
*/
|
|
173
253
|
ethGasPrice(chainId) {
|
|
174
254
|
return __awaiter(this, void 0, void 0, function* () {
|
|
255
|
+
console.warn('"portal.ethGasPrice" is deprecated. Use "portal.request" instead.');
|
|
175
256
|
return this.provider.request({
|
|
176
257
|
chainId,
|
|
177
258
|
method: 'eth_gasPrice',
|
|
@@ -179,8 +260,17 @@ class Portal {
|
|
|
179
260
|
});
|
|
180
261
|
});
|
|
181
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Gets the balance of the current Ethereum address.
|
|
265
|
+
*
|
|
266
|
+
* @deprecated This method is deprecated. Use `portal.request` with method 'eth_getBalance' instead.
|
|
267
|
+
*
|
|
268
|
+
* @param {string} chainId - The chain ID of the Ethereum network.
|
|
269
|
+
* @returns {Promise<string>} A Promise that resolves to the current balance.
|
|
270
|
+
*/
|
|
182
271
|
ethGetBalance(chainId) {
|
|
183
272
|
return __awaiter(this, void 0, void 0, function* () {
|
|
273
|
+
console.warn('"portal.ethGetBalance" is deprecated. Use "portal.request" instead.');
|
|
184
274
|
return this.provider.request({
|
|
185
275
|
chainId,
|
|
186
276
|
method: 'eth_getBalance',
|
|
@@ -188,8 +278,18 @@ class Portal {
|
|
|
188
278
|
});
|
|
189
279
|
});
|
|
190
280
|
}
|
|
191
|
-
|
|
281
|
+
/**
|
|
282
|
+
* Sends an Ethereum transaction.
|
|
283
|
+
*
|
|
284
|
+
* @deprecated This method is deprecated. Use `portal.request` with method 'eth_getTransactionCount' instead.
|
|
285
|
+
*
|
|
286
|
+
* @param {string} chainId - The chain ID of the Ethereum network.
|
|
287
|
+
* @param {EthereumTransaction} transaction - The transaction object containing the necessary transaction details.
|
|
288
|
+
* @returns {Promise<string>} A Promise that resolves to the transaction hash.
|
|
289
|
+
*/
|
|
290
|
+
ethSendTransaction(chainId, transaction) {
|
|
192
291
|
return __awaiter(this, void 0, void 0, function* () {
|
|
292
|
+
console.warn('"portal.ethSendTransaction" is deprecated. Use "portal.request" instead.');
|
|
193
293
|
return this.provider.request({
|
|
194
294
|
chainId,
|
|
195
295
|
method: 'eth_sendTransaction',
|
|
@@ -197,17 +297,18 @@ class Portal {
|
|
|
197
297
|
});
|
|
198
298
|
});
|
|
199
299
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
ethSignTransaction(
|
|
300
|
+
/**
|
|
301
|
+
* Signs an Ethereum transaction.
|
|
302
|
+
*
|
|
303
|
+
* @deprecated This method is deprecated. Use `portal.request` with method 'eth_signTransaction' instead.
|
|
304
|
+
*
|
|
305
|
+
* @param {string} chainId - The chain ID of the Ethereum network.
|
|
306
|
+
* @param {EthereumTransaction} transaction - The transaction object containing the necessary transaction details.
|
|
307
|
+
* @returns {Promise<string>} A Promise that resolves to the signed transaction.
|
|
308
|
+
*/
|
|
309
|
+
ethSignTransaction(chainId, transaction) {
|
|
210
310
|
return __awaiter(this, void 0, void 0, function* () {
|
|
311
|
+
console.warn('"portal.ethSignTransaction" is deprecated. Use "portal.request" instead.');
|
|
211
312
|
return this.provider.request({
|
|
212
313
|
chainId,
|
|
213
314
|
method: 'eth_signTransaction',
|
|
@@ -215,8 +316,18 @@ class Portal {
|
|
|
215
316
|
});
|
|
216
317
|
});
|
|
217
318
|
}
|
|
218
|
-
|
|
319
|
+
/**
|
|
320
|
+
* Signs an Ethereum message using EIP-712.
|
|
321
|
+
*
|
|
322
|
+
* @deprecated This method is deprecated. Use `portal.request` with method 'eth_signTypedData' instead.
|
|
323
|
+
*
|
|
324
|
+
* @param {string} chainId - The chain ID of the Ethereum network.
|
|
325
|
+
* @param {TypedData} data - The typed data object to sign.
|
|
326
|
+
* @returns {Promise<string>} A Promise that resolves to the signed message.
|
|
327
|
+
*/
|
|
328
|
+
ethSignTypedData(chainId, data) {
|
|
219
329
|
return __awaiter(this, void 0, void 0, function* () {
|
|
330
|
+
console.warn('"portal.ethSignTypedData" is deprecated. Use "portal.request" instead.');
|
|
220
331
|
return this.provider.request({
|
|
221
332
|
chainId,
|
|
222
333
|
method: 'eth_signTypedData',
|
|
@@ -224,8 +335,18 @@ class Portal {
|
|
|
224
335
|
});
|
|
225
336
|
});
|
|
226
337
|
}
|
|
227
|
-
|
|
338
|
+
/**
|
|
339
|
+
* Signs an Ethereum message using EIP-712 (legacy).
|
|
340
|
+
*
|
|
341
|
+
* @deprecated This method is deprecated. Use `portal.request` with method 'eth_signTypedData_v3' instead.
|
|
342
|
+
*
|
|
343
|
+
* @param {string} chainId - The chain ID of the Ethereum network.
|
|
344
|
+
* @param {TypedData} data - The typed data object to sign.
|
|
345
|
+
* @returns {Promise<string>} A Promise that resolves to the signed message.
|
|
346
|
+
*/
|
|
347
|
+
ethSignTypedDataV3(chainId, data) {
|
|
228
348
|
return __awaiter(this, void 0, void 0, function* () {
|
|
349
|
+
console.warn('"portal.ethSignTypedDataV3" is deprecated. Use "portal.request" instead.');
|
|
229
350
|
return this.provider.request({
|
|
230
351
|
chainId,
|
|
231
352
|
method: 'eth_signTypedData_v3',
|
|
@@ -233,8 +354,18 @@ class Portal {
|
|
|
233
354
|
});
|
|
234
355
|
});
|
|
235
356
|
}
|
|
236
|
-
|
|
357
|
+
/**
|
|
358
|
+
* Signs an Ethereum message using EIP-712 (v4).
|
|
359
|
+
*
|
|
360
|
+
* @deprecated This method is deprecated. Use `portal.request` with method 'eth_signTypedData_v4' instead.
|
|
361
|
+
*
|
|
362
|
+
* @param {string} chainId - The chain ID of the Ethereum network.
|
|
363
|
+
* @param {TypedData} data - The typed data object to sign.
|
|
364
|
+
* @returns {Promise<string>} A Promise that resolves to the signed message.
|
|
365
|
+
*/
|
|
366
|
+
ethSignTypedDataV4(chainId, data) {
|
|
237
367
|
return __awaiter(this, void 0, void 0, function* () {
|
|
368
|
+
console.warn('"portal.ethSignTypedDataV4" is deprecated. Use "portal.request" instead.');
|
|
238
369
|
return this.provider.request({
|
|
239
370
|
chainId,
|
|
240
371
|
method: 'eth_signTypedData_v4',
|
|
@@ -242,8 +373,9 @@ class Portal {
|
|
|
242
373
|
});
|
|
243
374
|
});
|
|
244
375
|
}
|
|
245
|
-
personalSign(
|
|
376
|
+
personalSign(chainId, message) {
|
|
246
377
|
return __awaiter(this, void 0, void 0, function* () {
|
|
378
|
+
console.warn('"portal.personalSign" is deprecated. Use "portal.request" instead.');
|
|
247
379
|
return (yield this.provider.request({
|
|
248
380
|
chainId,
|
|
249
381
|
method: 'personal_sign',
|
|
@@ -251,13 +383,89 @@ class Portal {
|
|
|
251
383
|
}));
|
|
252
384
|
});
|
|
253
385
|
}
|
|
386
|
+
sendSol({ chainId, to, lamports, }) {
|
|
387
|
+
var _a;
|
|
388
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
389
|
+
// Ensure the chainId is solana.
|
|
390
|
+
if (!chainId.startsWith('solana:')) {
|
|
391
|
+
throw new Error('[Portal] Invalid chainId. Please provide a chainId that starts with "solana:"');
|
|
392
|
+
}
|
|
393
|
+
// Ensure the to address is a valid Solana address.
|
|
394
|
+
if (!to || typeof to !== 'string' || to.length !== 44) {
|
|
395
|
+
throw new Error('[Portal] Invalid "to" Solana address provided, must be 44 characters');
|
|
396
|
+
}
|
|
397
|
+
// Validate the lamports.
|
|
398
|
+
if (typeof lamports !== 'number' || lamports <= 0) {
|
|
399
|
+
throw new Error('[Portal] Invalid lamports amount, must be a positive number greater than 0');
|
|
400
|
+
}
|
|
401
|
+
// Get the most recent blockhash.
|
|
402
|
+
const blockhashResponse = yield this.provider.request({
|
|
403
|
+
chainId: chainId,
|
|
404
|
+
method: 'getLatestBlockhash',
|
|
405
|
+
params: [],
|
|
406
|
+
});
|
|
407
|
+
const blockhash = ((_a = blockhashResponse === null || blockhashResponse === void 0 ? void 0 : blockhashResponse.value) === null || _a === void 0 ? void 0 : _a.blockhash) || '';
|
|
408
|
+
// If we didn't get a blockhash, throw an error.
|
|
409
|
+
if (!blockhash) {
|
|
410
|
+
throw new Error('[Portal] Failed to get most recent blockhash');
|
|
411
|
+
}
|
|
412
|
+
// Get the Solana address from the client, validate the addresses.
|
|
413
|
+
const solanaAddress = yield this.getSolanaAddress();
|
|
414
|
+
if (!solanaAddress) {
|
|
415
|
+
throw new Error('[Portal] Failed to get Solana address');
|
|
416
|
+
}
|
|
417
|
+
// Get the Solana gateway URL.
|
|
418
|
+
const gatewayUrl = this.getRpcUrl(chainId);
|
|
419
|
+
if (!gatewayUrl) {
|
|
420
|
+
throw new Error('[Portal] No RPC endpoint configured for chainId');
|
|
421
|
+
}
|
|
422
|
+
// Create a new connection to the Solana network.
|
|
423
|
+
new Connection(gatewayUrl, 'confirmed');
|
|
424
|
+
// The sender's public key.
|
|
425
|
+
const fromPublicKey = new PublicKey(solanaAddress);
|
|
426
|
+
// The recipient's public key.
|
|
427
|
+
const toPublicKey = new PublicKey(to);
|
|
428
|
+
// Create a new transaction.
|
|
429
|
+
const transaction = new SolanaTransaction().add(SystemProgram.transfer({
|
|
430
|
+
fromPubkey: fromPublicKey,
|
|
431
|
+
toPubkey: toPublicKey,
|
|
432
|
+
lamports,
|
|
433
|
+
}));
|
|
434
|
+
transaction.recentBlockhash = blockhash;
|
|
435
|
+
transaction.feePayer = fromPublicKey;
|
|
436
|
+
const compiledMessage = transaction.compileMessage();
|
|
437
|
+
// Build the transaction and its message.
|
|
438
|
+
const message = {
|
|
439
|
+
accountKeys: compiledMessage.accountKeys.map((key) => key.toBase58()),
|
|
440
|
+
header: compiledMessage.header,
|
|
441
|
+
instructions: compiledMessage.instructions,
|
|
442
|
+
recentBlockhash: blockhash,
|
|
443
|
+
};
|
|
444
|
+
const formattedTransaction = {
|
|
445
|
+
signatures: null,
|
|
446
|
+
message,
|
|
447
|
+
};
|
|
448
|
+
// Attempt to sign and send the transaction
|
|
449
|
+
const transactionResult = yield this.provider.request({
|
|
450
|
+
chainId: chainId,
|
|
451
|
+
method: 'sol_signAndSendTransaction',
|
|
452
|
+
params: [formattedTransaction],
|
|
453
|
+
});
|
|
454
|
+
// If we didn't get a transactionResult, throw an error.
|
|
455
|
+
if (!transactionResult) {
|
|
456
|
+
throw new Error('[Portal] Failed to send Solana transaction');
|
|
457
|
+
}
|
|
458
|
+
// Return the transactionResult.
|
|
459
|
+
return transactionResult;
|
|
460
|
+
});
|
|
461
|
+
}
|
|
254
462
|
/*******************************
|
|
255
463
|
* API Methods
|
|
256
464
|
*******************************/
|
|
257
|
-
getBalances() {
|
|
465
|
+
getBalances(chainId) {
|
|
258
466
|
var _a;
|
|
259
467
|
return __awaiter(this, void 0, void 0, function* () {
|
|
260
|
-
return yield ((_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getBalances());
|
|
468
|
+
return yield ((_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getBalances(chainId));
|
|
261
469
|
});
|
|
262
470
|
}
|
|
263
471
|
getClient() {
|
|
@@ -266,34 +474,22 @@ class Portal {
|
|
|
266
474
|
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getClient();
|
|
267
475
|
});
|
|
268
476
|
}
|
|
269
|
-
getNFTs() {
|
|
270
|
-
var _a;
|
|
271
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
272
|
-
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getNFTs();
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
getBackupShareMetadata() {
|
|
276
|
-
var _a;
|
|
277
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
278
|
-
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getBackupShareMetadata();
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
getSigningShareMetadata() {
|
|
477
|
+
getNFTs(chainId) {
|
|
282
478
|
var _a;
|
|
283
479
|
return __awaiter(this, void 0, void 0, function* () {
|
|
284
|
-
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.
|
|
480
|
+
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getNFTs(chainId);
|
|
285
481
|
});
|
|
286
482
|
}
|
|
287
|
-
getTransactions(limit, offset, order
|
|
483
|
+
getTransactions(chainId, limit, offset, order) {
|
|
288
484
|
var _a;
|
|
289
485
|
return __awaiter(this, void 0, void 0, function* () {
|
|
290
|
-
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getTransactions(limit, offset, order
|
|
486
|
+
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.getTransactions(chainId, limit, offset, order);
|
|
291
487
|
});
|
|
292
488
|
}
|
|
293
|
-
simulateTransaction(transaction) {
|
|
489
|
+
simulateTransaction(chainId, transaction) {
|
|
294
490
|
var _a;
|
|
295
491
|
return __awaiter(this, void 0, void 0, function* () {
|
|
296
|
-
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.simulateTransaction(transaction);
|
|
492
|
+
return (_a = this.mpc) === null || _a === void 0 ? void 0 : _a.simulateTransaction(transaction, chainId);
|
|
297
493
|
});
|
|
298
494
|
}
|
|
299
495
|
/*******************************
|
|
@@ -323,24 +519,24 @@ class Portal {
|
|
|
323
519
|
/****************************
|
|
324
520
|
* RPC Methods
|
|
325
521
|
****************************/
|
|
326
|
-
getRpcUrl() {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
522
|
+
getRpcUrl(chainId) {
|
|
523
|
+
// Ensure a chainId is provided.
|
|
524
|
+
if (!chainId) {
|
|
525
|
+
throw new Error('[Portal] No chainId provided. Please provide a chainId to get the RPC endpoint');
|
|
330
526
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
throw new Error(`[PortalProvider] No RPC endpoint configured for chainId: ${this.chainId}`);
|
|
527
|
+
// Ensure the chainId is configured in the rpcConfig.
|
|
528
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
529
|
+
if (!this.rpcConfig.hasOwnProperty(chainId)) {
|
|
530
|
+
throw new Error(`[Portal] No RPC endpoint configured for chainId: ${chainId}`);
|
|
336
531
|
}
|
|
337
|
-
//
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
532
|
+
// Derive the RPC endpoint from the rpcConfig.
|
|
533
|
+
const gatewayUrl = this.rpcConfig[chainId];
|
|
534
|
+
// If the RPC endpoint is a string, return it as-is.
|
|
535
|
+
if (typeof gatewayUrl === 'string') {
|
|
536
|
+
return gatewayUrl;
|
|
341
537
|
}
|
|
342
|
-
//
|
|
343
|
-
throw new Error(`[
|
|
538
|
+
// Otherwise, something is wrong with the configuration.
|
|
539
|
+
throw new Error(`[Portal] Could not find a valid rpcConfig entry for chainId: ${chainId}`);
|
|
344
540
|
}
|
|
345
541
|
/**************************
|
|
346
542
|
* RPC Encoding Methods
|
|
@@ -59,7 +59,7 @@ export class MpcError extends Error {
|
|
|
59
59
|
// Init the actual error
|
|
60
60
|
super(error.message(context));
|
|
61
61
|
// Custom error context
|
|
62
|
-
this.code = error.code;
|
|
62
|
+
this.code = (error === null || error === void 0 ? void 0 : error.code) || 999;
|
|
63
63
|
if (context) {
|
|
64
64
|
this.context = context;
|
|
65
65
|
}
|
|
@@ -136,7 +136,7 @@ export const PortalErrorCodeTypes = {
|
|
|
136
136
|
export class PortalMpcError extends Error {
|
|
137
137
|
constructor(error) {
|
|
138
138
|
super(error.message);
|
|
139
|
-
this.code = error.code;
|
|
139
|
+
this.code = (error === null || error === void 0 ? void 0 : error.code) || 999;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
export default MpcError;
|