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 && (
+ <>
+
+
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;
}
}