What this does: Give it an Injective wallet address (or several). It gives you back a CSV listing every CW20 token that wallet holds, with name, symbol, balance, and contract address. Open the CSV in Excel or Google Sheets.
Why you might need it: Most Injective wallet apps and explorers show "bank" balances (INJ, USDT, peggy/IBC tokens, TokenFactory). They don't always show CW20 holdings, because CW20 token balances live inside smart contracts, not in the main account ledger. This tool fetches them.
A working example — this wallet holds nINJ, NONJA, hINJ, and Pedro. Run the tool and you get them in a CSV.
If Node.js is on your computer, this is all you need:
npx -y github:ckhbtc/cw20-balances inj1zud3rrh3jlfrn4rlqszlxp6yq5vmlaz6ycgp8s
Replace the inj1... part with the wallet you care about. It writes a file called balances.csv in the folder you ran it from. Open it in Excel.
That's it.
You only need to do this once.
- Go to https://nodejs.org/ and download the LTS version for your operating system (Mac, Windows, or Linux).
- Run the installer, click through with defaults.
- Open your terminal:
- Mac: ⌘+Space, type "Terminal", press Enter.
- Windows: Start menu → "Command Prompt" or "PowerShell".
- Type
node --versionand press Enter. If you see something likev20.11.0, you're good. - Now run the one-line command from the section above.
Each row is one token holding. Columns:
| column | what it means |
|---|---|
wallet_address |
The Injective wallet you queried. |
contract_address |
The CW20 contract address on-chain (inj1...). |
symbol |
Ticker, e.g. NONJA, hINJ. |
name |
Full token name, e.g. Hydro Wrapped INJ. |
decimals |
How many decimal places the token uses (matters for reading balances). |
balance_raw |
The raw on-chain integer balance. Ignore unless you need exact precision. |
balance_human |
The balance in normal human numbers — this is the one to read. |
factory_denom |
Internal "wrapped" denom. Usually ignore. |
coingecko_id |
The token's CoinGecko ID, when known. Useful if you want to look up a price. |
A note on Excel: Excel may display very long decimals in scientific notation (1.23E+24). If that happens, select the column → Format Cells → Number → set decimal places. Or just look at balance_human.
Check several wallets in one go. Just list them:
npx -y github:ckhbtc/cw20-balances inj1abc... inj1xyz... inj1qrs...
The CSV will have rows for all wallets, with wallet_address telling you which is which.
Check a long list of wallets. Make a plain text file wallets.txt with one address per line (blank lines and comments are fine — the tool just looks for inj1...):
npx -y github:ckhbtc/cw20-balances --file wallets.txt
Save to a specific filename:
npx -y github:ckhbtc/cw20-balances inj1abc... -o jan-snapshot.csv
Include zero-balance entries (by default, only tokens with a non-zero balance show up):
npx -y github:ckhbtc/cw20-balances --include-zero inj1abc...
Paste an injscan URL (the address is extracted automatically):
npx -y github:ckhbtc/cw20-balances "https://injscan.com/account/inj1zud3rrh3jlfrn4rlqszlxp6yq5vmlaz6ycgp8s/cw20/"
Show all options:
npx -y github:ckhbtc/cw20-balances --help
node: command not found— Node.js isn't installed. See "If you don't have Node.js yet" above.error: ... is not an Injective address— Injective addresses always start withinj1. Double-check you copied the whole thing.- Empty CSV (only the header row) — The wallet has no CW20 token holdings. Run again with
--include-zeroto see if any zero-balance entries exist. - The numbers in Excel look weird (
1.23E+24) — Excel is auto-formatting big numbers. Select the column, change the format to Number with enough decimal places, or just readbalance_humaninstead ofbalance_raw.
CW20 is the Cosmos equivalent of ERC-20 — a token standard implemented as a CosmWasm smart contract. Unlike Injective's "bank module" tokens (native INJ, IBC tokens, peggy-bridged ERC-20s, TokenFactory denoms), CW20 balances are stored inside the contract's own state, not in cosmos.bank.v1beta1.Balances. So you can't just call one chain endpoint and get a wallet's CW20 holdings — you'd have to query every CW20 contract on chain individually.
This tool calls https://bff-api.injective.network/api/v1/account/cw20-balances/{address}, which is the public Injective indexer that powers injscan and Helix. The indexer has already discovered every CW20 contract on-chain and tracks per-holder balances, so we just request a wallet's CW20 balances and get a clean list back. We don't maintain a hardcoded list of CW20 contracts — it's all dynamic.
A nice side-effect: in the output, contract_address is always a plain inj1.... That's how you know it's a CW20 — bank-module denoms have a different shape (factory/..., ibc/..., peggy0x..., or just inj for native INJ).
Source: cw20-balances.js. MIT licensed.