Skip to content

Commit

Permalink
Namadillo: Withdraw Tweaks (#1287)
Browse files Browse the repository at this point in the history
* feat: removing ibc channel fields when channels are known

* feat: general improvements on withdrawal
  • Loading branch information
pedrorezende authored Nov 21, 2024
1 parent 7c15e90 commit ec8353c
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 93 deletions.
211 changes: 119 additions & 92 deletions apps/namadillo/src/App/Ibc/IbcWithdraw.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Chain } from "@chain-registry/types";
import { mapUndefined } from "@namada/utils";
import { TransferTransactionTimeline } from "App/Transactions/TransferTransactionTimeline";
import {
OnSubmitTransferParams,
TransferModule,
Expand All @@ -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";
Expand All @@ -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";
Expand All @@ -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<Address>();
const [amount, setAmount] = useState<BigNumber | undefined>();
const [customAddress, setCustomAddress] = useState<string>("");
const [sourceChannel, setSourceChannel] = useState("");
const [transaction, setTransaction] =
useState<PartialTransferTransactionData>();

const { data: availableAssets } = useAtomValue(namadaTransparentAssetsAtom);

Expand Down Expand Up @@ -78,119 +82,142 @@ 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<void> => {
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 => {
connectToChainId(chain.chain_id);
};

return (
<>
<header className="flex flex-col items-center text-center mb-3 gap-6">
<IbcTopHeader type="namToIbc" isShielded={false} />
<div className="max-w-[360px] mx-auto mb-3">
<h2 className="mb-1 text-lg font-light">
Withdraw assets from Namada via IBC
</h2>
<p className="text-sm font-light leading-tight">
To withdraw shielded assets please unshield them to your transparent
account
</p>
<div className="relative min-h-[600px]">
{!transaction && (
<>
<header className="flex flex-col items-center text-center mb-3 gap-6">
<IbcTopHeader type="namToIbc" isShielded={false} />
<div className="max-w-[360px] mx-auto mb-3">
<h2 className="mb-1 text-lg font-light">
Withdraw assets from Namada via IBC
</h2>
<p className="text-sm font-light leading-tight">
To withdraw shielded assets please unshield them to your
transparent account
</p>
</div>
</header>
<TransferModule
source={{
wallet: wallets.namada,
walletAddress: namadaAccount.data?.address,
chain: namadaChainRegistry as Chain,
isShielded: false,
availableAssets,
availableAmount,
selectedAssetAddress,
onChangeSelectedAsset: setSelectedAssetAddress,
amount,
onChangeAmount: setAmount,
}}
destination={{
wallet: wallets.keplr,
walletAddress: keplrAddress,
availableWallets: [wallets.keplr!],
availableChains,
enableCustomAddress: true,
customAddress,
onChangeCustomAddress: setCustomAddress,
chain: mapUndefined((id) => chainRegistry[id]?.chain, chainId),
onChangeWallet,
onChangeChain,
isShielded: false,
}}
isSubmitting={isPending}
isIbcTransfer={true}
ibcOptions={{
sourceChannel,
onChangeSourceChannel: setSourceChannel,
}}
onSubmitTransfer={submitIbcTransfer}
transactionFee={transactionFee}
errorMessage={generalErrorMessage}
/>
</>
)}
{transaction && (
<div
className={clsx(
"absolute z-50 py-12 left-0 top-0 w-full h-full bg-black"
)}
>
<TransferTransactionTimeline transaction={transaction} />
</div>
</header>
<TransferModule
source={{
wallet: wallets.namada,
walletAddress: namadaAccount.data?.address,
chain: namadaChainRegistry as Chain,
isShielded: false,
availableAssets,
availableAmount,
selectedAssetAddress,
onChangeSelectedAsset: setSelectedAssetAddress,
amount,
onChangeAmount: setAmount,
}}
destination={{
wallet: wallets.keplr,
walletAddress: keplrAddress,
availableWallets: [wallets.keplr!],
availableChains,
enableCustomAddress: true,
customAddress,
onChangeCustomAddress: setCustomAddress,
chain: mapUndefined((id) => chainRegistry[id]?.chain, chainId),
onChangeWallet,
onChangeChain,
isShielded: false,
}}
isIbcTransfer={true}
ibcOptions={{
sourceChannel,
onChangeSourceChannel: setSourceChannel,
}}
onSubmitTransfer={submitIbcTransfer}
transactionFee={transactionFee}
/>
</>
)}
</div>
);
};
7 changes: 6 additions & 1 deletion apps/namadillo/src/App/Transfer/TransferModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -315,7 +320,7 @@ export const TransferModule = ({
onChangeMemo={setMemo}
transactionFee={transactionFee}
/>
{isIbcTransfer && (
{isIbcTransfer && requiresIbcChannels && (
<IbcChannels
isShielded={Boolean(source.isShielded || destination.isShielded)}
sourceChannel={ibcOptions.sourceChannel}
Expand Down
3 changes: 3 additions & 0 deletions apps/namadillo/src/types/events.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
BondProps,
IbcTransferProps,
RedelegateProps,
ShieldedTransferProps,
ShieldingTransferProps,
Expand Down Expand Up @@ -62,5 +63,7 @@ declare global {
"ShieldedTransfer.Success": EventData<ShieldedTransferProps>;
"ShieldingTransfer.Success": EventData<ShieldingTransferProps>;
"UnshieldingTransfer.Success": EventData<UnshieldingTransferProps>;
"IbcTransfer.Success": EventData<IbcTransferProps>;
"IbcTransfer.Error": EventData<IbcTransferProps>;
}
}

1 comment on commit ec8353c

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.