Install @polkadot/api npm package.
Set NODE_ADDR environment variable to "wss://node.ksm.genshiro.io" for Genshiro or "wss://node.pol.equilibrium.io" for Equilibrium.
Set MASTER_ADDR to your substrate address.
Run and see balances changes in log.
Created
May 25, 2023 10:11
-
-
Save knopki/af27fc41796287535e9c6927c7ff9d8d to your computer and use it in GitHub Desktop.
Equilibrium/Genshiro balances monitor
This file contains hidden or 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
| const { ApiPromise, WsProvider } = require('@polkadot/api'); | |
| const DECIMALS = 9; | |
| const MASTER_ADDR = process.env.MASTER_ADDR || "cZgDYsXQ6xsPHFSUbtyZEGfeGnKMH5YrANnXD4cze5zLVdn8H"; | |
| const NODE_WS = process.env.NODE_ADDR || 'wss://node.ksm.genshiro.io'; | |
| const ACCOUNT_TYPES = ["Master", "Bailsman", "Trader", "Borrower"] | |
| function log(msg) { | |
| const ts = new Date().toISOString().slice(0, 19).replace("T", " "); | |
| process.stderr.write(`${ts} ${msg}\n`); | |
| } | |
| function hex2a(hexx) { | |
| const hex = hexx.toString(); | |
| let str = ''; | |
| for (let i = 0; i < hex.length; i += 2) { | |
| str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)) | |
| }; | |
| return str; | |
| } | |
| async function printChainInfo(api) { | |
| // Retrieve the chain & node information information via rpc calls | |
| const [chain, nodeName, nodeVersion] = await Promise.all([ | |
| api.rpc.system.chain(), | |
| api.rpc.system.name(), | |
| api.rpc.system.version() | |
| ]); | |
| log(`You are connected to chain ${chain} using ${nodeName} v${nodeVersion}`); | |
| } | |
| async function getAssetsMap(api) { | |
| const assets = (await api.query.eqAssets.assets()).toJSON() | |
| return new Map(assets.map(asset => ([asset.id, hex2a(asset.id.toString(16))]))); | |
| } | |
| async function getAccounts(api, masterAddr) { | |
| const typeToAccMapFn = async t => { | |
| const addr = t == "Master" | |
| ? masterAddr | |
| : (await api.query.subaccounts.subaccount(masterAddr, t)).unwrapOr(null); | |
| return addr ? [t, addr] : null; | |
| }; | |
| return new Map( | |
| (await Promise.all(ACCOUNT_TYPES.map(typeToAccMapFn))).filter(Boolean) | |
| ); | |
| } | |
| function printBalances(accType, nonce, lock, balances) { | |
| log(`Account ${accType} at nonce ${nonce}`); | |
| log(`Account ${accType} has locked amount of native asset of ${lock / 10**DECIMALS}`); | |
| for (const [asset, value] of balances.entries()) { | |
| log(`Account ${accType} has ${value / 10**DECIMALS} ${asset}`); | |
| } | |
| } | |
| async function sub(api, assetsMap, accountsAddrs, callback) { | |
| const accTypes = [...accountsAddrs.keys()]; | |
| const mapBalance = (info) => { | |
| const { nonce, data: { v0: { lock, balance } } } = info.toJSON(); | |
| const balances = new Map(); | |
| for (const [assetId, num] of balance) { | |
| const assetSymbol = assetsMap.get(assetId); | |
| const assetBalance = ((num?.positive || 0) - (num?.negative || 0)); | |
| balances.set(assetSymbol, assetBalance); | |
| } | |
| return { nonce, lock, balances }; | |
| }; | |
| return api.query.system.account.multi([...accountsAddrs.values()], (balances) => { | |
| const acctsBalances = Array(balances.length) | |
| .fill() | |
| .map((_, idx) => [accTypes[idx], mapBalance(balances[idx])]); | |
| for (const [accType, { nonce, lock, balances }] of acctsBalances) { | |
| callback(accType, nonce, lock, balances); | |
| } | |
| }); | |
| } | |
| async function main() { | |
| const provider = new WsProvider(NODE_WS); | |
| const api = await ApiPromise.create({ provider }); | |
| await printChainInfo(api); | |
| // retrieve assets map | |
| const assetsMap = await getAssetsMap(api); | |
| log(`Available assets: ${[...assetsMap.values()].join(", ")}`); | |
| // get subaccounts | |
| const accountsAddrs = await getAccounts(api, MASTER_ADDR); | |
| for (const [t, addr] of accountsAddrs.entries()) { | |
| log(`${t} account address: ${addr}`); | |
| } | |
| // subscribe balance updates | |
| const unsub = await sub(api, assetsMap, accountsAddrs, printBalances); | |
| let stopped = false; | |
| for (const signal of ["SIGINT", "SIGTERM"]) { | |
| process.on(signal, (signal) => { | |
| log(`${signal} received; closing...`); | |
| unsub(); | |
| stopped = true; | |
| }); | |
| } | |
| while (!stopped) { | |
| await new Promise(resolve => setTimeout(resolve, 1000)); | |
| } | |
| } | |
| main().catch(console.error).finally(() => process.exit()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment