UNPKG

@trezor/connect

Version:

High-level javascript interface for Trezor hardware wallet.

316 lines 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const resolveAfter_1 = require("@trezor/utils/lib/resolveAfter"); const BlockchainLink_1 = require("../backend/BlockchainLink"); const constants_1 = require("../constants"); const AbstractMethod_1 = require("../core/AbstractMethod"); const coinInfo_1 = require("../data/coinInfo"); const events_1 = require("../events"); const Discovery_1 = require("./common/Discovery"); const paramsValidator_1 = require("./common/paramsValidator"); const accountUtils_1 = require("../utils/accountUtils"); const pathUtils_1 = require("../utils/pathUtils"); class GetAccountInfo extends AbstractMethod_1.AbstractMethod { disposed = false; hasBundle; discovery; init() { this.requiredPermissions = ['read']; this.useDevice = true; this.useUi = true; let willUseDevice = false; this.hasBundle = !!this.payload.bundle; const payload = !this.payload.bundle ? { ...this.payload, bundle: [this.payload] } : this.payload; (0, paramsValidator_1.validateParams)(payload, [{ name: 'bundle', type: 'array' }]); this.params = payload.bundle.map(batch => { (0, paramsValidator_1.validateParams)(batch, [ { name: 'coin', type: 'string', required: true }, { name: 'identity', type: 'string' }, { name: 'descriptor', type: 'string' }, { name: 'path', type: 'string' }, { name: 'details', type: 'string' }, { name: 'tokens', type: 'string' }, { name: 'page', type: 'number' }, { name: 'pageSize', type: 'number' }, { name: 'from', type: 'number' }, { name: 'to', type: 'number' }, { name: 'contractFilter', type: 'string' }, { name: 'gap', type: 'number' }, { name: 'marker', type: 'object' }, { name: 'defaultAccountType', type: 'string' }, { name: 'derivationType', type: 'number' }, { name: 'suppressBackupWarning', type: 'boolean' }, ]); const coinInfo = (0, coinInfo_1.getCoinInfo)(batch.coin); if (!coinInfo) { throw constants_1.ERRORS.TypedError('Method_UnknownCoin'); } (0, BlockchainLink_1.isBackendSupported)(coinInfo); let address_n = []; if (batch.path) { address_n = (0, pathUtils_1.validatePath)(batch.path, 3); willUseDevice = typeof batch.descriptor !== 'string'; } if (!batch.path && !batch.descriptor) { if (payload.bundle.length > 1) { throw Error('Discovery for multiple coins in not supported'); } willUseDevice = true; } this.firmwareRange = (0, paramsValidator_1.getFirmwareRange)(this.name, coinInfo, this.firmwareRange); return { ...batch, address_n, coinInfo, }; }); this.useDevice = willUseDevice; this.useDeviceState = willUseDevice; this.useUi = willUseDevice; this.noBackupConfirmationMode = this.params.every(batch => batch.suppressBackupWarning) ? 'popup-only' : 'always'; } get info() { return 'Export account info'; } get confirmation() { if (this.params.length === 1 && !this.params[0].path && !this.params[0].descriptor) { return { view: 'export-account-info', label: `Export info for ${this.params[0].coinInfo.label} account of your selection`, customConfirmButton: { label: 'Proceed to account selection', className: 'not-empty-css', }, }; } else { const keys = {}; this.params.forEach(b => { if (!keys[b.coinInfo.label]) { keys[b.coinInfo.label] = { coinInfo: b.coinInfo, values: [], }; } keys[b.coinInfo.label].values.push(b.descriptor || b.address_n); }); const str = []; Object.keys(keys).forEach((k, _i, _a) => { const details = keys[k]; details.values.forEach(acc => { str.push(k); str.push(' '); if (typeof acc === 'string') { str.push(acc); } else { str.push((0, accountUtils_1.getAccountLabel)(acc, details.coinInfo)); } }); }); return { view: 'export-account-info', label: `Export info for: ${str.join('')}`, }; } } checkFirmwareRange() { if (this.params.length === 1) { return super.checkFirmwareRange(); } const invalid = []; for (let i = 0; i < this.params.length; i++) { this.firmwareRange = (0, paramsValidator_1.getFirmwareRange)(this.name, this.params[i].coinInfo, AbstractMethod_1.DEFAULT_FIRMWARE_RANGE); const exception = super.checkFirmwareRange(); if (exception) { invalid.push({ index: i, exception, coin: this.params[i].coin, }); } } if (invalid.length > 0) { throw constants_1.ERRORS.TypedError('Method_Discovery_BundleException', JSON.stringify(invalid)); } } async run() { if (this.params.length === 1 && !this.params[0].path && !this.params[0].descriptor) { return this.discover(this.params[0]); } const responses = []; const sendProgress = (progress, response, error) => { if (!this.hasBundle || this.device?.getCurrentSession().isDisposed()) return; this.postMessage((0, events_1.createUiMessage)(events_1.UI.BUNDLE_PROGRESS, { total: this.params.length, progress, response, error, })); }; for (let i = 0; i < this.params.length; i++) { const request = this.params[i]; const { address_n } = request; let { descriptor } = request; let legacyXpub; let descriptorChecksum; if (this.disposed) break; if (address_n && typeof descriptor !== 'string') { try { const accountDescriptor = await this.device .getCommands() .getAccountDescriptor(request.coinInfo, address_n, request.derivationType); if (accountDescriptor) { descriptor = accountDescriptor.descriptor; legacyXpub = accountDescriptor.legacyXpub; descriptorChecksum = accountDescriptor.descriptorChecksum; } } catch (error) { if (this.hasBundle) { responses.push(null); sendProgress(i, null, error.message); continue; } else { throw error; } } } if (this.disposed) break; try { if (typeof descriptor !== 'string') { throw constants_1.ERRORS.TypedError('Runtime', 'GetAccountInfo: descriptor not found'); } const blockchain = await (0, BlockchainLink_1.initBlockchain)(request.coinInfo, this.postMessage, request.identity); if (this.disposed) break; const info = await blockchain.getAccountInfo({ descriptor, details: request.details, tokens: request.tokens, page: request.page, pageSize: request.pageSize, pageCursor: request.pageCursor, from: request.from, to: request.to, contractFilter: request.contractFilter, gap: request.gap, marker: request.marker, tokenAccountsPubKeys: request.tokenAccountsPubKeys, }); if (this.disposed) break; let utxo; if ((0, accountUtils_1.isUtxoBased)(request.coinInfo) && typeof request.details === 'string' && request.details !== 'basic') { utxo = await blockchain.getAccountUtxo(descriptor); } if (this.disposed) break; const account = { path: request.path, ...info, descriptor, legacyXpub, utxo, descriptorChecksum, }; responses.push(account); sendProgress(i, account); } catch (error) { if (this.hasBundle) { responses.push(null); sendProgress(i, null, error.message); continue; } else { throw error; } } } if (this.disposed) return new Promise(() => []); return this.hasBundle ? responses : responses[0]; } async discover(request) { const { coinInfo, identity, defaultAccountType, derivationType } = request; const blockchain = await (0, BlockchainLink_1.initBlockchain)(coinInfo, this.postMessage, identity); const dfd = this.createUiPromise(events_1.UI.RECEIVE_ACCOUNT); const discovery = new Discovery_1.Discovery({ blockchain, getDescriptor: path => this.device.getCommands().getAccountDescriptor(coinInfo, path, derivationType), }); discovery.on('progress', accounts => { this.postMessage((0, events_1.createUiMessage)(events_1.UI.SELECT_ACCOUNT, { type: 'progress', coinInfo, accounts, })); }); discovery.on('complete', () => { this.postMessage((0, events_1.createUiMessage)(events_1.UI.SELECT_ACCOUNT, { type: 'end', coinInfo, })); }); discovery.start().catch(error => { dfd.reject(error); }); this.postMessage((0, events_1.createUiMessage)(events_1.UI.SELECT_ACCOUNT, { type: 'start', accountTypes: discovery.types.map(t => t.type), defaultAccountType, coinInfo, })); const uiResp = await dfd.promise; discovery.stop(); const account = discovery.accounts[uiResp.payload]; if (!discovery.completed) { await (0, resolveAfter_1.resolveAfter)(501); } const info = await blockchain.getAccountInfo({ descriptor: account.descriptor, details: request.details, tokens: request.tokens, page: request.page, pageSize: request.pageSize, pageCursor: request.pageCursor, from: request.from, to: request.to, contractFilter: request.contractFilter, gap: request.gap, marker: request.marker, }); let utxo; if ((0, accountUtils_1.isUtxoBased)(coinInfo) && typeof request.details === 'string' && request.details !== 'basic') { utxo = await blockchain.getAccountUtxo(account.descriptor); } return { path: (0, pathUtils_1.getSerializedPath)(account.address_n), ...info, utxo, }; } dispose() { this.disposed = true; const { discovery } = this; if (discovery) { discovery.removeAllListeners(); discovery.stop(); } } } exports.default = GetAccountInfo; //# sourceMappingURL=getAccountInfo.js.map