diff --git a/main.ts b/main.ts index c7b6058..7da5fef 100644 --- a/main.ts +++ b/main.ts @@ -6,7 +6,7 @@ import { HttpBatchClient, Tendermint34Client } from "npm:@cosmjs/tendermint-rpc" import * as promclient from "npm:prom-client"; import express from "npm:express@4.18.2"; import settings from "./settings.ts"; -import { communityPoolFunds, totalSupply } from "./queries.ts"; +import { communityPoolFunds, getContractUsage, getIbcChannels, totalSupply } from "./queries.ts"; function printableCoin(coin: Coin): string { if (coin.denom?.startsWith("u")) { @@ -17,6 +17,12 @@ function printableCoin(coin: Coin): string { } } + +function mapChannelToDescription(chainId: string, channelId: string): string { + // Default to a unknown if the channel is not found + return settings[chainId].mappingChannels[channelId] || "unknown-proxy"; +} + export interface Account { readonly name: string; readonly address: string; @@ -32,7 +38,6 @@ function errorLog(msg: string) { } if (import.meta.main) { - const app = express(); const balances = new Map(); @@ -43,6 +48,18 @@ if (import.meta.main) { labelNames: ["account", "rpcEndpoint", "chainId"] as const, }); + const customerUsageGauge = new promclient.Gauge({ + name: "customer_usage", + help: "Usage data per customer chain", + labelNames: [ + "channel", + "rpcEndpoint", + "chainId", + "description", + "address", + ] as const, + }); + // Updates all gauges with the current balances const gaugify = () => { for (const [key, val] of balances.entries()) { @@ -53,6 +70,7 @@ if (import.meta.main) { // deno-lint-ignore no-explicit-any app.get("/metrics", (_req: any, res: any) => { gaugify(); + updateContractUsage(); res.set("Content-Type", promclient.register.contentType); promclient.register.metrics().then((metrics) => res.end(metrics)); @@ -91,21 +109,57 @@ if (import.meta.main) { }; const updateCommunityPool = () => { - communityPoolFunds(tmClient, "unois").then((balance) => { - const exportAccountName = "community pool"; - debugLog(`${exportAccountName}: ${printableCoin(balance)}`); - balances.set(exportAccountName, balance.amount); - }, (err) => errorLog(err.toString())); + communityPoolFunds(tmClient, "unois").then( + (balance) => { + const exportAccountName = "community pool"; + debugLog(`${exportAccountName}: ${printableCoin(balance)}`); + balances.set(exportAccountName, balance.amount); + }, + (err) => errorLog(err.toString()) + ); + }; + + const updateContractUsage = async () => { + try { + const contractState = await getContractUsage( + tmClient, + settings[chainId].gatewayAddr + ); + + // get an array of channels infos + const channelsInfo = await getIbcChannels(tmClient); + + // array of customer data + for (const customer of contractState.customers) { + const description = mapChannelToDescription(chainId, customer.channel_id); + const connection = channelsInfo.filter(channel => channel.channelId === customer.channel_id); + + customerUsageGauge.set( + { + channel: customer.channel_id, + rpcEndpoint: rpcEndpoint, + chainId: chainId, + description: description, + address: connection[0].counterparty?.portId?.slice(5) + }, + customer.requested_beacons + ); + } + } catch (err) { + errorLog(err.toString()); + } }; // Initial call updateAccounts(); updateTotalSupply(); updateCommunityPool(); + updateContractUsage(); setInterval(updateAccounts, 10_000); setInterval(updateTotalSupply, 45_000); setInterval(updateCommunityPool, 100_000); + setInterval(updateContractUsage, 60_000); const port = 3000; app.listen(port, function () { diff --git a/queries.ts b/queries.ts index fd5a5f2..4a7a14f 100644 --- a/queries.ts +++ b/queries.ts @@ -6,7 +6,9 @@ import { QueryClient, setupBankExtension, setupDistributionExtension, + setupIbcExtension } from "npm:@cosmjs/stargate"; +import { setupWasmExtension } from "npm:@cosmjs/cosmwasm-stargate"; export async function totalSupply(tmClient: TendermintClient, searchDenom: string): Promise { const queryClient = QueryClient.withExtensions(tmClient, setupBankExtension); @@ -16,7 +18,7 @@ export async function totalSupply(tmClient: TendermintClient, searchDenom: strin /* Queries the community pool funds in full unois. */ export async function communityPoolFunds( tmClient: TendermintClient, - searchDenom: string, + searchDenom: string ): Promise { const queryClient = QueryClient.withExtensions(tmClient, setupDistributionExtension); const resp = await queryClient.distribution.communityPool(); @@ -28,3 +30,32 @@ export async function communityPoolFunds( return coin(amount, searchDenom); } } + +export async function getContractUsage( + tmClient: TendermintClient, + contractAddress: string, +) { + const queryClient = QueryClient.withExtensions(tmClient, setupWasmExtension); + let res: any; + try { + res = await queryClient.wasm.queryContractSmart(contractAddress, { + customers: {}, + }); + } catch (error) { + console.error(error); + } + return res; +} + +export async function getIbcChannels( + tmClient: TendermintClient +) { + const queryClient = QueryClient.withExtensions(tmClient, setupIbcExtension); + let res, filteredChannels; + try { + res = await queryClient.ibc.channel.channels(); + } catch (error) { + console.error(error); + } + return res.channels; +} diff --git a/settings.ts b/settings.ts index 52fdc56..d5cfff6 100644 --- a/settings.ts +++ b/settings.ts @@ -2,6 +2,8 @@ import { Account } from "./main.ts"; export interface ChainSettings { accounts: Account[]; + gatewayAddr: string; + mappingChannels: Record } const settings: Record = { @@ -33,6 +35,16 @@ const settings: Record = { denom: "unois", }, ], + gatewayAddr: "nois1acyc05v6fgcdgj88nmz2t40aex9nlnptqpwp5hf8hwg7rhce9uuqgqz5wp", + mappingChannels: { + "channel-11": "gelotto-proxy", + "channel-2": "juno-nois-team", + "channel-20": "injective-governance", + "channel-22": "architech", + "channel-35": "aura-team", + "channel-38": "stargaze-governance", + "channel-41": "osmosis-nois-team", + } }, "nois-testnet-005": { accounts: [ @@ -52,6 +64,11 @@ const settings: Record = { denom: "unois", }, ], + gatewayAddr: "nois1xwde9rzqk5u36fke0r9ddmtwvh43n4fv53c5vc462wz8xlnqjhls6d90xc", + mappingChannels: { + "channel-17": "juno-nois-team", + "channel-36": "injective-nois-team", + } }, };