Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: validate chains and warp routes, change jobs to run on main #457

Merged
merged 9 commits into from
Jan 6, 2025
6 changes: 6 additions & 0 deletions .changeset/afraid-lamps-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@hyperlane-xyz/registry': patch
---

Warp Routes: add logoURI for tokens that did not have it and rename chain names that were not sorted alphabetically
Chains: Add missing deployer field
6 changes: 4 additions & 2 deletions .github/workflows/combine.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
name: combine

on:
pull_request:
push:
branches:
- main
# Allows you to run this workflow manually
workflow_dispatch:

Expand Down Expand Up @@ -56,7 +58,7 @@ jobs:
CHANGES=$(git status -s)
if [[ ! -z $CHANGES ]]; then
git add .
git commit -m "Update chain metadata and address files"
git commit -m "Update chain metadata and address files [skip-ci]"
git push
else
echo "No changes to commit."
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/optimize-svg.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
name: optimize-svg

on:
pull_request:
push:
branches:
- main
# Allows you to run this workflow manually
workflow_dispatch:

Expand Down Expand Up @@ -50,7 +52,7 @@ jobs:
CHANGES=$(git status -s)
if [[ ! -z $CHANGES ]]; then
git add .
git commit -m "Optimize SVG files"
git commit -m "Optimize SVG files [skip-ci]"
git push
else
echo "No changes to commit."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: validate-files

Xaroz marked this conversation as resolved.
Show resolved Hide resolved
on:
push:
branches: ["main"]
branches: ['main']
pull_request:
# Allows you to run this workflow manually
workflow_dispatch:
Expand Down Expand Up @@ -43,3 +43,7 @@ jobs:
- name: validate-svg
run: |
node ./scripts/validate-svg.js

- name: validate-file-data
run: |
node ./scripts/validate-file-data.js
2 changes: 1 addition & 1 deletion chains/metertestnet/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ blockExplorers:
name: Meter Testnet Explorer
url: https://scan.meter.io/
chainId: 83
deployers:
deployer:
name: JaunePomme
url: https://github.com/JaunePomme
displayName: Meter testnet
Expand Down
3 changes: 3 additions & 0 deletions chains/u2utestnet/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ blockExplorers:
name: u2uscan
url: https://testnet.u2uscan.xyz
chainId: 2484
deployer:
name: junayedmh
url: https://github.com/JunayedMh
displayName: U2U Testnet
domainId: 2484
isTestnet: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ tokens:
- token: ethereum|polygon|0x93b637AEA6a0dF51E8E24E49C62da34f616491c5
- token: ethereum|prom|0xd9c95e2ad330E11D7Dfa58f18504049f625E955e
decimals: 6
logoURI: /deployments/warp_routes/USDC/logo.svg
name: USD Coin
standard: EvmHypCollateral
symbol: USDC
Expand Down
2 changes: 2 additions & 0 deletions deployments/warp_routes/USDC/bsc-polygon-prom-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tokens:
- token: ethereum|polygon|0xFDf46770Da4F907c09aEd92299552DC9c7996d99
- token: ethereum|prom|0x424712Bec7c94a0F804c50F77B641A24F33A138e
decimals: 18
logoURI: /deployments/warp_routes/USDC/logo.svg
name: USD Coin
standard: EvmHypCollateral
symbol: USDC
Expand All @@ -16,6 +17,7 @@ tokens:
- token: ethereum|bsc|0x647eeD57dFDd335f9B6f2a9DbDFe09f166b1AdaC
- token: ethereum|prom|0x424712Bec7c94a0F804c50F77B641A24F33A138e
decimals: 18
logoURI: /deployments/warp_routes/USDC/logo.svg
name: USD Coin
standard: EvmHypSynthetic
symbol: USDC
Expand Down
2 changes: 2 additions & 0 deletions deployments/warp_routes/USDT/bsc-polygon-prom-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tokens:
- token: ethereum|polygon|0xd9765D5fE176493808202e63E6B73b523D6A1C3A
- token: ethereum|prom|0xDf6C58ec668daB037373BC49215722c2b0664484
decimals: 18
logoURI: /deployments/warp_routes/USDT/logo.svg
name: Tether USD
standard: EvmHypCollateral
symbol: USDT
Expand All @@ -16,6 +17,7 @@ tokens:
- token: ethereum|bsc|0x74e19D0c1828be422dDCd367a6ADa8CA7003d1a9
- token: ethereum|prom|0xDf6C58ec668daB037373BC49215722c2b0664484
decimals: 18
logoURI: /deployments/warp_routes/USDT/logo.svg
name: Tether USD
standard: EvmHypSynthetic
symbol: USDT
Expand Down
5 changes: 5 additions & 0 deletions scripts/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fs from 'fs';
import path from 'path';
import { parse as yamlParse } from 'yaml';

