diff --git a/components/chainSelect/ChainSelect.tsx b/components/chainSelect/ChainSelect.tsx index 1c996fb..9ef95b4 100644 --- a/components/chainSelect/ChainSelect.tsx +++ b/components/chainSelect/ChainSelect.tsx @@ -8,7 +8,12 @@ import Button from "../inputs/Button"; import Input from "../inputs/Input"; import Select from "../inputs/Select"; import StackableContainer from "../layout/StackableContainer"; -import { ChainRegistryAsset } from "./chainregistry"; +import { + RegistryChainApisRpc, + RegistryChainExplorer, + getAssetsFromRegistry, + getChainFromRegistry, +} from "./chainregistry"; interface ChainOption { label: string; @@ -112,75 +117,64 @@ const ChainSelect = () => { const getChainInfo = async (chainOption: GithubChainRegistryItem) => { setChainError(null); - try { - const chainInfoUrl = - "https://cdn.jsdelivr.net/gh/cosmos/chain-registry@master/" + - chainOption.path + - "/chain.json"; - const chainAssetUrl = - "https://cdn.jsdelivr.net/gh/cosmos/chain-registry@master/" + - chainOption.path + - "/assetlist.json"; - const { data: chainData } = await axios.get(chainInfoUrl); - const { data: assetData } = await axios.get(chainAssetUrl); + try { + const chainData = await getChainFromRegistry(chainOption.path); + const assets = await getAssetsFromRegistry(chainOption.path); + const firstAsset = assets[0]; const nodeAddress = await getNodeFromArray(chainData.apis.rpc); - const addressPrefix = chainData["bech32_prefix"]; - const chainId = chainData["chain_id"]; - const chainDisplayName = chainData["pretty_name"]; - const registryName = chainOption.name; const explorerLink = getExplorerFromArray(chainData.explorers); + const denom = firstAsset.base || ""; + const displayDenom = firstAsset.symbol || ""; - const firstAsset: ChainRegistryAsset | undefined = assetData.assets?.[0]; - const denom = firstAsset?.base || ""; - const displayDenom = firstAsset?.symbol || ""; - const feeToken = - chainData["fees"]?.fee_tokens.find((token: { denom: string }) => token.denom == denom) ?? - {}; + const displayUnit = firstAsset.denom_units.find((u) => u.denom == firstAsset.display); + const displayDenomExponent = displayUnit?.exponent ?? 6; + + const feeToken = chainData.fees.fee_tokens.find((token) => token.denom == denom) ?? { denom }; const gasPrice = - feeToken["average_gas_price"] ?? - feeToken["low_gas_price"] ?? - feeToken["high_gas_price"] ?? - feeToken["fixed_min_gas_price"] ?? + feeToken.average_gas_price ?? + feeToken.low_gas_price ?? + feeToken.high_gas_price ?? + feeToken.fixed_min_gas_price ?? 0.03; const formattedGasPrice = firstAsset ? `${gasPrice}${denom}` : ""; - const displayUnit = firstAsset?.denom_units.find((u) => u.denom == firstAsset.display); - const displayDenomExponent = displayUnit?.exponent ?? 6; // change app state dispatch({ type: "changeChain", value: { + registryName: chainOption.name, + addressPrefix: chainData.bech32_prefix, + chainId: chainData.chain_id, + chainDisplayName: chainData.pretty_name, nodeAddress, + explorerLink, denom, displayDenom, displayDenomExponent, gasPrice: formattedGasPrice, - chainId, - chainDisplayName, - registryName, - addressPrefix, - explorerLink, }, }); + setShowSettings(false); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - console.log(error); + } catch (error) { + if (error instanceof Error) { + setChainError(error.message); + } else { + setChainError("Error getting chain info"); + } + + console.error("Error getting chain info", error); setShowSettings(true); - setChainError(error.toString()); } }; - const getExplorerFromArray = (array: { kind: string; url: string; tx_page: string }[]) => { - if (array && array.length > 0) { - return array[0]["tx_page"]; - } - return ""; + const getExplorerFromArray = (explorers: readonly RegistryChainExplorer[]) => { + return explorers[0]?.tx_page ?? ""; }; - const getNodeFromArray = async (nodeArray: { address: string; provider: string }[]) => { + const getNodeFromArray = async (nodeArray: readonly RegistryChainApisRpc[]) => { // only return https connections const secureNodes = nodeArray .filter((node) => node.address.startsWith("https://")) diff --git a/components/chainSelect/chainregistry.ts b/components/chainSelect/chainregistry.ts index ef1aa4a..1714f4c 100644 --- a/components/chainSelect/chainregistry.ts +++ b/components/chainSelect/chainregistry.ts @@ -1,7 +1,49 @@ +import axios from "axios"; + +export interface RegistryChainApisRpc { + readonly address: string; + readonly provider: string; +} + +export interface RegistryChainApis { + readonly rpc: readonly RegistryChainApisRpc[]; +} + +export interface RegistryChainExplorer { + readonly kind: string; + readonly url: string; + readonly tx_page: string; +} + +export interface RegistryChainFeeTokens { + readonly denom: string; + readonly average_gas_price?: number; + readonly low_gas_price?: number; + readonly high_gas_price?: number; + readonly fixed_min_gas_price?: number; +} + +export interface RegistryChainFees { + readonly fee_tokens: readonly RegistryChainFeeTokens[]; +} + +export interface RegistryChain { + readonly apis: RegistryChainApis; + readonly bech32_prefix: string; + readonly chain_id: string; + readonly explorers: readonly RegistryChainExplorer[]; + readonly fees: RegistryChainFees; + readonly pretty_name: string; +} + +export interface RegistryChainResponse { + readonly data: RegistryChain; +} + /** * See https://github.com/cosmos/chain-registry/blob/1e9ecde770951cab90f0853a624411d79af90b83/provenance/assetlist.json#L8-L12 */ -export interface ChainRegistryDemonUnit { +export interface RegistryAssetDenomUnit { denom: string; exponent: number; aliases: string[]; @@ -10,9 +52,9 @@ export interface ChainRegistryDemonUnit { /** * See https://github.com/cosmos/chain-registry/blob/1e9ecde770951cab90f0853a624411d79af90b83/provenance/assetlist.json#L5-L28 */ -export interface ChainRegistryAsset { +export interface RegistryAsset { description: string; - denom_units: ChainRegistryDemonUnit[]; + denom_units: RegistryAssetDenomUnit[]; base: string; name: string; display: string; @@ -23,3 +65,28 @@ export interface ChainRegistryAsset { }; coingecko_id: string; } + +export interface RegistryAssetsResponse { + readonly data: { readonly assets: readonly RegistryAsset[] }; +} + +const registryGhUrl = "https://cdn.jsdelivr.net/gh/cosmos/chain-registry@master/"; + +export const getChainFromRegistry = async (chainGhName: string): Promise => { + const chainGhUrl = registryGhUrl + chainGhName + "/chain.json"; + + const { data: chain }: RegistryChainResponse = await axios.get(chainGhUrl); + return chain; +}; + +export const getAssetsFromRegistry = async ( + chainGhName: string, +): Promise => { + const assetsGhUrl = registryGhUrl + chainGhName + "/assetlist.json"; + + const { + data: { assets }, + }: RegistryAssetsResponse = await axios.get(assetsGhUrl); + + return assets; +};