diff --git a/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx b/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx index 00731c59dd..cf8a21eaba 100644 --- a/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx +++ b/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx @@ -2,7 +2,7 @@ import { IbcTransferProps } from "@namada/sdk-multicore"; import { AccountType } from "@namada/types"; import { mapUndefined } from "@namada/utils"; import { routes } from "App/routes"; -import { isShieldedAddress } from "App/Transfer/common"; +import { isIbcAddress, isShieldedAddress } from "App/Transfer/common"; import { TransferModule } from "App/Transfer/TransferModule"; import { OnSubmitTransferParams } from "App/Transfer/types"; import { @@ -28,6 +28,7 @@ import { useTransaction } from "hooks/useTransaction"; import { useTransactionActions } from "hooks/useTransactionActions"; import { useWalletManager } from "hooks/useWalletManager"; import { KeplrWalletManager } from "integrations/Keplr"; +import { getChainFromAddress } from "integrations/utils"; import invariant from "invariant"; import { useAtom, useAtomValue } from "jotai"; import { TransactionPair } from "lib/query"; @@ -84,6 +85,7 @@ export const IbcWithdraw = ({ walletAddress: keplrAddress, chainId, registry, + connectToChainId, } = useWalletManager(keplrWalletManager); const transparentAccount = useAtomValue(defaultAccountAtom); const namadaChain = useAtomValue(chainAtom); @@ -142,6 +144,22 @@ export const IbcWithdraw = ({ } }; + // Connect to IBC chain if destination address is an IBC address + useEffect(() => { + const connectIfIbc = async (address: string): Promise => { + const chain = getChainFromAddress(address); + if (chain?.chain_id) { + try { + await connectToChainId(chain.chain_id); + } catch (error) { + console.error("Failed to connect to IBC chain:", error); + } + } + }; + + if (isIbcAddress(destinationAddress)) connectIfIbc(destinationAddress); + }, [destinationAddress]); + const { data: ibcChannels, isError: unknownIbcChannels, diff --git a/apps/namadillo/src/App/Transfer/SelectToken.tsx b/apps/namadillo/src/App/Transfer/SelectToken.tsx index e6bc91dbad..4921bb71cd 100644 --- a/apps/namadillo/src/App/Transfer/SelectToken.tsx +++ b/apps/namadillo/src/App/Transfer/SelectToken.tsx @@ -7,6 +7,7 @@ import { connectedWalletsAtom, getChainRegistryByChainName, namadaRegistryChainAssetsMapAtom, + SUPPORTED_ASSETS_MAP, } from "atoms/integrations"; import { tokenPricesFamily } from "atoms/prices/atoms"; import clsx from "clsx"; @@ -125,6 +126,7 @@ export const SelectToken = ({ async (token: AssetWithAmountAndChain): Promise => { // Check if current address is Keplr and if we need to connect to specific chain for this token const isIbcOrKeplrToken = !isNamadaAddress(sourceAddress); + const destinationIsIbcOrKeplrToken = !isNamadaAddress(destinationAddress); // only used for IBC tokens let newSourceAddress: string | undefined; try { @@ -163,6 +165,19 @@ export const SelectToken = ({ } finally { setIsConnectingKeplr(false); } + } else if (destinationIsIbcOrKeplrToken) { + // Because IbcWithdraw uses registry from KeplrWalletManager, we need to connect to + // the source chain of the selected asset. Otherwise channels may not be correct as + // ibcChannelsFamily relies on connected registry. + const chainName = [...SUPPORTED_ASSETS_MAP.entries()].find( + ([_, assetSymbols]) => { + return assetSymbols.includes(token.asset.symbol); + } + )?.[0]; + invariant(chainName, "Chain name not found for selected asset"); + const registry = getChainRegistryByChainName(chainName); + invariant(registry, "Chain registry not found for counterparty"); + await connectToChainId(registry.chain.chain_id); } onSelect?.(token, newSourceAddress); diff --git a/apps/namadillo/src/App/Transfer/TransferLayout.tsx b/apps/namadillo/src/App/Transfer/TransferLayout.tsx index 64b56eb6ed..8a4c856a54 100644 --- a/apps/namadillo/src/App/Transfer/TransferLayout.tsx +++ b/apps/namadillo/src/App/Transfer/TransferLayout.tsx @@ -20,6 +20,7 @@ import { determineTransferType } from "./utils"; export const TransferLayout: React.FC = () => { const keplrWalletManager = new KeplrWalletManager(); + const userHasAccount = useUserHasAccount(); const [sourceAddressUrl, setSourceAddressUrl] = useUrlState("source"); const [destinationAddressUrl, setDestinationAddressUrl] = @@ -59,12 +60,11 @@ export const TransferLayout: React.FC = () => { // Refetch shielded balance for MASP operations useEffect(() => { - if (transferType === "shield" || transferType === "unshield") { - refetchShieldedBalance(); - } + if (["shield", "unshield"].includes(transferType)) refetchShieldedBalance(); }, [transferType, refetchShieldedBalance]); // Validate source address - check if it's from keyring or Keplr + // If not it means the address is invalid at best, poisoned at worst. useEffect(() => { const validateSourceAddress = async (): Promise => { if (!sourceAddressUrl || !userHasAccount || !accounts) return;