function findFiles(directory, fileTypes = [], isRecursive = true) {
const files = fs.readdirSync(directory);
Expand Down Expand Up @@ -32,3 +33,7 @@ export function getFilePaths(directories = [], fileTypes = [], isRecursive = tru
})
.flatMap((directory) => findFiles(directory, fileTypes, isRecursive));
}

export function readYaml(filePath) {
return yamlParse(fs.readFileSync(filePath, 'utf-8'));
}
182 changes: 182 additions & 0 deletions scripts/validate-file-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import fs from 'fs';
import path from 'path';
import { readYaml } from './utils.js';

const chainsDir = './chains';
const warpRoutesDir = './deployments/warp_routes';

// chains errors
const missingDeployerField = [];
const invalidTestnetChains = [];

// warp routes errors
const noConfigFileError = [];
const noLogoFileError = [];
const logoURIError = [];
const unorderedChainNamesError = [];

function validateChains() {
if (!fs.existsSync(chainsDir)) {
console.error(`Directory does not exist: ${chainsDir}`);
return;
}

const entries = fs.readdirSync(chainsDir, { withFileTypes: true });

entries.forEach((entry) => {
if (entry.isDirectory()) {
Xaroz marked this conversation as resolved.
Show resolved Hide resolved
const entryPath = path.join(chainsDir, entry.name);
const addressesPath = path.join(entryPath, 'addresses.yaml');
const metadataPath = path.join(entryPath, 'metadata.yaml');

if (fs.existsSync(metadataPath)) {
Xaroz marked this conversation as resolved.
Show resolved Hide resolved
// if addresses.yaml exists, check if deployer field is missing in metadata.yaml
const metadata = readYaml(metadataPath);
if (fs.existsSync(addressesPath)) {
if (!('deployer' in metadata)) {
Xaroz marked this conversation as resolved.
Show resolved Hide resolved
missingDeployerField.push(metadataPath);
}
}

// check if isTestNet is set properly for chains that could be testnets
// PD: this only works to check chains that have "test" on their name
if ('name' in metadata && metadata['name'].includes('test')) {
if (!('isTestnet' in metadata) || !metadata['isTestnet']) {
invalidTestnetChains.push(metadataPath);
}
}
}
Xaroz marked this conversation as resolved.
Show resolved Hide resolved
}
});
}

// This regex will make sure that we can split the filename when it contains the words
// addresses or config that way we can grab all the chain names and exclude these words
const filenameRegex = /^([\w-]+)-(addresses|config)\.yaml$/;

// check if chain names in warp routes are ordered alphabetically
function validateChainNameOrder(entryPath) {
Xaroz marked this conversation as resolved.
Show resolved Hide resolved
const yamlFiles = fs.readdirSync(entryPath).filter((file) => file.includes('.yaml'));

yamlFiles.forEach((filename) => {
const match = filename.match(filenameRegex);
const filePath = path.join(entryPath, filename);

if (match) {
Xaroz marked this conversation as resolved.
Show resolved Hide resolved
const chains = match[1].split('-');

for (let i = 0; i < chains.length - 1; i++) {
// Combine conditions: skip comparison for the last word
if (i !== chains.length - 1 && chains[i] > chains[i + 1]) {
unorderedChainNamesError.push(filePath);
return;
}
}
}
});
}

