diff --git a/script/generic/asset-infos.ts b/script/generic/asset-infos.ts index 0350183cc..ff0febd08 100644 --- a/script/generic/asset-infos.ts +++ b/script/generic/asset-infos.ts @@ -4,12 +4,9 @@ import { getChainAssetsPath, getChainAssetInfoPath } from "./repo-structure"; -import { - readFileSync, - isPathExistsSync -} from "./filesystem"; +import { isPathExistsSync } from "./filesystem"; import { arrayDiff } from "./types"; -import { isValidJSON } from "../generic/json"; +import { isValidJSON, readJsonFile, writeJsonFile } from "../generic/json"; import { ActionInterface, CheckStepInterface } from "../generic/interface"; import { CoinType } from "@trustwallet/wallet-core"; import * as bluebird from "bluebird"; @@ -24,7 +21,9 @@ function isAssetInfoHasAllKeys(info: unknown, path: string): [boolean, string] { return [hasAllKeys, `Info at path '${path}' missing next key(s): ${arrayDiff(requiredKeys, infoKeys)}`]; } -function isAssetInfoValid(info: unknown, path: string, address: string, chain: string): [string, string] { +// return error, warning, and fixed into if applicable +function isAssetInfoValid(info: unknown, path: string, address: string, chain: string, checkOnly: boolean): [string, string, unknown?] { + let fixedInfo: unknown|null = null; const isKeys1CorrectType = typeof info['name'] === "string" && info['name'] !== "" && typeof info['type'] === "string" && info['type'] !== "" && @@ -33,15 +32,24 @@ function isAssetInfoValid(info: unknown, path: string, address: string, chain: s typeof info['status'] === "string" && info['status'] !== "" ; if (!isKeys1CorrectType) { - return [`Check keys1 '${info['name']}' '${info['type']}' '${info['symbol']}' '${info['decimals']}' '${info['id']}' ${path}`, ""]; + return [`Check keys1 '${info['name']}' '${info['type']}' '${info['symbol']}' '${info['decimals']}' '${info['id']}' ${path}`, "", fixedInfo]; } - if (typeof info['type'] !== "string" || chainFromAssetType(info['type']) !== chain ) { - return [`Incorrect type '${info['type']}' '${chain}' '${path}`, ""]; + // type + if (typeof info['type'] !== "string") { + return [`Incorrect type for type '${info['type']}' '${chain}' '${path}`, "", fixedInfo]; } - - if (typeof info['id'] !== "string" || info['id'] !== address ) { - return [`Incorrect id '${info['id']}' '${path}`, ""]; + if (chainFromAssetType(info['type'].toUpperCase()) !== chain ) { + return [`Incorrect value for type '${info['type']}' '${chain}' '${path}`, "", fixedInfo]; + } + if (info['type'] !== info['type'].toUpperCase()) { + // type is correct value, but casing is wrong, fix + if (checkOnly) { + return ["", `Wrong casing for type '${info['type']}' '${chain}' '${path}`, fixedInfo]; + } + // fix + if (!fixedInfo) { fixedInfo = info; } + fixedInfo['type'] = info['type'].toUpperCase(); } const isKeys2CorrectType = @@ -50,19 +58,19 @@ function isAssetInfoValid(info: unknown, path: string, address: string, chain: s typeof info['website'] === "string" && (info['description'] === "-" || info['website'] !== "") && typeof info['explorer'] === "string" && info['explorer'] != ""; if (!isKeys2CorrectType) { - return [`Check keys2 '${info['description']}' '${info['website']}' '${info['explorer']}' ${path}`, ""]; + return [`Check keys2 '${info['description']}' '${info['website']}' '${info['explorer']}' ${path}`, "", fixedInfo]; } if (info['description'].length > 500) { const msg = `Description too long, ${info['description'].length}, ${path}`; - return ["", msg]; + return [msg, "", fixedInfo]; } - return ["", ""]; + return ["", "", fixedInfo]; } export function chainFromAssetType(type: string): string { - switch (type.toUpperCase()) { + switch (type) { case "ERC20": return "ethereum"; case "BEP2": return "binance"; case "BEP20": return "smartchain"; @@ -80,6 +88,7 @@ export function chainFromAssetType(type: string): string { case "NRC20": return "nuls"; case "VET": return "vechain"; case "ONTOLOGY": return "ontology"; + default: return ""; } } @@ -153,7 +162,8 @@ function explorerUrlAlternatives(chain: string, contract: string, name: string): return altUrls; } -function isAssetInfoOK(chain: string, address: string, errors: string[], warnings: string[]): void { +// Check the an assets's info.json; for errors/warning. Also does fixes in certain cases +function isAssetInfoOK(chain: string, address: string, errors: string[], warnings: string[], checkOnly: boolean): void { const assetInfoPath = getChainAssetInfoPath(chain, address); if (!isPathExistsSync(assetInfoPath)) { // Info file doesn't exist, no need to check @@ -166,20 +176,26 @@ function isAssetInfoOK(chain: string, address: string, errors: string[], warning return; } - const info = JSON.parse(readFileSync(assetInfoPath)); + let info: unknown = readJsonFile(assetInfoPath); + let fixedInfo: unknown|null = null; + const [hasAllKeys, msg1] = isAssetInfoHasAllKeys(info, assetInfoPath); if (!hasAllKeys) { console.log(msg1); errors.push(msg1); } - const [err2, warn2] = isAssetInfoValid(info, assetInfoPath, address, chain); + const [err2, warn2, fixedInfo2] = isAssetInfoValid(info, assetInfoPath, address, chain, checkOnly); if (err2) { errors.push(err2); } if (warn2) { warnings.push(warn2); } + if (fixedInfo2 && !checkOnly) { + info = fixedInfo2; + fixedInfo = fixedInfo2; + } const hasExplorer = Object.prototype.hasOwnProperty.call(info, 'explorer'); if (!hasExplorer) { @@ -205,6 +221,11 @@ function isAssetInfoOK(chain: string, address: string, errors: string[], warning } } } + + if (fixedInfo && !checkOnly) { + writeJsonFile(assetInfoPath, fixedInfo); + console.log(`Done fixes to info.json, ${assetInfoPath}`); + } } export class AssetInfos implements ActionInterface { @@ -224,7 +245,7 @@ export class AssetInfos implements ActionInterface { const assetsList = getChainAssetsList(chain); //console.log(` Found ${assetsList.length} assets for chain ${chain}`); await bluebird.each(assetsList, async (address) => { - isAssetInfoOK(chain, address, errors, warnings); + isAssetInfoOK(chain, address, errors, warnings, true); }); return [errors, warnings]; } @@ -234,4 +255,18 @@ export class AssetInfos implements ActionInterface { }); return steps; } + + async consistencyFix(): Promise { + bluebird.each(allChains, async chain => { + // only if there is no assets subfolder + if (isPathExistsSync(getChainAssetsPath(chain))) { + const errors: string[] = []; + const warnings: string[] = []; + const assetsList = getChainAssetsList(chain); + await bluebird.each(assetsList, async (address) => { + isAssetInfoOK(chain, address, errors, warnings, false); + }); + } + }); + } } diff --git a/script/generic/interface.ts b/script/generic/interface.ts index f7a0c5ba5..c64af33a6 100644 --- a/script/generic/interface.ts +++ b/script/generic/interface.ts @@ -14,8 +14,8 @@ export interface ActionInterface { getConsistencyChecks?(): CheckStepInterface[]; sanityFix?(): Promise; consistencyFix?(): Promise; - updateAuto?(): Promise; // For regular automatic updates - updateManual?(): Promise; // For occasional manual updates + updateAuto?(): Promise; // For regular automatic updates (from external source) + updateManual?(): Promise; // For occasional manual updates (from external source) } export enum FixCheckMode { diff --git a/script/generic/update-all.ts b/script/generic/update-all.ts index 0b31dc1ff..237995c8a 100644 --- a/script/generic/update-all.ts +++ b/script/generic/update-all.ts @@ -170,7 +170,7 @@ async function consistencyFixByList(actions: ActionInterface[]) { await bluebird.each(actions, async (action) => { try { if (action.consistencyFix) { - console.log(`Sanity fix '${action.getName()}':`); + console.log(`Consistency fix '${action.getName()}':`); await action.consistencyFix(); } } catch (error) {