diff --git a/bridge_ui/src/components/Transfer/Target.tsx b/bridge_ui/src/components/Transfer/Target.tsx
index 497b9f0f9..6c1ffdfe5 100644
--- a/bridge_ui/src/components/Transfer/Target.tsx
+++ b/bridge_ui/src/components/Transfer/Target.tsx
@@ -8,6 +8,7 @@ import { Alert } from "@material-ui/lab";
import { useCallback, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import useIsWalletReady from "../../hooks/useIsWalletReady";
+import useMetadata from "../../hooks/useMetadata";
import useSyncTargetAddress from "../../hooks/useSyncTargetAddress";
import { EthGasEstimateSummary } from "../../hooks/useTransactionFees";
import {
@@ -20,12 +21,14 @@ import {
selectTransferTargetChain,
selectTransferTargetError,
UNREGISTERED_ERROR_MESSAGE,
+ selectTransferAmount,
} from "../../store/selectors";
import { incrementStep, setTargetChain } from "../../store/transferSlice";
import { CHAINS, CHAINS_BY_ID } from "../../utils/consts";
import ButtonWithLoader from "../ButtonWithLoader";
import KeyAndBalance from "../KeyAndBalance";
import LowBalanceWarning from "../LowBalanceWarning";
+import SmartAddress from "../SmartAddress";
import SolanaCreateAssociatedAddress, {
useAssociatedAccountExistsState,
} from "../SolanaCreateAssociatedAddress";
@@ -53,9 +56,21 @@ function Target() {
const targetChain = useSelector(selectTransferTargetChain);
const targetAddressHex = useSelector(selectTransferTargetAddressHex);
const targetAsset = useSelector(selectTransferTargetAsset);
+ const targetAssetArrayed = useMemo(
+ () => (targetAsset ? [targetAsset] : []),
+ [targetAsset]
+ );
+ const metadata = useMetadata(targetChain, targetAssetArrayed);
+ const tokenName =
+ (targetAsset && metadata.data?.get(targetAsset)?.tokenName) || undefined;
+ const symbol =
+ (targetAsset && metadata.data?.get(targetAsset)?.symbol) || undefined;
+ const logo =
+ (targetAsset && metadata.data?.get(targetAsset)?.logo) || undefined;
const readableTargetAddress =
hexToNativeString(targetAddressHex, targetChain) || "";
const uiAmountString = useSelector(selectTransferTargetBalanceString);
+ const transferAmount = useSelector(selectTransferAmount);
const error = useSelector(selectTransferTargetError);
const isTargetComplete = useSelector(selectTransferIsTargetComplete);
const shouldLockFields = useSelector(selectTransferShouldLockFields);
@@ -93,13 +108,37 @@ function Target() {
))}
-
+ {readableTargetAddress ? (
+ <>
+ {targetAsset ? (
+
+ Bridged tokens:
+
+
+ {`(Amount: ${transferAmount})`}
+
+
+ ) : null}
+
+ Sent to:
+
+
+ {`(Current balance: ${uiAmountString || "0"})`}
+
+
+ >
+ ) : null}
{targetChain === CHAIN_ID_SOLANA && targetAsset ? (
) : null}
-
You will have to pay transaction fees on{" "}
diff --git a/bridge_ui/src/hooks/useEthMetadata.ts b/bridge_ui/src/hooks/useEthMetadata.ts
new file mode 100644
index 000000000..0eeec3aad
--- /dev/null
+++ b/bridge_ui/src/hooks/useEthMetadata.ts
@@ -0,0 +1,102 @@
+import { CHAIN_ID_ETH } from "@certusone/wormhole-sdk";
+import { ethers } from "@certusone/wormhole-sdk/node_modules/ethers";
+import { useEffect, useMemo, useState } from "react";
+import {
+ Provider,
+ useEthereumProvider,
+} from "../contexts/EthereumProviderContext";
+import { DataWrapper } from "../store/helpers";
+import useIsWalletReady from "./useIsWalletReady";
+
+export type EthMetadata = {
+ symbol?: string;
+ logo?: string;
+ tokenName?: string;
+ decimals?: number;
+};
+
+const ERC20_BASIC_ABI = [
+ "function name() view returns (string name)",
+ "function symbol() view returns (string symbol)",
+ "function decimals() view returns (uint8 decimals)",
+];
+
+const handleError = () => {
+ return undefined;
+};
+
+const fetchSingleMetadata = async (
+ address: string,
+ provider: Provider
+): Promise => {
+ const contract = new ethers.Contract(address, ERC20_BASIC_ABI, provider);
+ const [name, symbol, decimals] = await Promise.all([
+ contract.name().catch(handleError),
+ contract.symbol().catch(handleError),
+ contract.decimals().catch(handleError),
+ ]);
+ return { tokenName: name, symbol, decimals };
+};
+
+const fetchEthMetadata = async (addresses: string[], provider: Provider) => {
+ const promises: Promise[] = [];
+ addresses.forEach((address) => {
+ promises.push(fetchSingleMetadata(address, provider));
+ });
+ const resultsArray = await Promise.all(promises);
+ const output = new Map();
+ addresses.forEach((address, index) => {
+ output.set(address, resultsArray[index]);
+ });
+
+ return output;
+};
+
+function useEthMetadata(
+ addresses: string[]
+): DataWrapper