From edbdd513abdaa8ea2195861ec6c3e1ba92392552 Mon Sep 17 00:00:00 2001 From: Zakaria Lounes Date: Thu, 19 Sep 2024 22:45:11 +0200 Subject: [PATCH] ci: add chains update --- .github/workflows/update.yml | 41 ++++++ package-lock.json | 207 ++++++++++++++++++++++++++++- package.json | 11 +- scripts/chain-update.mjs | 235 +++++++++++++++++++++++++++++++++ scripts/utils/useChainList.mjs | 23 ++++ scripts/utils/useLoadJson.mjs | 5 + scripts/utils/useWriteFile.mjs | 9 ++ 7 files changed, 529 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/update.yml create mode 100644 scripts/chain-update.mjs create mode 100644 scripts/utils/useChainList.mjs create mode 100644 scripts/utils/useLoadJson.mjs create mode 100644 scripts/utils/useWriteFile.mjs diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml new file mode 100644 index 0000000..3df746e --- /dev/null +++ b/.github/workflows/update.yml @@ -0,0 +1,41 @@ +name: Update chains config + +on: + workflow_dispatch: + + jobs: + cron: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ ubuntu-latest ] + node: [ 20 ] + + steps: + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + + - name: Checkout 📡 + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Cache node_modules 💰 + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ matrix.os }}-node-v${{ matrix.node }}-deps-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} + + - name: Install Dependencies 🧬 + if: steps.cache.outputs.cache-hit != 'true' + run: yarn + + - name: Update chains + run: npm run update + env: + CI: true + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 diff --git a/package-lock.json b/package-lock.json index c80c237..dbc9281 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,212 @@ "packages": { "": { "name": "app-registry", - "version": "1.0.0" + "version": "1.0.0", + "hasInstallScript": true, + "devDependencies": { + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "22.5.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", + "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", + "dev": true, + "peer": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "peer": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } } } } diff --git a/package.json b/package.json index 659c9f0..6d26027 100644 --- a/package.json +++ b/package.json @@ -6,5 +6,14 @@ "type": "git", "url": "https://github.com/ezstaking/app-registry" }, - "private": true + "type": "module", + "private": true, + "scripts": { + "postinstall": "npm remove chain-registry 2>&1 && npm add chain-registry 2>&1", + "update": "NODE_OPTIONS='--experimental-specifier-resolution=node --loader ts-node/esm --experimental-modules' node scripts/chain-update.mjs" + }, + "devDependencies": { + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + } } diff --git a/scripts/chain-update.mjs b/scripts/chain-update.mjs new file mode 100644 index 0000000..fbcd595 --- /dev/null +++ b/scripts/chain-update.mjs @@ -0,0 +1,235 @@ +import useLoadJson from "./utils/useLoadJson.mjs"; +import useChainList from "./utils/useChainList.mjs"; +import useWriteFile from "./utils/useWriteFile.mjs"; + +let chains = []; + +const updateChain = async (env, network) => { + const registryChain = await useLoadJson(`./../../chains/${env}s/${network}/chain.json`); + + const { chain: remoteChain, assets: remoteAssets } = (await import(`chain-registry/${env}/${network}`)); + const remoteDenom = remoteChain.staking.staking_tokens[0].denom; + const remoteAsset = remoteAssets.assets.find((asset) => asset.base === remoteDenom); + const remoteDenomDetails = remoteAsset.denom_units.find((denomU) => denomU.denom === remoteAsset.display); + const remoteFeeToken = remoteChain.fees.fee_tokens.find((feeToken) => feeToken.denom === remoteDenom); + + // logo_URIs + if ( + registryChain.logo_URIs.png !== remoteChain.logo_URIs.png && + remoteChain.logo_URIs.png !== undefined + ) { + console.error(`${network} logo need to be updated (png)`); + registryChain.logo_URIs.png = remoteChain.logo_URIs.png; + } + if ( + registryChain.logo_URIs.svg !== remoteChain.logo_URIs.svg && + remoteChain.logo_URIs.svg !== undefined + ) { + console.error(`${network} logo need to be updated (svg)`); + registryChain.logo_URIs.svg = remoteChain.logo_URIs.svg; + } + + // chainId + if ( + registryChain.chainId !== remoteChain.chain_id && + remoteChain.chain_id !== undefined + ) { + console.error( + `${network} chainId need to be updated`, + registryChain.chainId, + remoteChain.chain_id + ); + registryChain.chainId = remoteChain.chain_id; + } + + // bech32 + if ( + registryChain.bech32 !== remoteChain.bech32_prefix && + remoteChain.bech32_prefix !== undefined + ) { + console.error( + `${network} bech32 need to be updated`, + registryChain.bech32, + remoteChain.bech32_prefix + ); + registryChain.bech32 = remoteChain.bech32_prefix; + } + + // denom + if ( + registryChain.denom !== remoteAsset.display && + remoteAsset.display !== undefined + ) { + console.error( + `${network} denom need to be updated`, + registryChain.denom, + remoteAsset.display + ); + registryChain.denom = remoteChain.display; + } + + // denomUpper + if ( + registryChain.denomUpper !== remoteAsset.symbol && + remoteAsset.symbol !== undefined + ) { + console.error( + `${network} denomUpper need to be updated`, + registryChain.denomUpper, + remoteAsset.symbol + ); + registryChain.denomUpper = remoteAsset.symbol; + } + + // sdenom + if ( + registryChain.sdenom !== remoteDenom && + remoteDenom !== undefined + ) { + console.error( + `${network} sdenom need to be updated`, + registryChain.sdenom, + remoteDenom + ); + registryChain.sdenom = remoteDenom; + } + + // coinType + if ( + registryChain.coinType !== remoteChain.slip44 && + remoteChain.slip44 !== undefined + ) { + console.error( + `${network} coinType need to be updated`, + registryChain.coinType, + remoteChain.slip44 + ); + registryChain.coinType = remoteChain.slip44; + } + + // gasPriceStep + if ( + registryChain.gasPriceStep.low !== remoteFeeToken.low_gas_price && + remoteFeeToken.low_gas_price !== undefined + ) { + console.error( + `${network} gasPriceStep.low need to be updated`, + registryChain.gasPriceStep.low, + remoteFeeToken.low_gas_price + ); + registryChain.gasPriceStep.low = remoteFeeToken.low_gas_price; + } + if ( + registryChain.gasPriceStep.average !== remoteFeeToken.average_gas_price && + remoteFeeToken.average_gas_price !== undefined + ) { + console.error( + `${network} gasPriceStep.average need to be updated`, + registryChain.gasPriceStep.average, + remoteFeeToken.average_gas_price + ); + registryChain.gasPriceStep.average = remoteFeeToken.average_gas_price; + } + if ( + registryChain.gasPriceStep.high !== remoteFeeToken.high_gas_price && + remoteFeeToken.high_gas_price !== undefined + ) { + console.error( + `${network} gasPriceStep.high need to be updated`, + registryChain.gasPriceStep.high, + remoteFeeToken.high_gas_price + ); + registryChain.gasPriceStep.high = remoteFeeToken.high_gas_price; + } + + // coinDecimals + if ( + registryChain.coinDecimals !== remoteDenomDetails.exponent && + remoteDenomDetails.exponent !== undefined + ) { + console.error( + `${network} coinDecimals need to be updated`, + registryChain.coinDecimals, + remoteDenomDetails.exponent + ); + registryChain.coinDecimals = remoteDenomDetails.exponent; + } + + // features + + // coinGeckoId + if ( + registryChain.coinGeckoId !== remoteAsset.coingecko_id && + remoteAsset.coingecko_id !== undefined + ) { + console.error( + `${network} coinGeckoId need to be updated`, + registryChain.coinGeckoId, + remoteAsset.coingecko_id + ); + registryChain.coinGeckoId = remoteAsset.coingecko_id; + } + + // chainInfo + if ( + `v${registryChain.chainInfo.cosmosSdkVersion}` !== remoteChain.codebase.cosmos_sdk_version && + remoteChain.codebase.cosmos_sdk_version !== undefined + ) { + console.error( + `${network} cosmosSdkVersion need to be updated`, + `v${registryChain.chainInfo.cosmosSdkVersion}`, + remoteChain.codebase.cosmos_sdk_version + ); + registryChain.chainInfo.cosmosSdkVersion = remoteChain.codebase.cosmos_sdk_version.substring(1); + } + if ( + `v${registryChain.chainInfo.ibcGoVersion}` !== remoteChain.codebase.ibc_go_version && + remoteChain.codebase.ibc_go_version !== undefined + ) { + console.error( + `${network} ibcGoVersion need to be updated`, + `v${registryChain.chainInfo.ibcGoVersion}`, + remoteChain.codebase.ibc_go_version + ); + registryChain.chainInfo.ibcGoVersion = remoteChain.codebase.ibc_go_version.substring(1); + } + + // links + if ( + registryChain.links[0].url !== remoteChain.website && + remoteChain.website !== undefined + ) { + console.error( + `${network} websiteUrl need to be updated`, + registryChain.links[0].url, + remoteChain.website + ); + registryChain.links[0].url = remoteChain.website; + } + + // isNativelySupportedByKeplr + + useWriteFile( + JSON.stringify(registryChain, null, 2) + "\n", + `./chains/${env}s/${network}/chain.json` + ); +} + +const updateChains = async (isMainnet) => { + chains = Object.keys(useChainList(isMainnet)); + + for (let i = 0; i < chains.length; i++) { + try { + await updateChain(isMainnet ? 'mainnet' : 'testnet', chains[i]); + } catch (_e) { + // console.error(e); + } + } +} + +const update = async () => { + await updateChains(true); + await updateChains(false); +} + +await update(); diff --git a/scripts/utils/useChainList.mjs b/scripts/utils/useChainList.mjs new file mode 100644 index 0000000..c0b9722 --- /dev/null +++ b/scripts/utils/useChainList.mjs @@ -0,0 +1,23 @@ +import * as fs from "fs"; +import {default as loadJson} from "./useLoadJson.mjs"; + +export default function (isMainnet) { + const env = isMainnet ? 'mainnets' : 'testnets'; + const files = fs.readdirSync(`./chains/${env}`).sort() + const data = {}; + + for (let i = 0; i < files.length; i++) { + if (["protocol.schema.json", "_template"].includes(files[i])) { + continue; + } + + const { + name, + chainName, + } = loadJson(`./../../chains/${env}/${files[i]}/chain.json`); + + data[name] = {chainName}; + } + + return data; +}; diff --git a/scripts/utils/useLoadJson.mjs b/scripts/utils/useLoadJson.mjs new file mode 100644 index 0000000..fcf0f20 --- /dev/null +++ b/scripts/utils/useLoadJson.mjs @@ -0,0 +1,5 @@ +import * as fs from "fs"; + +export default function (path) { + return JSON.parse(fs.readFileSync(new URL(path, import.meta.url))); +} diff --git a/scripts/utils/useWriteFile.mjs b/scripts/utils/useWriteFile.mjs new file mode 100644 index 0000000..d795452 --- /dev/null +++ b/scripts/utils/useWriteFile.mjs @@ -0,0 +1,9 @@ +import * as fs from "fs"; + +export default function (content, path) { + fs.writeFile(path, content, (err) => { + if (err) { + console.error(err); + } + }); +};