Canonical registry for ZIGChain. Includes metadata for native, factory, and IBC tokens, auto-generating wallet-ready asset lists and dApps — with the tooling to validate them, verify them on-chain, and publish them to the upstream Cosmos Chain Registry so wallets and frontends render them correctly.
- Native base denoms (e.g.,
uzig) — manually added, maintainer-curated. - Factory tokens (
coin.{creator}.{subdenom}) — automatically discovered from the ZIGChain network. - IBC tokens (
ibc/{hash}) — manual whitelist; only verified, accepted assets are listed.
Assets live in assets/{native,factory,ibc}/*.json with a network suffix (zig.mainnet.json, zig.testnet.json). Validation is driven by Pydantic models in models/ that serve as the single source of truth; JSON schemas in schemas/ are auto-generated from them. The scripts/generate_chain_registry.py generator produces Cosmos-compatible assetlist.json outputs under generated/chain-registry/ which can be synced to the upstream Cosmos Chain Registry.
Assumes prerequisites are installed (see Prerequisites).
Factory token (automatically discovered — most common contributor path):
python3 scripts/import_factory_assets.py --network mainnet # 1. Auto-import
# Edit the generated file under assets/factory/ to add logo_uris + description
python3 scripts/validate_assets.py --network mainnet # 2. Validate
python3 scripts/verify_chain_denominations.py --network mainnet # 3. Verify on-chain
git checkout -b feat/add-<symbol> && git add -A && git commit && git push && gh pr createIBC token (hand-authored whitelist):
# Hand-author assets/ibc/<symbol>.<network>.json following the schema
python3 scripts/validate_assets.py --network mainnet
python3 scripts/verify_chain_denominations.py --network mainnet
git checkout -b feat/add-ibc-<symbol> && git add -A && git commit && git push && gh pr createNative asset additions are maintainer-only — open an issue first if you think a new native denom belongs here.
The full walkthrough below explains what each step does, what to expect, and what to do if something fails.
-
Python 3.9+ with a virtual environment:
python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt -
Optional
config.yamlfor custom RPC/API endpoints:cp config.example.yaml config.yaml # Edit networks.mainnet.{rpc,api} / networks.testnet.{rpc,api} if neededIf omitted, the scripts fall back to public Numia endpoints. See Endpoint configuration for details.
-
zigchaindbinary — only required for factory token contributors (the importer shells out tozigchaind q factory list-denom). Install from the ZIGChain node docs. Verify withwhich zigchaind. -
Git fork and remote wiring — fork this repo on GitHub, clone your fork, and add this repo as
upstream:git clone git@github.com:<your-user>/zigchain-registry.git cd zigchain-registry git remote add upstream git@github.com:ZIGChain/zigchain-registry.git
git fetch upstream && git checkout -b feat/add-<symbol> upstream/mainNever work directly on main. A branch per asset addition keeps PRs focused and reviewable.
If it fails: check git remote -v — upstream must point at ZIGChain/zigchain-registry.
Is your token minted via the ZIGChain x/factory module (denom looks like coin.{creator}.{subdenom})?
├── Yes → Step 4a (Factory)
└── No
├── Is it bridged via IBC from another chain (denom looks like ibc/{HASH})?
│ └── Yes → Step 4b (IBC)
└── Otherwise (a new native base denom)
└── Stop — native additions are maintainer-only. Open an issue first.
- Format: PNG required; SVG optional but recommended.
- Dimensions: square (1:1 aspect ratio).
- Size: maximum 250 KB per file.
- Location: drop the files directly in the
logos/directory (flat — no subdirectories). - Naming: use the asset's
asset_idorsymbolas the filename (e.g.,zigchain.png,stzig.svg).
The filename you choose must match the path in your asset file's logo_uris URL. For example, logos/mytoken.png → https://raw.githubusercontent.com/ZIGChain/zigchain-registry/main/logos/mytoken.png. A mismatch here is caught at CI time, not locally.
If the logo is too large or non-square: compress/crop to spec before committing. CI checks URL reachability (post-merge), not file dimensions (pre-commit).
python3 scripts/import_factory_assets.py --network mainnetWhat it does: queries zigchaind q factory list-denom (paginated), derives symbol / name / display_denom from the subdenom, and writes assets/factory/coin.{creator}.{subdenom}.{network}.json. Existing files are skipped unless you pass --overwrite. When re-importing with --overwrite, maintainer-edited fields like is_verified, description, logo_uris, and socials are preserved.
Expected output: one ✅ Created line per new asset, ⏭️ Skipped for existing files, and an ✅ Import complete summary with counts.
What you must edit afterward: open the generated file under assets/factory/ and add:
logo_uris.png(required) andlogo_uris.svg(optional) — pointing at your logos from Step 3.description— a short human description of the token.- Optional:
website,twitter, or other social links.
Leave is_verified alone. It stays false for new contributions. A maintainer flips it to true after review — see What Happens After You Open the PR.
If the script fails:
zigchaind: command not found— install the binary and re-run (--zigchaind-path /custom/pathoverrides PATH lookup).Network error— override endpoints viaconfig.yaml, or retry (the public Numia RPC is occasionally rate-limited).
IBC tokens are curated manually. Create assets/ibc/<symbol>.<network>.json following the IBC schema (schemas/asset.ibc.schema.json). Required fields:
network,asset_id,type: "ibc",symbol,name,decimals,display_denombase_denom: must matchibc/{HASH}(uppercase 64-char hex)hash: the IBC hash (without theibc/prefix)origin_chain: canonical chain name (e.g.,cosmoshub,osmosis,noble)origin_denom: the base denom on the origin chaintracesandchannels: IBC trace / channel metadata
Use an existing IBC asset (e.g., assets/ibc/atom.mainnet.json) as a template. The IBC hash is deterministic from the channel and origin denom — derive it with zigchaind q ibc-transfer denom-hash {trace} or the Cosmos IBC denom tool.
If protected-asset rules flag your PR (e.g., a USDC-symbol asset must originate from Noble): confirm the origin_chain matches the expected canonical source. See Protected external asset verification for the list.
Only ZIG exists today. Adding a new native base denom is a maintainer decision with chain-level implications. Open an issue instead of sending a PR.
python3 scripts/validate_assets.py --network mainnetWhat it does: loads every asset file, validates against the Pydantic models, checks cross-file integrity (no duplicate asset_id or base_denom within a network), and enforces protected-asset rules (factory tokens can't impersonate well-known symbols like USDC/USDT).
Expected output:
✅ All assets validated successfully for network 'mainnet'!
Protection validation: N assets checked, 0 violations, 0 warnings
Violations vs warnings:
- Violations block merge. Fix your asset file and re-run.
- Warnings are advisory (e.g., a factory token with a symbol similar to a protected asset like
USDCX). Mention the warning in your PR description; a maintainer will decide.
If it fails:
- Pydantic error listing a field → fix that field per the schema.
Duplicate asset_id/Duplicate base_denom→ another file already claims this identifier; pick a different one or confirm this isn't a duplicate submission.
python3 scripts/verify_chain_denominations.py --network mainnetFor testnet contributions, pass --network testnet.
What it does: queries the ZIGChain REST API (/cosmos/bank/v1beta1/supply and /zigchain/factory/denom) and reconciles your registry entry against what actually exists on-chain. Factory tokens with zero supply are handled via the factory module query; native and IBC tokens are checked against bank supply.
Expected output:
✅ All assets verified successfully for this network.
If it fails:
Network error/HTTP error— transient RPC issue. Retry, or override endpoints inconfig.yaml(see Endpoint configuration).- Your asset appears as missing on-chain — confirm you used the correct
base_denom, and that the token actually exists on the network you're targeting. IBC tokens must exist in bank supply; a not-yet-bridged token will fail here.
python3 scripts/generate_chain_registry.py --skip-syncWhat it does: walks assets/ + logos/, builds a Cosmos-compatible assetlist.json under generated/chain-registry/ for each network that has assets, and copies logos into the corresponding images/ folders.
Verified-only is the default. Since your new contribution has is_verified: false, it will not appear in the generated output until a maintainer flips the flag during review. Empty diffs here are expected — this is a preview of what would ship upstream today, not of what your PR proposes.
To preview your contribution locally anyway:
python3 scripts/generate_chain_registry.py --include-unverified --skip-syncThe --include-unverified flag must be paired with --skip-sync — unverified assets must never be synced upstream.
git add assets/ logos/
git commit -m "feat: add <symbol> factory asset"
git push -u origin feat/add-<symbol>
gh pr create --title "feat: add <symbol>" --body "..."Reference any protected-asset warnings from Step 5 in your PR description so the maintainer knows to review them explicitly.
Five workflows run on every PR:
| Workflow | What it checks |
|---|---|
Validate Assets (validate.yml) |
Pydantic validation + cross-file integrity + protected-asset rules. Same as scripts/validate_assets.py. |
Check Schema Generation (check-schema.yml) |
Ensures the JSON schemas in schemas/ are up-to-date with the Pydantic models. |
Verify Chain Denominations (Mainnet + Testnet) (verify-chain-denoms.yml) |
Registry ↔ on-chain reconciliation. Same as scripts/verify_chain_denominations.py. |
Check is_verified changes (check-is-verified.yml) |
Blocks PRs that flip is_verified: false → true without maintainer acknowledgment. For contributors this check should simply pass (you're not flipping anything). |
Tests (test.yml) |
Runs the full pytest suite. |
If a check fails after you push, read the failure log, fix locally, and push again — CI re-runs automatically.
A maintainer reviews your PR. If accepted, they set is_verified: true on your asset(s) in a follow-up commit. This flip requires explicit maintainer action — it cannot be done by a contributor without the check-is-verified.yml workflow blocking the PR.
Once merged and verified, your asset is eligible for inclusion in the upstream Cosmos Chain Registry. Maintainers batch verified additions and open sync PRs upstream periodically.
If you'd like to open the upstream PR yourself after your asset is verified, it's welcome — fork cosmos/chain-registry, apply the relevant files from this repo's generated/chain-registry/ output, and open a PR. Otherwise, it's handled for you.
Every asset file must include:
network—"mainnet"or"testnet".asset_id— deterministic identifier, lowercase.type—"native","factory", or"ibc".symbol,name,decimals,display_denom.denom_units— array with exponent0matchingbase_denomexactly, and an exponent matchingdecimalsfor the display unit.
Asset filenames must include the network suffix, e.g., zig.mainnet.json. Factory files must use the full denom to avoid creator-collisions: coin.{creator}.{subdenom}.{network}.json.
Example — native asset:
{
"network": "mainnet",
"asset_id": "zig",
"type": "native",
"symbol": "ZIG",
"name": "ZIGChain Native Token",
"description": "The native staking token of ZIGChain",
"decimals": 6,
"display_denom": "ZIG",
"base_denom": "uzig",
"denom_units": [
{ "denom": "uzig", "exponent": 0 },
{ "denom": "ZIG", "exponent": 6 }
],
"logo_uris": {
"png": "https://raw.githubusercontent.com/ZIGChain/zigchain-registry/main/logos/zigchain.png",
"svg": "https://raw.githubusercontent.com/ZIGChain/zigchain-registry/main/logos/zigchain.svg"
}
}The JSON schemas in schemas/ are auto-generated from the Pydantic models in models/. Never edit schemas/*.json by hand — changes will be overwritten on the next schema generation. To modify validation rules, update the Pydantic models and regenerate schemas (see the Maintainer Guide).
See Step 3. Key points:
- PNG required, SVG optional.
- Square (1:1), ≤ 250 KB.
- Flat directory:
logos/<filename>.{png,svg}. - Filename must match the path in
logo_urisURLs.
Factory tokens cannot impersonate well-known external assets. Configuration lives in config/protected_assets.json. Each entry defines:
symbol— the protected symbol (e.g.,USDC).name— the protected name (e.g.,USD Coin).allowed_types— which asset types may use this symbol (e.g.,["ibc"]for USDC).expected_origin_chains— for IBC assets using a protected symbol, the origin chain must be in this list (e.g., USDC fromnoble).similar_patterns— optional regex that flags close variants (e.g.,USDCX) as warnings.
Factory tokens with a protected symbol fail validation outright. IBC tokens with a protected symbol must originate from an expected chain, or they fail. Similar-symbol warnings surface in the validate_assets.py output for manual review.
Scripts that query ZIGChain nodes or REST APIs read endpoints from config.yaml. Endpoints are not hard-coded; they're resolved via the get_rpc_endpoint(network) and get_api_endpoint(network) functions in scripts/config.py.
Setup:
cp config.example.yaml config.yaml
# Edit the endpoints if you want to use custom RPCsnetworks.<network>.rpc— used byscripts/import_factory_assets.pyviazigchaind --node <rpc>.networks.<network>.api— used byscripts/verify_chain_denominations.pyfor REST queries.
config.yaml is git-ignored. If it's missing, scripts fall back to public Numia endpoints.
Assets from different networks live in the same directory tree, distinguished by their network field and filename suffix (*.mainnet.json, *.testnet.json). Generated outputs are written per-network:
- Mainnet:
generated/chain-registry/zigchain/and_non-cosmos/ethereum/. - Testnet:
generated/chain-registry/testnets/zigchaintestnet/andtestnets/_non-cosmos/ethereumtestnet/— only written when testnet assets exist.
Not for community contributors. The scripts in this section modify generated artifacts, change validation rules, or flip verification flags.
When you change a Pydantic model in models/, regenerate the JSON schemas:
python3 scripts/generate_schemas.pyExpected output: one ✅ Generated <filename> line per schema, then ✅ All schemas generated successfully!.
The check-schema.yml CI workflow fails if this was forgotten.
A dry-run lint that reports how many existing assets would break under a proposed stricter ruleset (channel-pattern regex, transfer/ prefix, length caps, etc.):
python3 scripts/audit_strictness.pyExpected output (clean): ✅ No issues found — all assets are compatible with proposed strict rules.
Exit code 1 means at least one asset would break — inspect the report before tightening the model.
is_verified: true indicates a human maintainer has vetted the asset. Flipping false → true is the only contributor-disallowed action in this repo. The check-is-verified.yml CI workflow enforces this.
Bypass token: include the literal string [allow-verified] anywhere in a commit message in the PR range to authorize the flip. Use this deliberately — it's a conscious acknowledgment that the flip is maintainer-approved.
The workflow's underlying logic. Diffs BASE_SHA..HEAD_SHA for assets/**/*.json and fails if any file flips is_verified from false/missing to true without the bypass token.
Exit codes: 0 pass, 1 violation, 2 script error.
After verified assets are merged here, sync to the upstream fork with:
python3 scripts/generate_chain_registry.py \
--upstream-repo cosmos/chain-registry \
--fork-repo ZIGChain/chain-registryThis clones the fork, copies the generated assetlist.json + images/ into place, pushes a branch, and prints a PR URL. Pair with --git-no-prompt / --git-env-file for CI usage. Use --skip-sync for local dry-runs (no git operations).
zigchain-registry/
├── README.md
├── requirements.txt # Python dependencies
├── config.example.yaml # Copy to config.yaml for custom endpoints
├── models/ # Pydantic models (single source of truth)
│ ├── base.py
│ ├── native.py
│ ├── factory.py
│ └── ibc.py
├── schemas/ # Auto-generated JSON schemas — do not edit
├── assets/
│ ├── native/ # Native asset JSONs (ZIG only)
│ ├── factory/ # Factory token JSONs (auto-discovered)
│ └── ibc/ # IBC token JSONs (manual whitelist)
├── config/
│ └── protected_assets.json # Symbols that can't be impersonated
├── logos/ # Flat directory of PNG/SVG logos
├── generated/
│ └── chain-registry/ # Generated Cosmos assetlists (per-network)
├── scripts/
│ ├── validate_assets.py # Pydantic + integrity + protection
│ ├── import_factory_assets.py # Auto-import factory tokens
│ ├── verify_chain_denominations.py # Registry ↔ on-chain reconciliation
│ ├── generate_chain_registry.py # Build Cosmos chain-registry output
│ ├── generate_schemas.py # Regenerate schemas from models
│ ├── audit_strictness.py # Dry-run strictness audit
│ ├── config.py # Endpoint resolution module
│ └── ci/
│ └── check_is_verified.py # CI guard for the is_verified flip
└── .github/workflows/ # validate, check-schema, verify-chain-denoms,
# check-is-verified, test
Apache License 2.0 — see LICENSE.