function validateConfigFiles(entryPath) {
//Search for config files
const configFiles = fs.readdirSync(entryPath).filter((file) => file.includes('-config.yaml'));

if (configFiles.length === 0) {
noConfigFileError.push(entryPath);
return;
}

// Search and parse the config files in the current directory
// For each entry, find if field logoURI is missing
configFiles.forEach((configFile) => {
Xaroz marked this conversation as resolved.
Show resolved Hide resolved
const configFilePath = path.join(entryPath, configFile);
const configData = readYaml(configFilePath);

let foundLogoURIs = 0;

if ('tokens' in configData) {
configData.tokens.forEach((token) => {
if (!('logoURI' in token)) {
foundLogoURIs++;
}
});

// if no entry found, skip check
if (foundLogoURIs === 0) return;

// otherwise all tokens must contain logoURI,
if (foundLogoURIs !== configData.tokens.length) logoURIError.push(configFilePath);
}
});
}

function validateWarpRoutes() {
if (!fs.existsSync(warpRoutesDir)) {
console.error(`Directory does not exist: ${warpRoutesDir}`);
return;
}

const entries = fs.readdirSync(warpRoutesDir, { withFileTypes: true });

entries.forEach((entry) => {
if (entry.isDirectory()) {
const entryPath = path.join(warpRoutesDir, entry.name);

// check if logo file exists
const logoFile = fs.readdirSync(entryPath).find((file) => file.includes('logo'));
if (!logoFile) noLogoFileError.push(entryPath);

validateConfigFiles(entryPath);
validateChainNameOrder(entryPath);
}
});
}

function validateErrors() {
const errorCount =
missingDeployerField.length +
invalidTestnetChains.length +
noConfigFileError.length +
noLogoFileError.length +
logoURIError.length +
unorderedChainNamesError.length;

if (errorCount === 0) return;

console.error(`Number of errors found: ${errorCount}`);

if (missingDeployerField.length > 0)
console.error(
'Error: Chain contains addresses.yaml but missing deployer field in metadata.yaml for the following paths:',
missingDeployerField,
);

if (invalidTestnetChains.length > 0)
console.error(
'Error: Chain contains "test" on its name but isTestNet is not set to "true" for the following paths:',
invalidTestnetChains,
);

if (noConfigFileError.length > 0)
console.error('Error: no config file at paths:', noConfigFileError);

if (noLogoFileError.length > 0) console.error('Error: logo file missing at:', noLogoFileError);

if (logoURIError.length > 0)
console.error('Error: All tokens must contain logoURI field:', logoURIError);

if (unorderedChainNamesError.length > 0)
console.error(
'Error: Chain names not ordered alphabetically at paths:',
unorderedChainNamesError,
);

process.exit(1);
}

function main() {
validateChains();
validateWarpRoutes();
validateErrors();
}

main();
21 changes: 6 additions & 15 deletions scripts/validate-svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,12 @@ function isValidSvg(filePath) {
const stats = fs.statSync(filePath);
const fileSize = (stats.size / 1024).toFixed(2);

if (!fileName.endsWith('logo.svg')) {
invalidNameSVGs.push(filePath);
}
if (!fileName.endsWith('logo.svg')) invalidNameSVGs.push(filePath);

if (stats.size > MAX_FILE_SIZE) {
invalidSizeSVGs.push({ filePath, fileSize: `${fileSize}KBs` });
}
if (stats.size > MAX_FILE_SIZE) invalidSizeSVGs.push({ filePath, fileSize: `${fileSize}KBs` });

const fileContent = fs.readFileSync(filePath, 'utf8');
if (RASTER_IMAGE_REGEX.test(fileContent)) {
rasterImgSVGs.push(filePath);
}
if (RASTER_IMAGE_REGEX.test(fileContent)) rasterImgSVGs.push(filePath);
}

function validateErrors() {
Expand All @@ -35,23 +29,20 @@ function validateErrors() {

console.error(`Number of errors found: ${errorCount}`);

if (invalidNameSVGs.length > 0) {
if (invalidNameSVGs.length > 0)
console.error(
"Error: Files do not end with 'logo.svg' in the following paths:",
invalidNameSVGs,
);
}

if (invalidSizeSVGs.length > 0) {
if (invalidSizeSVGs.length > 0)
console.error('Error: Files size exceed 100KBs in:', invalidSizeSVGs);
}

if (rasterImgSVGs.length > 0) {
if (rasterImgSVGs.length > 0)
console.error(
'Error: Files contain an <image> tag, likely embedding a raster image in the following paths:',
rasterImgSVGs,
);
}

process.exit(1);
}
Expand Down
Loading