@portal-hq/web 3.2.3 → 3.3.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 +1 -1
- package/lib/commonjs/index.js +147 -19
- package/lib/commonjs/index.test.js +548 -0
- package/lib/commonjs/mpc/errors/index.js +1 -1
- package/lib/commonjs/mpc/index.js +145 -2
- package/lib/commonjs/mpc/index.test.js +1414 -0
- package/lib/commonjs/provider/index.js +172 -39
- package/lib/commonjs/provider/index.test.js +1222 -0
- package/lib/esm/index.js +122 -18
- package/lib/esm/index.test.js +520 -0
- package/lib/esm/mpc/errors/index.js +1 -1
- package/lib/esm/mpc/index.js +145 -2
- package/lib/esm/mpc/index.test.js +1409 -0
- package/lib/esm/provider/index.js +171 -39
- package/lib/esm/provider/index.test.js +1217 -0
- package/package.json +5 -5
- package/src/__mocks/constants.ts +771 -0
- package/src/__mocks/portal/mpc.ts +27 -0
- package/src/__mocks/portal/portal.ts +14 -0
- package/src/__mocks/portal/provider.ts +7 -0
- package/src/index.test.ts +820 -0
- package/src/index.ts +183 -44
- package/src/mpc/errors/index.ts +1 -1
- package/src/mpc/index.test.ts +1716 -0
- package/src/mpc/index.ts +182 -2
- package/src/provider/index.test.ts +1570 -0
- package/src/provider/index.ts +184 -39
- package/types.d.ts +298 -33
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @jest-environment jsdom
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
22
|
+
if (mod && mod.__esModule) return mod;
|
|
23
|
+
var result = {};
|
|
24
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
25
|
+
__setModuleDefault(result, mod);
|
|
26
|
+
return result;
|
|
27
|
+
};
|
|
28
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
29
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
30
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
31
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
32
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
33
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
34
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
38
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
39
|
+
};
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
const _1 = __importStar(require("."));
|
|
42
|
+
const constants_1 = require("./__mocks/constants");
|
|
43
|
+
const mpc_1 = __importDefault(require("./__mocks/portal/mpc"));
|
|
44
|
+
const provider_1 = __importDefault(require("./__mocks/portal/provider"));
|
|
45
|
+
/**
|
|
46
|
+
* context -
|
|
47
|
+
* https://github.com/jestjs/jest/issues/4422
|
|
48
|
+
* https://github.com/anza-xyz/solana-pay/issues/106
|
|
49
|
+
* */
|
|
50
|
+
const originalUint8ArrayHasInstance = Uint8Array[Symbol.hasInstance];
|
|
51
|
+
beforeAll(() => {
|
|
52
|
+
Object.defineProperty(Uint8Array, Symbol.hasInstance, {
|
|
53
|
+
value(potentialInstance) {
|
|
54
|
+
return (originalUint8ArrayHasInstance.call(this, potentialInstance) ||
|
|
55
|
+
Buffer.isBuffer(potentialInstance));
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
afterAll(() => {
|
|
60
|
+
Object.defineProperty(Uint8Array, Symbol.hasInstance, originalUint8ArrayHasInstance);
|
|
61
|
+
});
|
|
62
|
+
describe('Portal', () => {
|
|
63
|
+
let portal;
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
jest.clearAllMocks();
|
|
66
|
+
portal = new _1.default({
|
|
67
|
+
rpcConfig: Object.assign(Object.assign({}, constants_1.mockRpcConfig), {
|
|
68
|
+
// for testing -
|
|
69
|
+
// @ts-ignore-next-line
|
|
70
|
+
'incorrect-config': { test: 'test' } }),
|
|
71
|
+
});
|
|
72
|
+
portal.mpc = mpc_1.default;
|
|
73
|
+
portal.provider = provider_1.default;
|
|
74
|
+
});
|
|
75
|
+
describe('clearLocalWallet', () => {
|
|
76
|
+
it('should call mpc.clearLocalWallet', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
77
|
+
yield portal.clearLocalWallet();
|
|
78
|
+
expect(portal.mpc.clearLocalWallet).toHaveBeenCalledTimes(1);
|
|
79
|
+
}));
|
|
80
|
+
});
|
|
81
|
+
describe('createWallet', () => {
|
|
82
|
+
it('should successfully generate a wallet and call mpc.generate correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
const mockProgressFn = jest.fn();
|
|
84
|
+
const res = yield portal.createWallet(mockProgressFn);
|
|
85
|
+
expect(res).toBe(constants_1.mockAddress);
|
|
86
|
+
expect(portal.mpc.generate).toHaveBeenCalledTimes(1);
|
|
87
|
+
expect(portal.mpc.generate).toHaveBeenCalledWith({
|
|
88
|
+
host: 'web.portalhq.io',
|
|
89
|
+
mpcVersion: 'v6',
|
|
90
|
+
featureFlags: {},
|
|
91
|
+
}, mockProgressFn);
|
|
92
|
+
}));
|
|
93
|
+
it('should successfully generate a wallet and call mpc.generate correctly with custom constructor args', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
94
|
+
portal = new _1.default({
|
|
95
|
+
rpcConfig: constants_1.mockRpcConfig,
|
|
96
|
+
featureFlags: { isMultiBackupEnabled: true },
|
|
97
|
+
host: 'test-host',
|
|
98
|
+
});
|
|
99
|
+
portal.mpc = mpc_1.default;
|
|
100
|
+
portal.provider = provider_1.default;
|
|
101
|
+
const mockProgressFn = jest.fn();
|
|
102
|
+
const res = yield portal.createWallet(mockProgressFn);
|
|
103
|
+
expect(res).toBe(constants_1.mockAddress);
|
|
104
|
+
expect(portal.mpc.generate).toHaveBeenCalledTimes(1);
|
|
105
|
+
expect(portal.mpc.generate).toHaveBeenCalledWith({
|
|
106
|
+
host: 'test-host',
|
|
107
|
+
mpcVersion: 'v6',
|
|
108
|
+
featureFlags: { isMultiBackupEnabled: true },
|
|
109
|
+
}, mockProgressFn);
|
|
110
|
+
}));
|
|
111
|
+
});
|
|
112
|
+
describe('backupWallet', () => {
|
|
113
|
+
it('should successfully backup a wallet and call mpc.backup correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
114
|
+
const mockProgressFn = jest.fn();
|
|
115
|
+
const res = yield portal.backupWallet(_1.BackupMethods.gdrive, mockProgressFn, constants_1.mockBackupConfig);
|
|
116
|
+
expect(res).toBe(constants_1.mockMpcBackupResponse);
|
|
117
|
+
expect(portal.mpc.backup).toHaveBeenCalledTimes(1);
|
|
118
|
+
expect(portal.mpc.backup).toHaveBeenCalledWith({
|
|
119
|
+
backupMethod: _1.BackupMethods.gdrive,
|
|
120
|
+
backupConfigs: constants_1.mockBackupConfig,
|
|
121
|
+
host: 'web.portalhq.io',
|
|
122
|
+
mpcVersion: 'v6',
|
|
123
|
+
featureFlags: {},
|
|
124
|
+
}, mockProgressFn);
|
|
125
|
+
}));
|
|
126
|
+
it('should successfully backup a wallet and call mpc.backup correctly with custom constructor args', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
127
|
+
portal = new _1.default({
|
|
128
|
+
rpcConfig: constants_1.mockRpcConfig,
|
|
129
|
+
featureFlags: { isMultiBackupEnabled: true },
|
|
130
|
+
host: 'test-host',
|
|
131
|
+
});
|
|
132
|
+
portal.mpc = mpc_1.default;
|
|
133
|
+
portal.provider = provider_1.default;
|
|
134
|
+
const mockProgressFn = jest.fn();
|
|
135
|
+
const res = yield portal.backupWallet(_1.BackupMethods.passkey, mockProgressFn, constants_1.mockBackupConfig);
|
|
136
|
+
expect(res).toBe(constants_1.mockMpcBackupResponse);
|
|
137
|
+
expect(portal.mpc.backup).toHaveBeenCalledTimes(1);
|
|
138
|
+
expect(portal.mpc.backup).toHaveBeenCalledWith({
|
|
139
|
+
backupMethod: _1.BackupMethods.passkey,
|
|
140
|
+
backupConfigs: constants_1.mockBackupConfig,
|
|
141
|
+
host: 'test-host',
|
|
142
|
+
mpcVersion: 'v6',
|
|
143
|
+
featureFlags: { isMultiBackupEnabled: true },
|
|
144
|
+
}, mockProgressFn);
|
|
145
|
+
}));
|
|
146
|
+
});
|
|
147
|
+
describe('recoverWallet', () => {
|
|
148
|
+
it('should successfully recover a wallet and call mpc.recover correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
149
|
+
const mockProgressFn = jest.fn();
|
|
150
|
+
const res = yield portal.recoverWallet(constants_1.mockCipherText, _1.BackupMethods.password, constants_1.mockBackupConfig, mockProgressFn);
|
|
151
|
+
expect(res).toBe(constants_1.mockAddress);
|
|
152
|
+
expect(portal.mpc.recover).toHaveBeenCalledTimes(1);
|
|
153
|
+
expect(portal.mpc.recover).toHaveBeenCalledWith({
|
|
154
|
+
cipherText: constants_1.mockCipherText,
|
|
155
|
+
backupMethod: _1.BackupMethods.password,
|
|
156
|
+
backupConfigs: constants_1.mockBackupConfig,
|
|
157
|
+
host: 'web.portalhq.io',
|
|
158
|
+
mpcVersion: 'v6',
|
|
159
|
+
featureFlags: {},
|
|
160
|
+
}, mockProgressFn);
|
|
161
|
+
}));
|
|
162
|
+
it('should successfully recover a wallet and call mpc.recover correctly with custom constructor args', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
163
|
+
portal = new _1.default({
|
|
164
|
+
rpcConfig: constants_1.mockRpcConfig,
|
|
165
|
+
featureFlags: { isMultiBackupEnabled: true },
|
|
166
|
+
host: 'test-host',
|
|
167
|
+
});
|
|
168
|
+
portal.mpc = mpc_1.default;
|
|
169
|
+
portal.provider = provider_1.default;
|
|
170
|
+
const mockProgressFn = jest.fn();
|
|
171
|
+
const res = yield portal.recoverWallet(constants_1.mockCipherText, _1.BackupMethods.password, constants_1.mockBackupConfig, mockProgressFn);
|
|
172
|
+
expect(res).toBe(constants_1.mockAddress);
|
|
173
|
+
expect(portal.mpc.recover).toHaveBeenCalledTimes(1);
|
|
174
|
+
expect(portal.mpc.recover).toHaveBeenCalledWith({
|
|
175
|
+
cipherText: constants_1.mockCipherText,
|
|
176
|
+
backupMethod: _1.BackupMethods.password,
|
|
177
|
+
backupConfigs: constants_1.mockBackupConfig,
|
|
178
|
+
host: 'test-host',
|
|
179
|
+
mpcVersion: 'v6',
|
|
180
|
+
featureFlags: { isMultiBackupEnabled: true },
|
|
181
|
+
}, mockProgressFn);
|
|
182
|
+
}));
|
|
183
|
+
});
|
|
184
|
+
describe('provisionWallet', () => {
|
|
185
|
+
it('should successfully generate a wallet and call mpc.recover correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
186
|
+
const mockProgressFn = jest.fn();
|
|
187
|
+
const res = yield portal.provisionWallet(constants_1.mockCipherText, _1.BackupMethods.password, constants_1.mockBackupConfig, mockProgressFn);
|
|
188
|
+
expect(res).toBe(constants_1.mockAddress);
|
|
189
|
+
expect(portal.mpc.recover).toHaveBeenCalledTimes(1);
|
|
190
|
+
expect(portal.mpc.recover).toHaveBeenCalledWith({
|
|
191
|
+
cipherText: constants_1.mockCipherText,
|
|
192
|
+
backupMethod: _1.BackupMethods.password,
|
|
193
|
+
backupConfigs: constants_1.mockBackupConfig,
|
|
194
|
+
host: 'web.portalhq.io',
|
|
195
|
+
mpcVersion: 'v6',
|
|
196
|
+
featureFlags: {},
|
|
197
|
+
}, mockProgressFn);
|
|
198
|
+
}));
|
|
199
|
+
it('should successfully generate a wallet and call mpc.recover correctly with custom constructor args', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
200
|
+
portal = new _1.default({
|
|
201
|
+
rpcConfig: constants_1.mockRpcConfig,
|
|
202
|
+
featureFlags: { isMultiBackupEnabled: true },
|
|
203
|
+
host: 'test-host',
|
|
204
|
+
});
|
|
205
|
+
portal.mpc = mpc_1.default;
|
|
206
|
+
portal.provider = provider_1.default;
|
|
207
|
+
const mockProgressFn = jest.fn();
|
|
208
|
+
const res = yield portal.provisionWallet(constants_1.mockCipherText, _1.BackupMethods.password, constants_1.mockBackupConfig, mockProgressFn);
|
|
209
|
+
expect(res).toBe(constants_1.mockAddress);
|
|
210
|
+
expect(portal.mpc.recover).toHaveBeenCalledTimes(1);
|
|
211
|
+
expect(portal.mpc.recover).toHaveBeenCalledWith({
|
|
212
|
+
cipherText: constants_1.mockCipherText,
|
|
213
|
+
backupMethod: _1.BackupMethods.password,
|
|
214
|
+
backupConfigs: constants_1.mockBackupConfig,
|
|
215
|
+
host: 'test-host',
|
|
216
|
+
mpcVersion: 'v6',
|
|
217
|
+
featureFlags: { isMultiBackupEnabled: true },
|
|
218
|
+
}, mockProgressFn);
|
|
219
|
+
}));
|
|
220
|
+
});
|
|
221
|
+
describe('eject', () => {
|
|
222
|
+
it('should successfully eject a wallet when backup with portal is enabled', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
223
|
+
const res = yield portal.eject(_1.BackupMethods.password, constants_1.mockBackupConfig);
|
|
224
|
+
expect(res).toEqual(constants_1.mockEjectResult);
|
|
225
|
+
expect(portal.mpc.eject).toHaveBeenCalledTimes(1);
|
|
226
|
+
expect(portal.mpc.eject).toHaveBeenCalledWith({
|
|
227
|
+
cipherText: '',
|
|
228
|
+
backupMethod: _1.BackupMethods.password,
|
|
229
|
+
backupConfigs: constants_1.mockBackupConfig,
|
|
230
|
+
organizationBackupShare: '',
|
|
231
|
+
host: 'web.portalhq.io',
|
|
232
|
+
mpcVersion: 'v6',
|
|
233
|
+
featureFlags: {},
|
|
234
|
+
});
|
|
235
|
+
}));
|
|
236
|
+
it('should successfully eject a wallet when backup with portal is not enabled', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
237
|
+
portal.mpc.getClient = portal.mpc.getClient.mockResolvedValueOnce(Object.assign(Object.assign({}, constants_1.mockClientResponse), { environment: Object.assign(Object.assign({}, constants_1.mockClientResponse.environment), { backupWithPortalEnabled: false }) }));
|
|
238
|
+
const res = yield portal.eject(_1.BackupMethods.password, constants_1.mockBackupConfig, constants_1.mockOrgBackupShare, constants_1.mockCipherText);
|
|
239
|
+
expect(res).toEqual(constants_1.mockEjectResult);
|
|
240
|
+
expect(portal.mpc.eject).toHaveBeenCalledTimes(1);
|
|
241
|
+
expect(portal.mpc.eject).toHaveBeenCalledWith({
|
|
242
|
+
cipherText: constants_1.mockCipherText,
|
|
243
|
+
organizationBackupShare: constants_1.mockOrgBackupShare,
|
|
244
|
+
backupMethod: _1.BackupMethods.password,
|
|
245
|
+
backupConfigs: constants_1.mockBackupConfig,
|
|
246
|
+
host: 'web.portalhq.io',
|
|
247
|
+
mpcVersion: 'v6',
|
|
248
|
+
featureFlags: {},
|
|
249
|
+
});
|
|
250
|
+
}));
|
|
251
|
+
it('should error out if client could not be found', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
252
|
+
portal.mpc.getClient = portal.mpc.getClient.mockResolvedValueOnce(null);
|
|
253
|
+
yield expect(portal.eject(_1.BackupMethods.password, constants_1.mockBackupConfig, constants_1.mockOrgBackupShare, constants_1.mockCipherText)).rejects.toThrowError(new Error('Client not found.'));
|
|
254
|
+
}));
|
|
255
|
+
it('should error if clientBackupCipherText was not supplied when backup with portal is not enabled', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
256
|
+
portal.mpc.getClient = portal.mpc.getClient.mockResolvedValueOnce(Object.assign(Object.assign({}, constants_1.mockClientResponse), { environment: Object.assign(Object.assign({}, constants_1.mockClientResponse.environment), { backupWithPortalEnabled: false }) }));
|
|
257
|
+
yield expect(portal.eject(_1.BackupMethods.password, constants_1.mockBackupConfig)).rejects.toThrowError(new Error('clientBackupCipherText cannot be empty string.'));
|
|
258
|
+
}));
|
|
259
|
+
it('should error if orgBackupShare was empty when backup with portal is not enabled', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
260
|
+
portal.mpc.getClient = portal.mpc.getClient.mockResolvedValueOnce(Object.assign(Object.assign({}, constants_1.mockClientResponse), { environment: Object.assign(Object.assign({}, constants_1.mockClientResponse.environment), { backupWithPortalEnabled: false }) }));
|
|
261
|
+
yield expect(portal.eject(_1.BackupMethods.password, constants_1.mockBackupConfig, '', constants_1.mockCipherText)).rejects.toThrowError(new Error('orgBackupShare cannot be empty string.'));
|
|
262
|
+
}));
|
|
263
|
+
});
|
|
264
|
+
describe('getEip155Address', () => {
|
|
265
|
+
it("should return the wallet's eip155 address correctly", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
266
|
+
const res = yield portal.getEip155Address();
|
|
267
|
+
expect(res).toBe(constants_1.mockEip155Address);
|
|
268
|
+
}));
|
|
269
|
+
});
|
|
270
|
+
describe('getSolanaAddress', () => {
|
|
271
|
+
it("should return the wallet's solana address correctly", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
272
|
+
const res = yield portal.getSolanaAddress();
|
|
273
|
+
expect(res).toBe(constants_1.mockSolanaAddress);
|
|
274
|
+
}));
|
|
275
|
+
});
|
|
276
|
+
describe('doesWalletExist', () => {
|
|
277
|
+
it('should successfully return if wallets exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
278
|
+
const res = yield portal.doesWalletExist();
|
|
279
|
+
expect(res).toBe(constants_1.mockClientResponse.wallets.length > 0);
|
|
280
|
+
}));
|
|
281
|
+
it('should successfully return if wallets exist for a specific chain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
282
|
+
expect(yield portal.doesWalletExist('eip155:1')).toBe(!!constants_1.mockClientResponse.metadata.namespaces['eip155']);
|
|
283
|
+
expect(yield portal.doesWalletExist('unsupported:chain')).toBe(false);
|
|
284
|
+
}));
|
|
285
|
+
});
|
|
286
|
+
describe('isWalletOnDevice', () => {
|
|
287
|
+
it('should successfully check if wallet is on device', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
288
|
+
const res = yield portal.isWalletOnDevice();
|
|
289
|
+
expect(res).toBe(constants_1.mockSharesOnDevice.ED25519 && constants_1.mockSharesOnDevice.SECP256K1);
|
|
290
|
+
}));
|
|
291
|
+
it('should successfully check if wallet is on device for a specific chain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
292
|
+
expect(yield portal.isWalletOnDevice('eip155:1')).toBe(constants_1.mockSharesOnDevice.SECP256K1);
|
|
293
|
+
expect(yield portal.isWalletOnDevice('unsupported:chain')).toBe(false);
|
|
294
|
+
}));
|
|
295
|
+
});
|
|
296
|
+
describe('isWalletBackedUp', () => {
|
|
297
|
+
it('should successfully check if wallet is backed up', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
298
|
+
const res = yield portal.isWalletBackedUp();
|
|
299
|
+
expect(res).toBe(true);
|
|
300
|
+
}));
|
|
301
|
+
it('should successfully check if wallet is backed up for a specific chain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
302
|
+
expect(yield portal.isWalletBackedUp('eip155:1')).toBe(true);
|
|
303
|
+
expect(yield portal.isWalletBackedUp('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')).toBe(false);
|
|
304
|
+
expect(yield portal.isWalletBackedUp('unsupported:chain')).toBe(false);
|
|
305
|
+
}));
|
|
306
|
+
});
|
|
307
|
+
describe('sendSol', () => {
|
|
308
|
+
beforeEach(() => {
|
|
309
|
+
portal.address = constants_1.mockSolanaAddress;
|
|
310
|
+
});
|
|
311
|
+
it('should successfully send sol', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
312
|
+
portal.provider.request = portal.provider.request
|
|
313
|
+
.mockResolvedValueOnce(constants_1.mockBlockHashResponse)
|
|
314
|
+
.mockResolvedValueOnce(constants_1.mockSignedHash);
|
|
315
|
+
const result = yield portal.sendSol({
|
|
316
|
+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
317
|
+
to: '9G2CRh8pzicbRkiNLh8Xsp2DEP28UhwtHSyqetGYTCWD',
|
|
318
|
+
lamports: 10000,
|
|
319
|
+
});
|
|
320
|
+
expect(result).toBe(constants_1.mockSignedHash);
|
|
321
|
+
expect(portal.provider.request).toHaveBeenCalledTimes(2);
|
|
322
|
+
expect(portal.provider.request.mock.calls[0]).toEqual([
|
|
323
|
+
{
|
|
324
|
+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
325
|
+
method: 'getLatestBlockhash',
|
|
326
|
+
params: [],
|
|
327
|
+
},
|
|
328
|
+
]);
|
|
329
|
+
expect(portal.provider.request.mock.calls[1]).toEqual([
|
|
330
|
+
{
|
|
331
|
+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
332
|
+
method: 'sol_signAndSendTransaction',
|
|
333
|
+
params: [
|
|
334
|
+
{
|
|
335
|
+
message: {
|
|
336
|
+
accountKeys: [
|
|
337
|
+
constants_1.mockSolanaAddress,
|
|
338
|
+
'9G2CRh8pzicbRkiNLh8Xsp2DEP28UhwtHSyqetGYTCWD',
|
|
339
|
+
'11111111111111111111111111111111',
|
|
340
|
+
],
|
|
341
|
+
header: {
|
|
342
|
+
numReadonlySignedAccounts: 0,
|
|
343
|
+
numReadonlyUnsignedAccounts: 1,
|
|
344
|
+
numRequiredSignatures: 1,
|
|
345
|
+
},
|
|
346
|
+
instructions: [
|
|
347
|
+
{
|
|
348
|
+
accounts: [0, 1],
|
|
349
|
+
// @solana/web3.js/src/programs/system.ts > .transfer > encodeData
|
|
350
|
+
data: '3Bxs43ZMjSRQLs6o',
|
|
351
|
+
programIdIndex: 2,
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
recentBlockhash: constants_1.mockBlockHashResponse.value.blockhash,
|
|
355
|
+
},
|
|
356
|
+
signatures: null,
|
|
357
|
+
},
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
]);
|
|
361
|
+
}));
|
|
362
|
+
it('should throw an error if the chainId is invalid', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
363
|
+
yield expect(portal.sendSol({
|
|
364
|
+
chainId: 'eip155:1',
|
|
365
|
+
to: '9G2CRh8pzicbRkiNLh8Xsp2DEP28UhwtHSyqetGYTCWD',
|
|
366
|
+
lamports: 10000,
|
|
367
|
+
})).rejects.toThrow(new Error('[Portal] Invalid chainId. Please provide a chainId that starts with "solana:"'));
|
|
368
|
+
}));
|
|
369
|
+
it('should throw an error if the to address is invalid', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
370
|
+
yield expect(portal.sendSol({
|
|
371
|
+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
372
|
+
to: 'test',
|
|
373
|
+
lamports: 10000,
|
|
374
|
+
})).rejects.toThrow(new Error('[Portal] Invalid "to" Solana address provided, must be 44 characters'));
|
|
375
|
+
}));
|
|
376
|
+
it('should throw an error if the lamports arg is invalid', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
377
|
+
yield expect(portal.sendSol({
|
|
378
|
+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
379
|
+
to: '9G2CRh8pzicbRkiNLh8Xsp2DEP28UhwtHSyqetGYTCWD',
|
|
380
|
+
lamports: -32,
|
|
381
|
+
})).rejects.toThrow(new Error('[Portal] Invalid lamports amount, must be a positive number greater than 0'));
|
|
382
|
+
}));
|
|
383
|
+
it('should throw an error if the latest blockhash could not be fetched', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
384
|
+
portal.provider.request = portal.provider.request.mockResolvedValueOnce({ error: 'test' });
|
|
385
|
+
yield expect(portal.sendSol({
|
|
386
|
+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
387
|
+
to: '9G2CRh8pzicbRkiNLh8Xsp2DEP28UhwtHSyqetGYTCWD',
|
|
388
|
+
lamports: 10000,
|
|
389
|
+
})).rejects.toThrow(new Error('[Portal] Failed to get most recent blockhash'));
|
|
390
|
+
}));
|
|
391
|
+
it('should throw an error if rpc url was empty for the chain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
392
|
+
portal = new _1.default({
|
|
393
|
+
rpcConfig: {
|
|
394
|
+
'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1': '',
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
portal.address = constants_1.mockSolanaAddress;
|
|
398
|
+
portal.mpc = mpc_1.default;
|
|
399
|
+
portal.provider = provider_1.default;
|
|
400
|
+
portal.provider.request = portal.provider.request.mockResolvedValueOnce(constants_1.mockBlockHashResponse);
|
|
401
|
+
yield expect(portal.sendSol({
|
|
402
|
+
chainId: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
|
|
403
|
+
to: '9G2CRh8pzicbRkiNLh8Xsp2DEP28UhwtHSyqetGYTCWD',
|
|
404
|
+
lamports: 10000,
|
|
405
|
+
})).rejects.toThrow(new Error('[Portal] No RPC endpoint configured for chainId'));
|
|
406
|
+
}));
|
|
407
|
+
it("should throw an error if client's solana address could not be fetched", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
408
|
+
portal.provider.request = portal.provider.request.mockResolvedValueOnce(constants_1.mockBlockHashResponse);
|
|
409
|
+
portal.mpc.getClient = portal.mpc.getClient.mockResolvedValueOnce(null);
|
|
410
|
+
yield expect(portal.sendSol({
|
|
411
|
+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
412
|
+
to: '9G2CRh8pzicbRkiNLh8Xsp2DEP28UhwtHSyqetGYTCWD',
|
|
413
|
+
lamports: 10000,
|
|
414
|
+
})).rejects.toThrow(new Error('[Portal] Failed to get Solana address'));
|
|
415
|
+
}));
|
|
416
|
+
it("should throw an error if txn hash wasn't returned from the provider", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
417
|
+
portal.provider.request = portal.provider.request
|
|
418
|
+
.mockResolvedValueOnce(constants_1.mockBlockHashResponse)
|
|
419
|
+
.mockResolvedValueOnce(null);
|
|
420
|
+
yield expect(portal.sendSol({
|
|
421
|
+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
422
|
+
to: '9G2CRh8pzicbRkiNLh8Xsp2DEP28UhwtHSyqetGYTCWD',
|
|
423
|
+
lamports: 10000,
|
|
424
|
+
})).rejects.toThrow(new Error('[Portal] Failed to send Solana transaction'));
|
|
425
|
+
}));
|
|
426
|
+
});
|
|
427
|
+
describe('sendEth', () => {
|
|
428
|
+
it('should correctly call provider.request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
429
|
+
portal.address = constants_1.mockAddress;
|
|
430
|
+
yield portal.sendEth({
|
|
431
|
+
chainId: 'eip155:1',
|
|
432
|
+
to: 'test',
|
|
433
|
+
value: '42',
|
|
434
|
+
});
|
|
435
|
+
expect(portal.provider.request).toHaveBeenCalledTimes(1);
|
|
436
|
+
expect(portal.provider.request).toHaveBeenCalledWith({
|
|
437
|
+
chainId: 'eip155:1',
|
|
438
|
+
method: 'eth_sendTransaction',
|
|
439
|
+
params: [
|
|
440
|
+
{
|
|
441
|
+
from: constants_1.mockAddress,
|
|
442
|
+
to: 'test',
|
|
443
|
+
value: '42',
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
});
|
|
447
|
+
}));
|
|
448
|
+
});
|
|
449
|
+
describe('getBalances', () => {
|
|
450
|
+
it('should correctly call mpc.getBalances', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
451
|
+
yield portal.getBalances('eip155:1');
|
|
452
|
+
expect(portal.mpc.getBalances).toHaveBeenCalledTimes(1);
|
|
453
|
+
expect(portal.mpc.getBalances).toHaveBeenCalledWith('eip155:1');
|
|
454
|
+
}));
|
|
455
|
+
});
|
|
456
|
+
describe('getClient', () => {
|
|
457
|
+
it('should correctly call mpc.getClient', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
458
|
+
yield portal.getClient();
|
|
459
|
+
expect(portal.mpc.getClient).toHaveBeenCalledTimes(1);
|
|
460
|
+
expect(portal.mpc.getClient).toHaveBeenCalledWith();
|
|
461
|
+
}));
|
|
462
|
+
});
|
|
463
|
+
describe('getNFTs', () => {
|
|
464
|
+
it('should correctly call mpc.getNFTs', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
465
|
+
yield portal.getNFTs('eip155:1');
|
|
466
|
+
expect(portal.mpc.getNFTs).toHaveBeenCalledTimes(1);
|
|
467
|
+
expect(portal.mpc.getNFTs).toHaveBeenCalledWith('eip155:1');
|
|
468
|
+
}));
|
|
469
|
+
});
|
|
470
|
+
describe('getTransactions', () => {
|
|
471
|
+
it('should correctly call mpc.getTransactions', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
472
|
+
yield portal.getTransactions('eip155:1', 1, 10, _1.GetTransactionsOrder.DESC);
|
|
473
|
+
expect(portal.mpc.getTransactions).toHaveBeenCalledTimes(1);
|
|
474
|
+
expect(portal.mpc.getTransactions).toHaveBeenCalledWith('eip155:1', 1, 10, _1.GetTransactionsOrder.DESC);
|
|
475
|
+
}));
|
|
476
|
+
});
|
|
477
|
+
describe('simulateTransaction', () => {
|
|
478
|
+
it('should correctly call mpc.simulateTransaction', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
479
|
+
yield portal.simulateTransaction('eip155:1', constants_1.mockEthTransaction);
|
|
480
|
+
expect(portal.mpc.simulateTransaction).toHaveBeenCalledTimes(1);
|
|
481
|
+
expect(portal.mpc.simulateTransaction).toHaveBeenCalledWith(constants_1.mockEthTransaction, 'eip155:1');
|
|
482
|
+
}));
|
|
483
|
+
});
|
|
484
|
+
describe('evaluateTransaction', () => {
|
|
485
|
+
it('should correctly call mpc.evaluateTransaction', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
486
|
+
yield portal.evaluateTransaction('eip155:1', constants_1.mockEthTransaction, 'validation');
|
|
487
|
+
expect(portal.mpc.evaluateTransaction).toHaveBeenCalledTimes(1);
|
|
488
|
+
expect(portal.mpc.evaluateTransaction).toHaveBeenCalledWith('eip155:1', constants_1.mockEthTransaction, 'validation');
|
|
489
|
+
}));
|
|
490
|
+
});
|
|
491
|
+
describe('buildTransaction', () => {
|
|
492
|
+
it('should correctly call mpc.buildTransaction', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
493
|
+
yield portal.buildTransaction('eip155:1', constants_1.mockAddress, 'USDC', '1');
|
|
494
|
+
expect(portal.mpc.buildTransaction).toHaveBeenCalledTimes(1);
|
|
495
|
+
expect(portal.mpc.buildTransaction).toHaveBeenCalledWith('eip155:1', constants_1.mockAddress, 'USDC', '1');
|
|
496
|
+
}));
|
|
497
|
+
});
|
|
498
|
+
describe('getNFTAssets', () => {
|
|
499
|
+
it('should correctly call mpc.getNFTAssets', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
500
|
+
yield portal.getNFTAssets('eip155:1');
|
|
501
|
+
expect(portal.mpc.getNFTAssets).toHaveBeenCalledTimes(1);
|
|
502
|
+
expect(portal.mpc.getNFTAssets).toHaveBeenCalledWith('eip155:1');
|
|
503
|
+
}));
|
|
504
|
+
});
|
|
505
|
+
describe('getAssets', () => {
|
|
506
|
+
it('should correctly call mpc.getAssets', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
507
|
+
yield portal.getAssets('eip155:1');
|
|
508
|
+
expect(portal.mpc.getAssets).toHaveBeenCalledTimes(1);
|
|
509
|
+
expect(portal.mpc.getAssets).toHaveBeenCalledWith('eip155:1', false);
|
|
510
|
+
}));
|
|
511
|
+
});
|
|
512
|
+
describe('getQuote', () => {
|
|
513
|
+
it('should correctly call mpc.getQuote', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
514
|
+
yield portal.getQuote('test', constants_1.mockQuoteArgs, 'eip155:1');
|
|
515
|
+
expect(portal.mpc.getQuote).toHaveBeenCalledTimes(1);
|
|
516
|
+
expect(portal.mpc.getQuote).toHaveBeenCalledWith('test', constants_1.mockQuoteArgs, 'eip155:1');
|
|
517
|
+
}));
|
|
518
|
+
});
|
|
519
|
+
describe('getSources', () => {
|
|
520
|
+
it('should correctly call mpc.getSources', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
521
|
+
yield portal.getSources('test', 'eip155:1');
|
|
522
|
+
expect(portal.mpc.getSources).toHaveBeenCalledTimes(1);
|
|
523
|
+
expect(portal.mpc.getSources).toHaveBeenCalledWith('test', 'eip155:1');
|
|
524
|
+
}));
|
|
525
|
+
});
|
|
526
|
+
describe('storedClientBackupShare', () => {
|
|
527
|
+
it('should correctly call mpc.storedClientBackupShare', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
528
|
+
yield portal.storedClientBackupShare(true, _1.BackupMethods.password);
|
|
529
|
+
expect(portal.mpc.storedClientBackupShare).toHaveBeenCalledTimes(1);
|
|
530
|
+
expect(portal.mpc.storedClientBackupShare).toHaveBeenCalledWith(true, _1.BackupMethods.password);
|
|
531
|
+
}));
|
|
532
|
+
});
|
|
533
|
+
describe('getRpcUrl', () => {
|
|
534
|
+
it('should return the correct rpc url for the given chainId', () => {
|
|
535
|
+
expect(portal.getRpcUrl('eip155:1')).toEqual(constants_1.mockEthRpcUrl);
|
|
536
|
+
expect(portal.getRpcUrl('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')).toEqual(constants_1.mockSolRpcUrl);
|
|
537
|
+
});
|
|
538
|
+
it('should throw an error if the chainId is not provided', () => {
|
|
539
|
+
expect(() => portal.getRpcUrl()).toThrow(new Error('[Portal] No chainId provided. Please provide a chainId to get the RPC endpoint'));
|
|
540
|
+
});
|
|
541
|
+
it('should throw an error if the chainId is not present in the rpc config', () => {
|
|
542
|
+
expect(() => portal.getRpcUrl('test')).toThrow(new Error('[Portal] No RPC endpoint configured for chainId: test'));
|
|
543
|
+
});
|
|
544
|
+
it('should throw an error if the chainId is not present in the rpc config', () => {
|
|
545
|
+
expect(() => portal.getRpcUrl('incorrect-config')).toThrow(new Error('[Portal] Could not find a valid rpcConfig entry for chainId: incorrect-config'));
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
});
|
|
@@ -62,7 +62,7 @@ class MpcError extends Error {
|
|
|
62
62
|
// Init the actual error
|
|
63
63
|
super(error.message(context));
|
|
64
64
|
// Custom error context
|
|
65
|
-
this.code = (error === null || error === void 0 ? void 0 : error.code) || 999;
|
|
65
|
+
this.code = (error === null || error === void 0 ? void 0 : error.code) || '999';
|
|
66
66
|
if (context) {
|
|
67
67
|
this.context = context;
|
|
68
68
|
}
|