UNPKG

@safik/fk-plug-controller

Version:

Internet Computer Plug wallet's controller

744 lines (743 loc) 39.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable @typescript-eslint/camelcase */ /* eslint-disable camelcase */ const bip39 = __importStar(require("bip39")); const crypto_js_1 = __importDefault(require("crypto-js")); const principal_1 = require("@dfinity/principal"); const cross_fetch_1 = __importDefault(require("cross-fetch")); const _1 = __importDefault(require(".")); const errors_1 = require("../errors"); const PlugWallet_1 = __importDefault(require("../PlugWallet")); const dfx_1 = require("../utils/dfx"); const mock_1 = __importDefault(require("../utils/storage/mock")); const account_1 = require("../utils/account"); const tokens_1 = require("../constants/tokens"); const mockSendICP = jest.fn(); jest.mock('../utils/dfx', () => { return { createAgent: jest.fn(() => ({})), createLedgerActor: () => ({ sendICP: mockSendICP, }), }; }); jest.mock('../utils/dfx/token', () => { return { createTokenActor: () => ({ getMetadata: jest.fn(() => ({ fungible: { symbol: 'WTC', decimals: 5, name: 'Wrapped Cycles' }, })), }), }; }); // jest.mock('../utils/dfx/nft', () => { // return { // createNFTActor: (): { // user_tokens: jest.Mock<any, any>; // data_of: jest.Mock<any, any>; // transfer_to: jest.Mock<boolean, any>; // } => ({ // user_tokens: jest.fn(() => [BigInt(10)]), // data_of: jest.fn(() => ({ // index: BigInt(10), // canister: 'qcg3w-tyaaa-aaaah-qakea-cai', // name: 'IC Punk# 10', // url: 'https://qcg3w-tyaaa-aaaah-qakea-cai.raw.ic0.app/Token/10', // metadata: { // index: BigInt(10), // name: 'IC Punk# 10', // url: 'https://qcg3w-tyaaa-aaaah-qakea-cai.raw.ic0.app/Token/10', // owner: Principal.from( // 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe' // ), // desc: 'string', // properties: [], // }, // })), // transfer_to: jest.fn((_, id) => { // if (id === BigInt(130)) { // throw new Error(ERRORS.TRANSFER_NFT_ERROR); // } // return true; // }), // }), // }; // }); jest.mock('../utils/dfx/token/methods', () => { return {}; }); const TEST_PASSWORD = 'Somepassword1234'; const TEST_MNEMONIC = bip39.generateMnemonic(); const createManyWallets = (keyRing, mockingMethod) => __awaiter(void 0, void 0, void 0, function* () { const many = Math.round(Math.random() * 20) + 2; for (let i = 0; i < many; i += 1) { const wallet = yield keyRing.createPrincipal(); // eslint-disable-line if (mockingMethod) mockingMethod(wallet); } return many; }); const createManyTransactions = () => { const many = Math.round(Math.random() * 20) + 2; const transactions = { total: 0, transactions: [] }; for (let i = 0; i < many; i += 1) { transactions.transactions.push({ timestamp: BigInt(0), hash: '0', details: { from: 'string', to: 'string', amount: BigInt(1000), currency: { symbol: 'ICP', decimals: 8 }, fee: { amount: BigInt(1000), currency: { symbol: 'ICP', decimals: 8 }, }, status: 'COMPLETED', }, type: 'SEND', caller: 'stirng', }); transactions.transactions.push({ timestamp: BigInt(0), hash: '0', details: { from: 'string', to: 'string', amount: BigInt(1000), currency: { symbol: 'XTC', decimals: 5 }, fee: { amount: BigInt(1000), currency: { symbol: 'XTC', decimals: 5 }, }, status: 'COMPLETED', }, caller: 'string', type: 'SEND', }); } return transactions; }; describe('Plug KeyRing', () => { const testWallet = new PlugWallet_1.default({ name: 'test', mnemonic: TEST_MNEMONIC, walletNumber: 0, fetch: cross_fetch_1.default, }); let keyRing; const cleanup = () => __awaiter(void 0, void 0, void 0, function* () { yield mock_1.default.clear(); keyRing = new _1.default(mock_1.default); }); beforeAll(cleanup); beforeEach(cleanup); afterEach(cleanup); describe('initialization', () => { it('should be empty and locked if not initialized', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(() => keyRing.setCurrentPrincipal(testWallet.walletNumber)).rejects.toEqual(Error(errors_1.ERRORS.NOT_INITIALIZED)); yield expect(() => keyRing.unlock(TEST_PASSWORD)).rejects.toEqual(Error(errors_1.ERRORS.NOT_INITIALIZED)); yield expect(() => keyRing.createPrincipal()).rejects.toEqual(Error(errors_1.ERRORS.NOT_INITIALIZED)); yield expect(() => keyRing.getState()).rejects.toEqual(Error(errors_1.ERRORS.NOT_INITIALIZED)); expect(keyRing.isInitialized).toBe(false); expect(keyRing.isUnlocked).toBe(false); })); }); describe('creation', () => { it('should create a new keyring and be locked by default', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); expect(keyRing.isInitialized).toBe(true); expect(keyRing.isUnlocked).toBe(false); yield expect(() => keyRing.getState()).rejects.toEqual(Error(errors_1.ERRORS.STATE_LOCKED)); })); it('should create a new keyring and expose state correctly', () => __awaiter(void 0, void 0, void 0, function* () { const { wallet } = yield keyRing.create({ password: TEST_PASSWORD }); expect(yield keyRing.unlock(TEST_PASSWORD)).toEqual(true); expect(keyRing.isInitialized).toBe(true); expect(keyRing.isUnlocked).toBe(true); const state = yield keyRing.getState(); expect(state.wallets.length).toEqual(1); const stateWallet = state.wallets[0]; expect(stateWallet.toJSON()).toEqual(wallet.toJSON()); expect(state.password).toEqual(TEST_PASSWORD); expect(bip39.validateMnemonic(state.mnemonic)).toEqual(true); expect(stateWallet.registeredTokens).toEqual([tokens_1.TOKENS.XTC]); })); it('should fail if not password was provided', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(() => keyRing.create({ password: '' })).rejects.toEqual(Error(errors_1.ERRORS.PASSWORD_REQUIRED)); })); }); describe('import', () => { it('should import a keyring and expose state correctly', () => __awaiter(void 0, void 0, void 0, function* () { const { wallet } = yield keyRing.importMnemonic({ password: TEST_PASSWORD, mnemonic: TEST_MNEMONIC, }); expect(keyRing.isInitialized).toBe(true); const unlocked = yield keyRing.unlock(TEST_PASSWORD); expect(keyRing.isUnlocked).toBe(true); expect(unlocked).toEqual(true); const state = yield keyRing.getState(); expect(state.wallets.length).toEqual(1); const stateWallet = state.wallets[0]; expect(stateWallet.toJSON()).toEqual(wallet.toJSON()); expect(state.mnemonic).toEqual(TEST_MNEMONIC); expect(state.password).toEqual(TEST_PASSWORD); expect(bip39.validateMnemonic(state.mnemonic)).toEqual(true); expect(stateWallet.registeredTokens).toEqual([tokens_1.TOKENS.XTC]); expect(stateWallet.connectedApps).toEqual([]); })); it('should fail if not password or mnemonic were provided', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(() => keyRing.importMnemonic({ password: '', mnemonic: TEST_MNEMONIC })).rejects.toEqual(Error(errors_1.ERRORS.PASSWORD_REQUIRED)); yield expect(() => keyRing.importMnemonic({ password: TEST_PASSWORD, mnemonic: '' })).rejects.toEqual(Error(errors_1.ERRORS.INVALID_MNEMONIC)); expect(keyRing.isInitialized).toBe(false); })); it('should fail if the mnemonic is invalid', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(() => keyRing.importMnemonic({ password: TEST_PASSWORD, mnemonic: 'some test mnemonic', })).rejects.toEqual(Error(errors_1.ERRORS.INVALID_MNEMONIC)); expect(keyRing.isInitialized).toBe(false); })); it('should import the same wallet even with different passwords', () => __awaiter(void 0, void 0, void 0, function* () { const { wallet } = yield keyRing.importMnemonic({ mnemonic: TEST_MNEMONIC, password: TEST_PASSWORD, }); const { wallet: newWallet } = yield keyRing.importMnemonic({ mnemonic: TEST_MNEMONIC, password: 'newpassword1', }); expect(wallet.toJSON()).toEqual(newWallet.toJSON()); expect(wallet.principal).toEqual(newWallet.principal); })); }); describe('lock', () => { it('should create a keyring and be locked by default', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield expect(() => keyRing.getState()).rejects.toEqual(Error(errors_1.ERRORS.STATE_LOCKED)); expect(keyRing.isInitialized).toBe(true); expect(keyRing.isUnlocked).toBe(false); })); it('should import a keyring and be locked by default', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.importMnemonic({ password: TEST_PASSWORD, mnemonic: TEST_MNEMONIC, }); yield expect(() => keyRing.getState()).rejects.toEqual(Error(errors_1.ERRORS.STATE_LOCKED)); expect(keyRing.isUnlocked).toBe(false); })); it('should unlock correctly with correct password', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); expect(keyRing.isUnlocked).toBe(true); const state = yield keyRing.getState(); expect(state.wallets.length).toEqual(1); expect(state.password).toEqual(TEST_PASSWORD); })); it('should fail to unlock with incorrect password', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); const unlocked = yield keyRing.unlock('false1234'); expect(unlocked).toBe(false); expect(keyRing.isUnlocked).toBe(false); yield expect(() => keyRing.getState()).rejects.toEqual(Error(errors_1.ERRORS.STATE_LOCKED)); })); it('should lock correctly when unlocked', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); expect(keyRing.isUnlocked).toBe(true); yield keyRing.lock(); expect(keyRing.isUnlocked).toBe(false); yield expect(() => keyRing.getState()).rejects.toEqual(Error(errors_1.ERRORS.STATE_LOCKED)); })); }); describe('storage', () => { it('should persist data encypted correctly after creating a new keyring', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); const _a = yield keyRing.getState(), { currentWalletId } = _a, state = __rest(_a, ["currentWalletId"]); const encryptedState = crypto_js_1.default.AES.encrypt(JSON.stringify(state), TEST_PASSWORD); const { vault: stored, isInitialized } = mock_1.default.get(); expect(crypto_js_1.default.AES.decrypt(encryptedState, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)).toEqual(crypto_js_1.default.AES.decrypt(stored, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)); expect(isInitialized).toEqual(true); })); it('should persist data encypted correctly after importing a keyring', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.importMnemonic({ mnemonic: TEST_MNEMONIC, password: TEST_PASSWORD, }); yield keyRing.unlock(TEST_PASSWORD); const _b = yield keyRing.getState(), { currentWalletId } = _b, state = __rest(_b, ["currentWalletId"]); const encryptedState = crypto_js_1.default.AES.encrypt(JSON.stringify(state), TEST_PASSWORD); const { vault: stored, isInitialized } = mock_1.default.get(); expect(crypto_js_1.default.AES.decrypt(encryptedState, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)).toEqual(crypto_js_1.default.AES.decrypt(stored, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)); expect(isInitialized).toEqual(true); })); it('should persist data encypted correctly after creating a new principal', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.createPrincipal(); const _c = yield keyRing.getState(), { currentWalletId } = _c, state = __rest(_c, ["currentWalletId"]); const encryptedState = crypto_js_1.default.AES.encrypt(JSON.stringify(state), TEST_PASSWORD); const { vault: stored, isInitialized } = mock_1.default.get(); expect(crypto_js_1.default.AES.decrypt(encryptedState, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)).toEqual(crypto_js_1.default.AES.decrypt(stored, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)); expect(isInitialized).toEqual(true); })); it('should persist data encypted correctly after registering a new token', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.registerToken('5ymop-yyaaa-aaaah-qaa4q-cai', 'xtc'); // register XTC const _d = yield keyRing.getState(), { currentWalletId } = _d, state = __rest(_d, ["currentWalletId"]); const encryptedState = crypto_js_1.default.AES.encrypt(JSON.stringify(state), TEST_PASSWORD); const { vault: stored, isInitialized } = mock_1.default.get(); expect(crypto_js_1.default.AES.decrypt(encryptedState, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)).toEqual(crypto_js_1.default.AES.decrypt(stored, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)); expect(isInitialized).toEqual(true); })); }); it('should persist data encypted correctly after adding a new app', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.addConnectedApp({ name: 'Chris', icon: ':smile:', url: 'dx4k2-mtdzp-qavet-nrazz-4tmro-oii6a-hlrlv-azdys-5j72q-ids2p-cae', whitelist: [], }); const _a = yield keyRing.getState(), { currentWalletId } = _a, state = __rest(_a, ["currentWalletId"]); const encryptedState = crypto_js_1.default.AES.encrypt(JSON.stringify(state), TEST_PASSWORD); const { vault: stored, isInitialized } = mock_1.default.get(); expect(crypto_js_1.default.AES.decrypt(encryptedState, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)).toEqual(crypto_js_1.default.AES.decrypt(stored, TEST_PASSWORD).toString(crypto_js_1.default.enc.Utf8)); expect(isInitialized).toEqual(true); })); describe('principal management', () => { it('should create new principals correctly when unlocked', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.createPrincipal(); let state = yield keyRing.getState(); expect(state.wallets.length).toEqual(2); yield keyRing.createPrincipal(); state = yield keyRing.getState(); expect(state.wallets.length).toEqual(3); })); it('should create many new principals correctly', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.createPrincipal(); yield keyRing.createPrincipal(); yield keyRing.createPrincipal(); yield keyRing.createPrincipal(); const state = yield keyRing.getState(); expect(state.wallets.length).toEqual(5); })); it('should fail to create new principals when locked', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield expect(() => keyRing.createPrincipal()).rejects.toEqual(Error(errors_1.ERRORS.STATE_LOCKED)); })); it('should set the current principal correctly', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.createPrincipal(); const wallet = yield keyRing.createPrincipal(); yield keyRing.setCurrentPrincipal(wallet.walletNumber); expect(keyRing.currentWalletId).toEqual(wallet.walletNumber); expect(keyRing.currentWallet).toEqual(wallet); })); it('should fail to set invalid current principal ', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield expect(() => keyRing.setCurrentPrincipal(1)).rejects.toEqual(new Error(errors_1.ERRORS.INVALID_WALLET_NUMBER)); yield expect(() => keyRing.setCurrentPrincipal(-2)).rejects.toEqual(new Error(errors_1.ERRORS.INVALID_WALLET_NUMBER)); yield expect(() => keyRing.setCurrentPrincipal(1.2)).rejects.toEqual(new Error(errors_1.ERRORS.INVALID_WALLET_NUMBER)); })); it('should create new wallets with a default name', () => __awaiter(void 0, void 0, void 0, function* () { const { wallet } = yield keyRing.create({ password: TEST_PASSWORD }); expect(wallet.name).toEqual('Account 1'); const { wallet: newWallet } = yield keyRing.importMnemonic({ mnemonic: TEST_MNEMONIC, password: TEST_PASSWORD, }); expect(newWallet.name).toEqual('Account 1'); })); it('should create new wallets with a correct name and emoji', () => __awaiter(void 0, void 0, void 0, function* () { const { wallet } = yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); const wallet2 = yield keyRing.createPrincipal({ name: 'My new wallet', icon: ':smile:', }); // TODO: TS does not like emojis, but they are unicode strings expect(wallet2.name).toEqual('My new wallet'); expect(wallet2.icon).toEqual(':smile:'); const wallet3 = yield keyRing.createPrincipal({ name: 'My third wallet', }); // TODO: TS does not like emojis, but they are unicode strings expect(wallet3.name).toEqual('My third wallet'); expect(wallet3.icon).toEqual(wallet.icon); const wallet4 = yield keyRing.createPrincipal({ icon: ':crying:', }); // TODO: TS does not like emojis, but they are unicode strings expect(wallet4.name).toEqual(wallet.name); expect(wallet4.icon).toEqual(':crying:'); })); it('should change the wallets name correctly', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.createPrincipal(); yield keyRing.createPrincipal(); yield keyRing.editPrincipal(0, { name: 'New name1' }); yield keyRing.editPrincipal(1, { name: 'New name2' }); yield keyRing.editPrincipal(2, { name: 'New name3' }); const { wallets } = yield keyRing.getState(); expect(wallets[0].name).toEqual('New name1'); expect(wallets[1].name).toEqual('New name2'); expect(wallets[2].name).toEqual('New name3'); })); it('should fail to change an invalid wallet', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield expect(() => keyRing.editPrincipal(10, { name: 'New name', emoji: 'test' })).rejects.toEqual(Error(errors_1.ERRORS.INVALID_WALLET_NUMBER)); yield expect(() => keyRing.editPrincipal(-1, { name: 'New name', emoji: 'test' })).rejects.toEqual(Error(errors_1.ERRORS.INVALID_WALLET_NUMBER)); yield expect(() => keyRing.editPrincipal(1.231, { name: 'New name', emoji: 'test' })).rejects.toEqual(Error(errors_1.ERRORS.INVALID_WALLET_NUMBER)); })); it('should change the wallet icon correctly', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.createPrincipal(); yield keyRing.createPrincipal(); yield keyRing.editPrincipal(0, { emoji: '123' }); yield keyRing.editPrincipal(1, { emoji: 'New emoji2' }); yield keyRing.editPrincipal(2, { emoji: 'New name3' }); const { wallets } = yield keyRing.getState(); expect(wallets[0].icon).toEqual('123'); expect(wallets[1].icon).toEqual('New emoji2'); expect(wallets[2].icon).toEqual('New name3'); })); // Skipped since color is breaking it it('should register a token correctly to different subaccounts', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield keyRing.createPrincipal(); yield keyRing.createPrincipal(); yield keyRing.registerToken('5ymop-yyaaa-aaaah-qaa4q-cai', 'xtc', 1); // register WTC to other subaccounts yield keyRing.registerToken('5ymop-yyaaa-aaaah-qaa4q-cai', 'xtc', 2); // register WTC yield keyRing.registerToken('5ymop-yyaaa-aaaah-qaa4q-cai', 'xtc', 2); // register WTC twice const { wallets } = yield keyRing.getState(); expect(wallets[0].registeredTokens).toMatchObject([tokens_1.TOKENS.XTC]); expect(wallets[1].registeredTokens).toMatchObject([ tokens_1.TOKENS.XTC, tokens_1.TOKENS.WTC, ]); expect(wallets[2].registeredTokens).toMatchObject([ tokens_1.TOKENS.XTC, tokens_1.TOKENS.WTC, ]); })); test('should fail to register an invalid canister id', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield expect(() => keyRing.registerToken('test', 'xtc')).rejects.toEqual(new Error(errors_1.ERRORS.INVALID_CANISTER_ID)); yield expect(() => keyRing.registerToken('ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe', 'xtc')).rejects.toEqual(new Error(errors_1.ERRORS.INVALID_CANISTER_ID)); })); test('should fail to add an app with an invalid canister whitelisted', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); yield expect(() => keyRing.addConnectedApp({ name: 'Chris', icon: ':smile:', url: 'chris123', whitelist: [ 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe', ], })).rejects.toEqual(new Error(errors_1.ERRORS.INVALID_APP)); })); test('should do nothing if app was already added', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); const app = { name: 'Chris', icon: ':smile:', url: 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe', whitelist: [], }; const connectedApps = yield keyRing.addConnectedApp(app); yield keyRing.addConnectedApp(app); expect(connectedApps).toEqual([app]); })); test('should delete correctly a previously saved app', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); const app1 = { name: 'App1', icon: ':smile:', url: 'test123.com', whitelist: [], }; const app2 = { name: 'App2', icon: ':sad:', url: 'plugwallet.ooo', whitelist: [], }; let connectedApps = yield keyRing.addConnectedApp(app1); connectedApps = yield keyRing.addConnectedApp(app2); expect(connectedApps).toEqual([app1, app2]); connectedApps = yield keyRing.deleteConnectedApp(app1.url); expect(connectedApps).toEqual([app2]); connectedApps = yield keyRing.deleteConnectedApp(app2.url); expect(connectedApps).toEqual([]); })); test('should do nothing when trying to delete an unexistant app', () => __awaiter(void 0, void 0, void 0, function* () { yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); const account = { name: 'Some app', icon: ':smile:', url: 'test123.com', whitelist: [], }; const connectedApps = yield keyRing.deleteConnectedApp(account.url); expect(connectedApps).toEqual([]); })); }); describe('get balance', () => { const balances = {}; let walletsCreated = 0; const mockGetBalance = wallet => { const randomBalance = BigInt(0); balances[wallet.walletNumber] = randomBalance; jest.spyOn(wallet, 'getBalance').mockImplementation(jest.fn(() => { return Promise.resolve(randomBalance); })); }; beforeEach(() => __awaiter(void 0, void 0, void 0, function* () { keyRing = new _1.default(mock_1.default); yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); walletsCreated = yield createManyWallets(keyRing, mockGetBalance); })); test('get default balance', () => __awaiter(void 0, void 0, void 0, function* () { expect(yield keyRing.getBalance()).toBe(balances[0]); })); test('get specific balance', () => __awaiter(void 0, void 0, void 0, function* () { const ind = Math.round(Math.random() * (walletsCreated - 1)); expect(yield keyRing.getBalance(ind)).toBe(balances[ind]); })); test('get error with invalid wallet numbers', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(keyRing.getBalance(-2)).rejects.toThrow(errors_1.ERRORS.INVALID_WALLET_NUMBER); yield expect(keyRing.getBalance(walletsCreated + 2)).rejects.toThrow(errors_1.ERRORS.INVALID_WALLET_NUMBER); })); }); describe('get transactions', () => { const transactions = {}; let walletsCreated = 0; const mockGetTransaction = wallet => { const randomTransactions = createManyTransactions(); transactions[wallet.walletNumber] = randomTransactions; jest.spyOn(wallet, 'getTransactions').mockImplementation(jest.fn(() => { return Promise.resolve(randomTransactions); })); }; beforeEach(() => __awaiter(void 0, void 0, void 0, function* () { keyRing = new _1.default(mock_1.default); const { wallet } = yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); mockGetTransaction(wallet); walletsCreated = yield createManyWallets(keyRing, mockGetTransaction); })); // test.only('get default trasnactions', async () => { // expect(await keyRing.getTransactions()).toBe(transactions[0]); // }); test('get specific transactions', () => __awaiter(void 0, void 0, void 0, function* () { const ind = Math.round(Math.random() * (walletsCreated - 1)); expect(yield keyRing.getTransactions(ind)).toBe(transactions[ind]); })); test('get error with invalid wallet numbers', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(keyRing.getTransactions(-2)).rejects.toThrow(errors_1.ERRORS.INVALID_WALLET_NUMBER); yield expect(keyRing.getTransactions(walletsCreated + 2)).rejects.toThrow(errors_1.ERRORS.INVALID_WALLET_NUMBER); })); }); describe('sendICP', () => { let walletsCreated = 0; beforeEach(() => __awaiter(void 0, void 0, void 0, function* () { keyRing = new _1.default(mock_1.default); yield keyRing.create({ password: TEST_PASSWORD }); yield keyRing.unlock(TEST_PASSWORD); walletsCreated = yield createManyWallets(keyRing); })); it('call create agent with secret key', () => __awaiter(void 0, void 0, void 0, function* () { const { wallets } = yield keyRing.getState(); const amount = BigInt(0); const ind = Math.round(Math.random() * (walletsCreated - 1)); const to = wallets[ind].principal; yield keyRing.send(to.toString(), amount.toString()); expect(dfx_1.createAgent).toHaveBeenCalled(); })); it('call sendICP with to account', () => __awaiter(void 0, void 0, void 0, function* () { const { wallets } = yield keyRing.getState(); const amount = BigInt(0); const ind = Math.round(Math.random() * (walletsCreated - 1)); const to = (0, account_1.getAccountId)(principal_1.Principal.fromText(wallets[ind].principal)); yield keyRing.send(to, amount.toString()); expect(dfx_1.createAgent).toHaveBeenCalled(); expect(mockSendICP.mock.calls[0][0].amount.toString()).toEqual(amount.toString()); expect(mockSendICP.mock.calls[0][0].to).toEqual(to); })); it('call sendICP with to principal', () => __awaiter(void 0, void 0, void 0, function* () { const { wallets } = yield keyRing.getState(); const amount = BigInt(0); const ind = Math.round(Math.random() * (walletsCreated - 1)); const to = wallets[ind].principal; yield keyRing.send(to.toString(), amount.toString()); expect(dfx_1.createAgent).toHaveBeenCalled(); expect(mockSendICP.mock.calls[0][0].amount.toString()).toEqual(amount.toString()); expect(mockSendICP.mock.calls[0][0].to).toEqual((0, account_1.getAccountId)(principal_1.Principal.fromText(to))); })); // describe('nfts', () => { // beforeEach(async () => { // keyRing = new PlugKeyRing(store); // await keyRing.importMnemonic({ // password: TEST_PASSWORD, // mnemonic: TEST_MNEMONIC, // }); // await keyRing.unlock(TEST_PASSWORD); // }); // it('should fetch NFTs correctly', async () => { // const nfts = await keyRing.getNFTs(); // expect(nfts).toEqual([ // { // index: BigInt(10), // canister: 'qcg3w-tyaaa-aaaah-qakea-cai', // name: 'IC Punk# 10', // url: 'https://qcg3w-tyaaa-aaaah-qakea-cai.raw.ic0.app/Token/10', // metadata: { // index: BigInt(10), // name: 'IC Punk# 10', // url: 'https://qcg3w-tyaaa-aaaah-qakea-cai.raw.ic0.app/Token/10', // owner: Principal.from('ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe'), // desc: 'string', // properties: [], // } // }, // ]); // }); // it('should fail to fetch NFTs on inexistant account', async () => { // await expect(keyRing.getNFTs(1)).rejects.toThrow( // ERRORS.INVALID_WALLET_NUMBER // ); // }); // it('should transfer an ICPunk NFT correctly', async () => { // const nfts = await keyRing.getNFTs(); // const { tokens } = nfts.icpunks[0]; // const transferred = await keyRing.transferNFT({ // id: tokens[0].index, // to: 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe', // }); // expect(transferred).toEqual(true); // }); // it('should transfer an EXT NFT correctly', async () => { // const nfts = await keyRing.getNFTs(); // const { tokens } = nfts.ext[0]; // const transferred = await keyRing.transferNFT({ // id: tokens[0].id!, // to: 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe', // }); // expect(transferred).toEqual(true); // }); // it('should fail to transfer NFTs on inexistant account', async () => { // const nfts = await keyRing.getNFTs(); // const { tokens } = nfts.icpunks[0]; // await expect( // keyRing.transferNFT({ // subAccount: 1, // id: tokens[0].index!, // to: // 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe', // }) // ).rejects.toThrow(ERRORS.INVALID_WALLET_NUMBER); // }); // // TODO: Not sure how to make it fail. // it('should fail to transfer NFTs that is not owned', async () => { // await expect( // keyRing.transferNFT({ // id: BigInt(130), // to: // 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe', // }) // ).rejects.toThrow(ERRORS.TRANSFER_NFT_ERROR); // }); // it('should fail to transfer NFTs to invalid principal', async () => { // const nfts = await keyRing.getNFTs(); // const { tokens } = nfts.icpunks[0]; // // Malformed pid // await expect( // keyRing.transferNFT({ // id: tokens[0].index!, // to: 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6lbzwp-7qe', // }) // ).rejects.toThrow(ERRORS.INVALID_PRINCIPAL_ID); // // Account ID // await expect( // keyRing.transferNFT({ // id: tokens[0].index!, // to: // '9627c5abbae5b63b3a1b2ad8b6ee85e99e45317c4276c8addb39211ce05d2a59', // }) // ).rejects.toThrow(ERRORS.INVALID_PRINCIPAL_ID); // // CONNFIRM WITH IC PUNKS // // Canister ID // await expect( // keyRing.transferNFT({ // id: tokens[0].index!, // to: '6xisx-7yaaa-aaaah-aagga-cai', // }) // ).rejects.toThrow(ERRORS.INVALID_PRINCIPAL_ID); // }); // }); afterEach(() => { jest.clearAllMocks(); }); }); });