Skip to content

Commit

Permalink
feat: fetching known ibc channels from github chain-registry repository
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrorezende committed Jan 14, 2025
1 parent 786729b commit fce77f4
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 81 deletions.
3 changes: 3 additions & 0 deletions apps/namadillo/public/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
#rpc_url = ""
#masp_indexer_url = ""
#localnet_enabled = false

github_chain_registry_base_url = "https://raw.githubusercontent.com/anoma/namada-chain-registry/refs/heads/main"
github_namada_interface_url = "https://raw.githubusercontent.com/anoma/namada-interface/refs/heads/main"
20 changes: 12 additions & 8 deletions apps/namadillo/src/App/Ibc/IbcTransfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ export const IbcTransfer = (): JSX.Element => {
} = useWalletManager(keplr);

// IBC Channels & Balances
const { data: ibcChannels } = useAtomValue(
ibcChannelsFamily(registry?.chain.chain_name)
);
const {
data: ibcChannels,
isError: unknownIbcChannels,
isLoading: isLoadingIbcChannels,
} = useAtomValue(ibcChannelsFamily(registry?.chain.chain_name));

const { data: userAssets, isLoading: isLoadingBalances } = useAtomValue(
assetBalanceAtomFamily({
Expand Down Expand Up @@ -101,16 +103,18 @@ export const IbcTransfer = (): JSX.Element => {
);
}, [defaultAccounts, shielded]);

const requiresIbcChannels =
!ibcChannels?.cosmosChannelId ||
(shielded && !ibcChannels?.namadaChannelId);
const requiresIbcChannels = Boolean(
!isLoadingIbcChannels &&
(unknownIbcChannels ||
(shielded && ibcChannels && !ibcChannels?.namadaChannel))
);

useEffect(() => setSelectedAssetAddress(undefined), [registry]);

// Set source and destination channels based on IBC channels data
useEffect(() => {
setSourceChannel(ibcChannels?.cosmosChannelId || "");
setDestinationChannel(ibcChannels?.namadaChannelId || "");
setSourceChannel(ibcChannels?.ibcChannel || "");
setDestinationChannel(ibcChannels?.namadaChannel || "");
}, [ibcChannels]);

const onSubmitTransfer = async ({
Expand Down
13 changes: 8 additions & 5 deletions apps/namadillo/src/App/Ibc/IbcWithdraw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,14 @@ export const IbcWithdraw: React.FC = () => {
connectToChainId(chain.chain_id);
};

const { data: ibcChannels } = useAtomValue(
ibcChannelsFamily(registry?.chain.chain_name)
);
const {
data: ibcChannels,
isError: unknownIbcChannels,
isLoading: isLoadingIbcChannels,
} = useAtomValue(ibcChannelsFamily(registry?.chain.chain_name));

useEffect(() => {
setSourceChannel(ibcChannels?.namadaChannelId || "");
setSourceChannel(ibcChannels?.namadaChannel || "");
}, [ibcChannels]);

const { execute: performWithdraw, isPending } = useTransaction({
Expand Down Expand Up @@ -190,7 +192,8 @@ export const IbcWithdraw: React.FC = () => {
}
};

const requiresIbcChannels = !ibcChannels?.cosmosChannelId;
const requiresIbcChannels = !isLoadingIbcChannels && unknownIbcChannels;

return (
<div className="relative min-h-[600px]">
<header className="flex flex-col items-center text-center mb-3 gap-6">
Expand Down
41 changes: 27 additions & 14 deletions apps/namadillo/src/atoms/integrations/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import {
IbcTransferProps,
} from "@namada/types";
import { defaultAccountAtom } from "atoms/accounts";
import { chainAtom, chainParametersAtom } from "atoms/chain";
import { chainAtom } from "atoms/chain";
import { defaultServerConfigAtom, settingsAtom } from "atoms/settings";
import { queryDependentFn } from "atoms/utils";
import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
import invariant from "invariant";
import { atom } from "jotai";
import { atomWithMutation, atomWithQuery } from "jotai-tanstack-query";
import { atomFamily, atomWithStorage } from "jotai/utils";
Expand All @@ -24,14 +25,14 @@ import {
import {
addLocalnetToRegistry,
createIbcTx,
getIbcChannels,
getKnownChains,
ibcAddressToDenomTrace,
IbcChannels,
mapCoinsToAssets,
} from "./functions";
import {
broadcastIbcTransaction,
fetchIbcChannelFromRegistry,
fetchLocalnetTomlConfig,
queryAndStoreRpc,
queryAssetBalances,
Expand Down Expand Up @@ -130,19 +131,31 @@ export const availableAssetsAtom = atom((get) => {
return getKnownChains(settings.enableTestnets).map(({ assets }) => assets);
});

export const ibcChannelsFamily = atomFamily((cosmosChainName?: string) =>
atomWithQuery<IbcChannels | undefined>((get) => {
const chainParameters = get(chainParametersAtom);

export const ibcChannelsFamily = atomFamily((ibcChainName?: string) =>
atomWithQuery<IbcChannels | null>((get) => {
const chainSettings = get(chainAtom);
const config = get(defaultServerConfigAtom);
return {
queryKey: ["ibc-channel", cosmosChainName, chainParameters.data!.chainId],
...queryDependentFn(
() =>
Promise.resolve(
getIbcChannels(chainParameters.data!.chainId, cosmosChainName!)
),
[typeof cosmosChainName !== "undefined", chainParameters]
),
queryKey: ["known-channels", ibcChainName, chainSettings.data?.chainId],
retry: false,
...queryDependentFn(async () => {
invariant(chainSettings.data, "No chain settings");
invariant(ibcChainName, "No IBC chain name");
invariant(
config.data?.github_chain_registry_base_url,
"No github_chain_registry_base_url was provided on config.toml"
);
return fetchIbcChannelFromRegistry(
chainSettings.data.chainId,
ibcChainName,
config.data?.github_chain_registry_base_url
);
}, [
chainSettings,
config,
!!ibcChainName,
!!config.data?.github_chain_registry_base_url,
]),
};
})
);
Expand Down
85 changes: 35 additions & 50 deletions apps/namadillo/src/atoms/integrations/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import * as osmosisTestnet from "chain-registry/testnet/osmosistestnet";
import * as stargazeTestnet from "chain-registry/testnet/stargazetestnet";
import { DenomTrace } from "cosmjs-types/ibc/applications/transfer/v1/transfer";
import { TransactionPair, buildTxPair } from "lib/query";
import namadaMainnetChain from "namada-chain-registry/namada/chain.json";
import {
Address,
AddressWithAssetAndAmount,
Expand All @@ -43,21 +44,20 @@ import internalDevnetChain from "namada-chain-registry/_testnets/namadainternald
import namadaAssets from "namada-chain-registry/namada/assetlist.json";
import namadaChain from "namada-chain-registry/namada/chain.json";

import campfireOsmosisTestnetIbc from "namada-chain-registry/_testnets/_IBC/namadacampfire-osmosistestnet.json";
import housefireOldCosmosTestnetIbc from "namada-chain-registry/_testnets/_IBC/namadahousefireold-cosmoshubtestnet.json";
import housefireOldOsmosisTestnetIbc from "namada-chain-registry/_testnets/_IBC/namadahousefireold-osmosistestnet.json";
import internalDevnetCosmosTestnetIbc from "namada-chain-registry/_testnets/_IBC/namadainternaldevnet-cosmoshubtestnet.json";

// TODO: this causes a big increase on bundle size. See #1224.
import cosmosRegistry from "chain-registry";
import { searchNamadaTestnetByChainId } from "lib/chain";

cosmosRegistry.chains.push(
export const namadaTestnetChainList = [
internalDevnetChain,
campfireChain,
housefireChain,
housefireOldChain,
namadaChain
);
] as Chain[];

cosmosRegistry.chains.push(...namadaTestnetChainList, namadaChain);

cosmosRegistry.assets.push(
internalDevnetAssets,
Expand All @@ -67,13 +67,6 @@ cosmosRegistry.assets.push(
namadaAssets
);

cosmosRegistry.ibc.push(
campfireOsmosisTestnetIbc,
internalDevnetCosmosTestnetIbc,
housefireOldCosmosTestnetIbc,
housefireOldOsmosisTestnetIbc
);

const mainnetChains: ChainRegistryEntry[] = [
celestia,
cosmos,
Expand Down Expand Up @@ -323,51 +316,43 @@ export const getRestApiAddressByIndex = (chain: Chain, index = 0): string => {
return randomRestApi.address;
};

export const getChainRegistryIbcFilePath = (
currentNamadaChainId: string,
ibcChainName: string
): string => {
const chain =
searchNamadaTestnetByChainId(currentNamadaChainId) || namadaMainnetChain;
const searchFilename = `${chain.chain_name}-${ibcChainName}.json`;
const isMainnet = currentNamadaChainId === namadaMainnetChain.chain_id;
const ibcFolder = isMainnet ? "_IBC" : "_testnets/_IBC";
return `${ibcFolder}/${searchFilename}`;
};

export type IbcChannels = {
namadaChannelId: string;
cosmosChannelId: string;
namadaChannel: string;
ibcChannel: string;
};

export const getIbcChannels = (
namadaChainId: string,
cosmosChainName: string
export const getChannelFromIbcInfo = (
ibcChainName: string,
ibcInfo: IBCInfo
): IbcChannels | undefined => {
const namadaChainName = cosmosRegistry.chains.find(
(chain) => chain.chain_id === namadaChainId
)?.chain_name;
const { chain_2, channels } = ibcInfo;
const channelEntry = channels[0];

if (typeof namadaChainName === "undefined") {
return undefined;
if (!channelEntry) {
console.warn("No channel entry found in IBC info");
return;
}

for (const ibcEntry of cosmosRegistry.ibc) {
const { chain_1, chain_2, channels } = ibcEntry;
const channelEntry = channels[0];
const namadaOnChannel1 = chain_2.chain_name === ibcChainName;
const namadaChannelId = namadaOnChannel1 ? "chain_1" : "chain_2";
const ibcChannelId = namadaOnChannel1 ? "chain_2" : "chain_1";

if (typeof channelEntry === "undefined") {
continue;
}

if (
chain_1.chain_name === namadaChainName &&
chain_2.chain_name === cosmosChainName
) {
return {
namadaChannelId: channelEntry.chain_1.channel_id,
cosmosChannelId: channelEntry.chain_2.channel_id,
};
}

if (
chain_1.chain_name === cosmosChainName &&
chain_2.chain_name === namadaChainName
) {
return {
cosmosChannelId: channelEntry.chain_1.channel_id,
namadaChannelId: channelEntry.chain_2.channel_id,
};
}
}
return {
namadaChannel: channelEntry[namadaChannelId].channel_id,
ibcChannel: channelEntry[ibcChannelId].channel_id,
};
};

export const createIbcTx = async (
Expand Down
33 changes: 29 additions & 4 deletions apps/namadillo/src/atoms/integrations/services.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Chain } from "@chain-registry/types";
import { Chain, IBCInfo } from "@chain-registry/types";
import { OfflineSigner } from "@cosmjs/launchpad";
import {
assertIsDeliverTxSuccess,
calculateFee,
DeliverTxResponse,
SigningStargateClient,
StargateClient,
StdFee,
assertIsDeliverTxSuccess,
calculateFee,
} from "@cosmjs/stargate";
import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";

import { sanitizeUrl } from "@namada/utils";
import { getIndexerApi } from "atoms/api";
import { queryForAck, queryForIbcTimeout } from "atoms/transactions";
import BigNumber from "bignumber.js";
Expand All @@ -28,7 +29,12 @@ import { toBaseAmount } from "utils";
import { getKeplrWallet } from "utils/ibc";
import { getSdkInstance } from "utils/sdk";
import { rpcByChainAtom } from "./atoms";
import { getRpcByIndex } from "./functions";
import {
getChainRegistryIbcFilePath,
getChannelFromIbcInfo,
getRpcByIndex,
IbcChannels,
} from "./functions";

type CommonParams = {
signer: OfflineSigner;
Expand Down Expand Up @@ -256,3 +262,22 @@ export const fetchLocalnetTomlConfig = async (): Promise<LocalnetToml> => {
const response = await fetch("/localnet-config.toml");
return toml.parse(await response.text()) as LocalnetToml;
};

export const fetchIbcChannelFromRegistry = async (
currentNamadaChainId: string,
ibcChainName: string,
namadaChainRegistryUrl: string
): Promise<IbcChannels | null> => {
const ibcFilePath = getChainRegistryIbcFilePath(
currentNamadaChainId,
ibcChainName
);

const queryUrl = new URL(
ibcFilePath,
sanitizeUrl(namadaChainRegistryUrl) + "/"
);

const channelInfo: IBCInfo = await (await fetch(queryUrl.toString())).json();
return getChannelFromIbcInfo(ibcChainName, channelInfo) || null;
};
8 changes: 8 additions & 0 deletions apps/namadillo/src/lib/chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Chain } from "@chain-registry/types";
import { namadaTestnetChainList } from "atoms/integrations";

export const searchNamadaTestnetByChainId = (
chainId: string
): Chain | undefined => {
return namadaTestnetChainList.find((chain) => chain.chain_id === chainId);
};
2 changes: 2 additions & 0 deletions apps/namadillo/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export type SettingsTomlOptions = {
masp_indexer_url?: string;
rpc_url?: string;
localnet_enabled?: boolean;
github_chain_registry_base_url?: string;
github_namada_interface_url?: string;
};

export type ChainParameters = {
Expand Down

0 comments on commit fce77f4

Please sign in to comment.