UNPKG

@ledgerhq/live-common

Version:
144 lines (124 loc) 4.14 kB
"use strict"; import "../../__tests__/test-helpers/environment"; // import path from "path"; // import fs from "fs/promises"; import allSpecs from "../../generated/specs"; import type { AppSpec } from "../types"; import { Account } from "@ledgerhq/types-live"; import { AppCandidate } from "@ledgerhq/ledger-wallet-framework/bot/types"; import { createSpeculosDevice, findAppCandidate, listAppCandidates, releaseSpeculosDevice, } from "../../load/speculos"; import { makeBridgeCacheSystem } from "../../bridge/cache"; import { getCurrencyBridge } from "../../bridge"; import { filter, map, reduce, timeout } from "rxjs/operators"; import { getEnv } from "@ledgerhq/live-env"; import { firstValueFrom, throwError } from "rxjs"; import { Report } from "./types"; import { toAccountRaw } from "../../account"; import { Audit } from "./audits"; main().then( r => { // eslint-disable-next-line no-console console.log(JSON.stringify(r)); process.exit(0); }, error => { // eslint-disable-next-line no-console console.log(JSON.stringify({ error: String(error) })); process.exit(0); }, ); async function main(): Promise<Report> { const report: Report = {}; const [family, key] = process.argv.slice(2); const spec: AppSpec<any> = allSpecs[family][key]; const { COINAPPS, SEED } = process.env; if (!COINAPPS) { throw new Error("COINAPPS env variable is required"); } if (!SEED) { throw new Error("SEED env variable is required"); } // Prepare speculos device simulator const appCandidates = await listAppCandidates(COINAPPS); const { appQuery, currency, dependency, onSpeculosDeviceCreated } = spec; const appCandidate = findAppCandidate(appCandidates, appQuery); if (!appCandidate) { console.warn("no app found for " + spec.name); console.warn(appQuery); console.warn(JSON.stringify(appCandidates, undefined, 2)); } if (!appCandidate) { throw new Error(`no app found for ${spec.name}. Are you sure your COINAPPS is up to date?`); } const deviceParams = { ...(appCandidate as AppCandidate), appName: spec.currency.managerAppName, seed: SEED, dependency, coinapps: COINAPPS, onSpeculosDeviceCreated, }; const device = await createSpeculosDevice(deviceParams); try { const audit = new Audit(); // We scan and synchronize the accounts const localCache = {}; const cache = makeBridgeCacheSystem({ saveData(c, d) { localCache[c.id] = d; return Promise.resolve(); }, getData(c) { return Promise.resolve(localCache[c.id]); }, }); const bridge = getCurrencyBridge(currency); const syncConfig = { paginationConfig: {}, }; await cache.prepareCurrency(currency); const accounts = await firstValueFrom( bridge .scanAccounts({ currency, deviceId: device.id, syncConfig, }) .pipe( filter(e => e.type === "discovered"), map(e => e.account), reduce<Account, Account[]>((all, a) => all.concat(a), []), timeout({ each: getEnv("BOT_TIMEOUT_SCAN_ACCOUNTS"), with: () => throwError(() => new Error("scan accounts timeout for currency " + currency.name)), }), ), ); audit.end(); const accountsRaw = JSON.stringify(accounts.map(a => toAccountRaw(a))); const preloadJSON = JSON.stringify(localCache); audit.setAccountsJSONSize(accountsRaw.length); audit.setPreloadJSONSize(preloadJSON.length); /* // TODO big data if (REPORT_FOLDER) { const accountsFile = path.join(REPORT_FOLDER, "accounts.json"); await fs.writeFile(accountsFile, accountsRaw); } */ report.refillAddress = accounts[0]?.freshAddress; report.accountBalances = accounts.map(a => a.balance.toString()); report.accountIds = accounts.map(a => a.id); report.accountOperationsLength = accounts.map(a => a.operations.length); report.auditResult = audit.result(); } finally { await releaseSpeculosDevice(device.id); } return report; }