forked from cosmos/chain-registry
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'cosmos:master' into master
- Loading branch information
Showing
547 changed files
with
21,057 additions
and
2,643 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
// Purpose: | ||
// to validate various data throughout the Chain Registry, prioritizing data that often gets missed by manual review | ||
// e.g., whether fee assets are registered to the chain's assetlist | ||
|
||
// -- THE PLAN -- | ||
// | ||
// read each chain's directory and files | ||
// read chain.json | ||
// read fee_tokens | ||
// check if fee token exists in the assetlist. | ||
// read staking | ||
// chaeck if staking token exists in the assetlist | ||
// | ||
|
||
import * as path from 'path'; | ||
import * as chain_reg from './chain_registry_local.mjs'; | ||
|
||
|
||
const chainIdMap = new Map(); | ||
|
||
|
||
function checkChainIdConflict(chain_name) { | ||
|
||
// Not concerned by conflicts with 'Killed' chains--could be a hard fork | ||
let chain_status = chain_reg.getFileProperty(chain_name, "chain", "status"); | ||
if (!chain_status || chain_status === "killed") { return; } | ||
|
||
let chain_id = chain_reg.getFileProperty(chain_name, "chain", "chain_id"); | ||
if (!chain_id) { return; } // must have a chainId | ||
if (chainIdMap.has(chain_id)) { | ||
let conflict_chain_name = chainIdMap.get(chain_id); | ||
throw new Error(`Duplicate chain ID for ${chain_name} found! Chain ID ${chain_id} is also claimed by ${conflict_chain_name}.`); | ||
} | ||
chainIdMap.set(chain_id, chain_name); | ||
|
||
} | ||
|
||
function checkFeeTokensAreRegistered(chain_name) { | ||
|
||
let fees = chain_reg.getFileProperty(chain_name, "chain", "fees"); | ||
fees?.fee_tokens?.forEach((fee_token) => { | ||
if (!fee_token.denom) { | ||
throw new Error(`One of ${chain_name}'s fee tokens does not have denom specified.`); | ||
} | ||
if (!chain_reg.getAssetProperty(chain_name, fee_token.denom, "base")) { | ||
throw new Error(`Chain ${chain_name} does not have fee token ${fee_token.denom} defined in its Assetlist.`); | ||
} | ||
}); | ||
|
||
} | ||
|
||
function checkStakingTokensAreRegistered(chain_name) { | ||
|
||
let staking = chain_reg.getFileProperty(chain_name, "chain", "staking"); | ||
staking?.staking_tokens?.forEach((staking_token) => { | ||
if (!staking_token.denom) { | ||
throw new Error(`One of ${chain_name}'s staking tokens does not have denom specified.`); | ||
} | ||
if (!chain_reg.getAssetProperty(chain_name, staking_token.denom, "base")) { | ||
throw new Error(`Chain ${chain_name} does not have staking token ${staking_token.denom} defined in its Assetlist.`); | ||
} | ||
}); | ||
|
||
} | ||
|
||
function checkDenomUnits(asset) { | ||
|
||
if (!asset.base) { return; } | ||
let VALID_BASE_UNIT; | ||
let VALID_DISPLAY_UNIT; | ||
asset.denom_units?.forEach((denom_unit) => { | ||
|
||
let denom_and_aliases = []; | ||
denom_and_aliases.push(denom_unit.denom); | ||
denom_unit.aliases?.forEach((alias) => { | ||
if (denom_and_aliases.includes(alias)) { return; } | ||
denom_and_aliases.push(alias); | ||
}); | ||
|
||
//find base unit | ||
if (denom_and_aliases.includes(asset.base)) { | ||
if (denom_unit.exponent !== 0) { | ||
throw new Error(`Base denomination ${asset.base} is not defined as having 0 exponent.`) | ||
} | ||
if (VALID_BASE_UNIT) { | ||
throw new Error(`Base denomination ${asset.base} refers to multiple denom_units.`); | ||
} | ||
VALID_BASE_UNIT = true; | ||
} | ||
|
||
//find display unit | ||
if (asset.display) { | ||
if (denom_and_aliases.includes(asset.display)) { | ||
if (VALID_DISPLAY_UNIT) { | ||
throw new Error(`Display denomination ${asset.display} refers to multiple denom_units.`); | ||
} | ||
VALID_DISPLAY_UNIT = true; | ||
} | ||
} | ||
|
||
//check if IBC hashes contain lowercase letters | ||
denom_and_aliases.forEach((denom) => { | ||
if (!denom.startsWith("ibc/")) { return; } | ||
const substring = denom.substring(4); | ||
if (substring.toUpperCase() !== substring) { | ||
throw new Error(`Denom ${denom} is an IBC hash denomination, yet contains lowercase letters after "ibc/"`); | ||
} | ||
}); | ||
|
||
}); | ||
|
||
if (!VALID_BASE_UNIT) { | ||
throw new Error(`Base denomination ${asset.base} is not defined as a denom_unit.`); | ||
} | ||
if (!VALID_DISPLAY_UNIT) { | ||
throw new Error(`Display denomination ${asset.display} is not defined as a denom_unit.`); | ||
} | ||
|
||
} | ||
|
||
|
||
export function validate_chain_files() { | ||
|
||
//get Chain Names | ||
const chainRegChains = chain_reg.getChains(); | ||
|
||
//iterate each chain | ||
chainRegChains.forEach((chain_name) => { | ||
|
||
//console.log(chain_name); | ||
|
||
//check if chain_id is registered by another chain | ||
checkChainIdConflict(chain_name); | ||
|
||
//check if all fee tokens are registered | ||
checkFeeTokensAreRegistered(chain_name); | ||
|
||
//check if all staking tokens are registered | ||
checkStakingTokensAreRegistered(chain_name); | ||
|
||
//get chain's assets | ||
const chainAssets = chain_reg.getFileProperty(chain_name, "assetlist", "assets"); | ||
|
||
//iterate each asset | ||
chainAssets?.forEach((asset) => { | ||
|
||
//check denom units | ||
checkDenomUnits(asset); | ||
|
||
}); | ||
|
||
|
||
}); | ||
|
||
} | ||
|
||
function main() { | ||
validate_chain_files(); | ||
} | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,27 @@ | ||
on: [pull_request, workflow_dispatch] | ||
name: PR Workflow | ||
name: Data Validation PR Workflow | ||
jobs: | ||
jobname: | ||
validate_zone_data: | ||
name: Validate Data | ||
runs-on: ubuntu-latest | ||
|
||
defaults: | ||
run: | ||
shell: bash | ||
|
||
steps: | ||
- name: checkout the repo | ||
uses: actions/checkout@v3 #Checks out the registry; sets up python | ||
|
||
- name: Set up Python | ||
uses: actions/setup-python@v3 | ||
|
||
- name: Checkout repository | ||
uses: actions/checkout@v2 | ||
with: | ||
python-version: 3.9 | ||
|
||
- name: Install Python dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
cd .github/workflows/utility | ||
- name: Run Data Validation python script | ||
shell: python | ||
run: | | ||
import sys | ||
sys.path.insert(1, '.github/workflows/utility') | ||
import validate_data | ||
validate_data.runAll() | ||
token: ${{ secrets.GITHUB_TOKEN }} | ||
submodules: true | ||
|
||
- name: Setup Node | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: 19.6.0 | ||
|
||
- name: Run code Node JS to Validate Data | ||
working-directory: ./.github/workflows/utility | ||
run: node validate_data.mjs |
Oops, something went wrong.