diff --git a/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx b/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx index 91ad91e19..fd63b2d60 100644 --- a/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx +++ b/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx @@ -1,5 +1,6 @@ import { Chain } from "@chain-registry/types"; import { mapUndefined } from "@namada/utils"; +import { TransferTransactionTimeline } from "App/Transactions/TransferTransactionTimeline"; import { OnSubmitTransferParams, TransferModule, @@ -14,6 +15,7 @@ import { ibcChannelsFamily, } from "atoms/integrations"; import BigNumber from "bignumber.js"; +import clsx from "clsx"; import { useWalletManager } from "hooks/useWalletManager"; import { wallets } from "integrations"; import { KeplrWalletManager } from "integrations/Keplr"; @@ -22,7 +24,7 @@ import { broadcastTx } from "lib/query"; import { useEffect, useState } from "react"; import namadaChainRegistry from "registry/namada.json"; import { namadaAsset } from "registry/namadaAsset"; -import { Address } from "types"; +import { Address, PartialTransferTransactionData, TransferStep } from "types"; import { IbcTopHeader } from "./IbcTopHeader"; const defaultChainId = "cosmoshub-4"; @@ -32,11 +34,13 @@ export const IbcWithdraw: React.FC = () => { const namadaAccount = useAtomValue(defaultAccountAtom); const chainRegistry = useAtomValue(chainRegistryAtom); const availableChains = useAtomValue(availableChainsAtom); - + const [generalErrorMessage, setGeneralErrorMessage] = useState(""); const [selectedAssetAddress, setSelectedAssetAddress] = useState
(); const [amount, setAmount] = useState(); const [customAddress, setCustomAddress] = useState(""); const [sourceChannel, setSourceChannel] = useState(""); + const [transaction, setTransaction] = + useState(); const { data: availableAssets } = useAtomValue(namadaTransparentAssetsAtom); @@ -78,65 +82,73 @@ export const IbcWithdraw: React.FC = () => { }, [ibcChannels]); const { - mutate: createIbcTx, - isSuccess, + mutateAsync: createIbcTx, isError, error: ibcTxError, - data: ibcTxData, + isPending, } = useAtomValue(createIbcTxAtom); - // TODO: properly notify the user on error useEffect(() => { if (isError) { - console.error(ibcTxError); + setGeneralErrorMessage(ibcTxError + ""); } }, [isError]); - useEffect(() => { - if (isSuccess) { - const { encodedTxData, signedTxs } = ibcTxData; - signedTxs.forEach((signedTx) => - broadcastTx( - encodedTxData, - signedTx, - encodedTxData.meta?.props, - "IbcTransfer" - ) - ); - } - }, [isSuccess]); - const submitIbcTransfer = async ({ amount, destinationAddress, memo, }: OnSubmitTransferParams): Promise => { - const selectedAsset = mapUndefined( - (address) => availableAssets?.[address], - selectedAssetAddress - ); - - if (typeof selectedAsset === "undefined") { - throw new Error("No selected asset"); - } - - if (typeof sourceChannel === "undefined") { - throw new Error("No channel ID is set"); - } + try { + const selectedAsset = mapUndefined( + (address) => availableAssets?.[address], + selectedAssetAddress + ); - if (typeof gasConfig === "undefined") { - throw new Error("No gas config"); + if (typeof selectedAsset === "undefined") { + throw new Error("No selected asset"); + } + + if (typeof sourceChannel === "undefined") { + throw new Error("No channel ID is set"); + } + + if (typeof gasConfig === "undefined") { + throw new Error("No gas config"); + } + + const { encodedTxData, signedTxs } = await createIbcTx({ + destinationAddress, + token: selectedAsset, + amount, + portId: "transfer", + channelId: sourceChannel.trim(), + gasConfig, + memo, + }); + + const tx: PartialTransferTransactionData = { + type: "TransparentToIbc", + asset: selectedAsset.asset, + chainId: namadaChainRegistry.chain_id, + currentStep: TransferStep.Sign, + }; + + setTransaction(tx); + await Promise.allSettled( + signedTxs.map((signedTx) => { + return broadcastTx( + encodedTxData, + signedTx, + encodedTxData.meta?.props, + "IbcTransfer" + ); + }) + ); + } catch (err) { + setGeneralErrorMessage(err + ""); + setTransaction(undefined); } - - createIbcTx({ - destinationAddress, - token: selectedAsset, - amount, - portId: "transfer", - channelId: sourceChannel.trim(), - gasConfig, - memo, - }); }; const onChangeChain = (chain: Chain): void => { @@ -144,53 +156,68 @@ export const IbcWithdraw: React.FC = () => { }; return ( - <> -
- -
-

- Withdraw assets from Namada via IBC -

-

- To withdraw shielded assets please unshield them to your transparent - account -

+
+ {!transaction && ( + <> +
+ +
+

+ Withdraw assets from Namada via IBC +

+

+ To withdraw shielded assets please unshield them to your + transparent account +

+
+
+ chainRegistry[id]?.chain, chainId), + onChangeWallet, + onChangeChain, + isShielded: false, + }} + isSubmitting={isPending} + isIbcTransfer={true} + ibcOptions={{ + sourceChannel, + onChangeSourceChannel: setSourceChannel, + }} + onSubmitTransfer={submitIbcTransfer} + transactionFee={transactionFee} + errorMessage={generalErrorMessage} + /> + + )} + {transaction && ( +
+
-
- chainRegistry[id]?.chain, chainId), - onChangeWallet, - onChangeChain, - isShielded: false, - }} - isIbcTransfer={true} - ibcOptions={{ - sourceChannel, - onChangeSourceChannel: setSourceChannel, - }} - onSubmitTransfer={submitIbcTransfer} - transactionFee={transactionFee} - /> - + )} + ); }; diff --git a/apps/namadillo/src/App/Transfer/TransferModule.tsx b/apps/namadillo/src/App/Transfer/TransferModule.tsx index 06c3e8f48..c8f1ecfd6 100644 --- a/apps/namadillo/src/App/Transfer/TransferModule.tsx +++ b/apps/namadillo/src/App/Transfer/TransferModule.tsx @@ -113,6 +113,11 @@ export const TransferModule = ({ source.selectedAssetAddress ); + const requiresIbcChannels = + isIbcTransfer && + (!ibcOptions?.sourceChannel || + (destination.isShielded && !ibcOptions.destinationChannel)); + const availableAmountMinusFees = useMemo(() => { const { selectedAssetAddress, availableAmount } = source; @@ -315,7 +320,7 @@ export const TransferModule = ({ onChangeMemo={setMemo} transactionFee={transactionFee} /> - {isIbcTransfer && ( + {isIbcTransfer && requiresIbcChannels && ( ; "ShieldingTransfer.Success": EventData; "UnshieldingTransfer.Success": EventData; + "IbcTransfer.Success": EventData; + "IbcTransfer.Error": EventData; } }