UNPKG

@funded-labs/plug-controller

Version:

Internet Computer Plug wallet's controller

641 lines (640 loc) 33.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (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 */ jest.mock('@funded-labs/dab-js'); 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 dab_js_1 = require("@funded-labs/dab-js"); 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 Network_1 = require("./modules/NetworkModule/Network"); const constants_1 = require("../utils/account/constants"); const account_2 = require("../utils/account"); const mockSendICP = jest.fn(); jest.mock('../utils/dfx', () => { return { createAgent: jest.fn(() => ({})), createLedgerActor: () => ({ sendICP: mockSendICP, }), }; }); const mockedSendToken = jest.fn(({ amount }) => ({ amount, })); const mockedTransferNFT = jest.fn(); const mockedICPunk = { 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_1.Principal.from('ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe'), desc: 'string', properties: [], }, }; const mockdeNFTCollection = { name: 'IC Punks', canisterId: 'qcg3w-tyaaa-aaaah-qakea-cai', standard: 'ICPunk', tokens: [mockedICPunk], }; const icpPrice = 4.29; dab_js_1.getTokenActor.mockReturnValue({ getMetadata: jest.fn(() => ({ fungible: { symbol: 'WTC', decimals: 5, name: 'Wrapped Cycles' }, })), getBalance: jest.fn(() => ({ value: '1000', decimals: 8, })), send: mockedSendToken, }); dab_js_1.getCachedUserNFTs.mockReturnValue(Promise.resolve([mockdeNFTCollection])); dab_js_1.getNFTActor.mockReturnValue({ transfer: mockedTransferNFT, }); 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) yield 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 { identity } = (0, account_2.createAccountFromMnemonic)(TEST_MNEMONIC, 0); const testWallet = new PlugWallet_1.default({ name: 'test', walletId: '0', orderNumber: 0, fetch: cross_fetch_1.default, network: new Network_1.Mainnet({}, cross_fetch_1.default), type: constants_1.Types.mnemonic, identity, }); 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.walletId)).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).toEqual(wallet.toJSON()); expect(state.password).toEqual(TEST_PASSWORD); const mnemonic = yield keyRing.getMnemonic(state.password); expect(bip39.validateMnemonic(mnemonic)).toEqual(true); })); 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).toEqual(wallet.toJSON()); const mnemonic = yield keyRing.getMnemonic(state.password); expect(mnemonic).toEqual(TEST_MNEMONIC); expect(state.password).toEqual(TEST_PASSWORD); expect(bip39.validateMnemonic(mnemonic)).toEqual(true); })); 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({ canisterId: '5ymop-yyaaa-aaaah-qaa4q-cai', standard: '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); })); }); 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.walletId); expect(keyRing.currentWalletId).toEqual(wallet.walletId); })); 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({ canisterId: '5ymop-yyaaa-aaaah-qaa4q-cai', standard: 'xtc', subaccount: '1', }); // register WTC to other subaccounts yield keyRing.registerToken({ canisterId: '5ymop-yyaaa-aaaah-qaa4q-cai', standard: 'xtc', subaccount: '2', }); // register WTC yield keyRing.registerToken({ canisterId: '5ymop-yyaaa-aaaah-qaa4q-cai', standard: 'xtc', subaccount: '2', }); // register WTC twice })); 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({ canisterId: 'test', standard: 'xtc' })).rejects.toEqual(new Error(errors_1.ERRORS.INVALID_CANISTER_ID)); yield expect(() => keyRing.registerToken({ canisterId: 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe', standard: 'xtc', })).rejects.toEqual(new Error(errors_1.ERRORS.INVALID_CANISTER_ID)); })); }); describe('get balance', () => { const balances = { 0: [ { amount: '1000', token: { canisterId: 'ryjl3-tyaaa-aaaaa-aaaba-cai', decimals: 8, name: 'ICP', standard: 'ICP', symbol: 'ICP', }, }, { amount: '1000', token: { canisterId: 'aanaa-xaaaa-aaaah-aaeiq-cai', decimals: 12, name: 'Cycles', standard: 'XTC', symbol: 'XTC', }, }, { amount: '1000', token: { canisterId: 'utozz-siaaa-aaaam-qaaxq-cai', decimals: 8, name: 'Wrapped ICP', standard: 'WICP', symbol: 'WICP', }, }, ], }; let walletsCreated = 0; const mockgetBalances = (wallet) => __awaiter(void 0, void 0, void 0, function* () { const randomBalance = BigInt(0); balances[wallet.walletNumber] = randomBalance; yield jest .spyOn(wallet, 'getBalances') .mockReturnValue(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, mockgetBalances); })); test('get default balance', () => __awaiter(void 0, void 0, void 0, function* () { expect(yield keyRing.getBalances()).toMatchObject(balances[0]); })); test('get specific balance', () => __awaiter(void 0, void 0, void 0, function* () { let ind = Math.round(Math.random() * (walletsCreated - 1)); if (ind === 0) ind++; expect(yield keyRing.getBalances({ subaccount: 'ind' })).toBe(balances[ind]); })); test('get error with invalid wallet numbers', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(keyRing.getBalances({ subaccount: '-2' })).rejects.toThrow(errors_1.ERRORS.INVALID_WALLET_NUMBER); yield expect(keyRing.getBalances({ subaccount: '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('get specific transactions', () => __awaiter(void 0, void 0, void 0, function* () { const ind = Math.round(Math.random() * (walletsCreated - 1)); expect(yield keyRing.getTransactions({ subaccount: 'ind', icpPrice })).toBe(transactions[ind]); })); test('get error with invalid wallet numbers', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(keyRing.getTransactions({ subaccount: '-2', icpPrice })).rejects.toThrow(errors_1.ERRORS.INVALID_WALLET_NUMBER); yield expect(keyRing.getTransactions({ subaccount: 'walletsCreated + 2', icpPrice })).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: to.toString(), amount: amount.toString(), canisterId: tokens_1.TOKENS.ICP.canisterId, }); 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: to.toString(), amount: amount.toString(), canisterId: tokens_1.TOKENS.ICP.canisterId, }); expect(dfx_1.createAgent).toHaveBeenCalled(); expect(mockedSendToken.mock.calls[0][0].amount).toEqual(amount); expect(mockedSendToken.mock.calls[0][0].to).toEqual(to); })); describe('nfts', () => { 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); })); it('should fetch NFTs correctly', () => __awaiter(void 0, void 0, void 0, function* () { const nfts = yield keyRing.getNFTs(); expect(nfts).toEqual([mockdeNFTCollection]); })); it('should fail to fetch NFTs on inexistant account', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(keyRing.getNFTs({ subaccount: '1' })).rejects.toThrow(errors_1.ERRORS.INVALID_WALLET_NUMBER); })); it('should transfer an NFT correctly', () => __awaiter(void 0, void 0, void 0, function* () { const nfts = (yield keyRing.getNFTs()) || []; const { tokens } = nfts[0]; const to = 'ogkan-uvha2-mbm2l-isqcz-odcvg-szdx6-qj5tg-ydzjf-qrwe2-lbzwp-7qe'; const transferred = yield keyRing.transferNFT({ token: tokens[0], to, standard: tokens[0].standard, }); expect(transferred).toMatchObject([]); expect(mockedTransferNFT).toHaveBeenCalled(); expect(mockedTransferNFT.mock.calls[0][0].toString()).toEqual(to); expect(mockedTransferNFT.mock.calls[0][1].toString()).toEqual(tokens[0].index.toString()); })); }); afterEach(() => { jest.clearAllMocks(); }); }); });