diff --git a/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx b/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx
index 03f20e67..13a9345a 100644
--- a/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx
+++ b/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx
@@ -7,7 +7,7 @@ import {
Typography,
} from "@material-ui/core";
import { Autocomplete, createFilterOptions } from "@material-ui/lab";
-import React, { useCallback, useEffect, useState } from "react";
+import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useEthereumProvider } from "../../contexts/EthereumProviderContext";
import { CovalentData } from "../../hooks/useGetSourceParsedTokenAccounts";
import { DataWrapper } from "../../store/helpers";
@@ -28,18 +28,34 @@ import NFTViewer from "./NFTViewer";
import { useDebounce } from "use-debounce/lib";
import RefreshButtonWrapper from "./RefreshButtonWrapper";
import { CHAIN_ID_ETH } from "@certusone/wormhole-sdk";
+import { sortParsedTokenAccounts } from "../../utils/sort";
-const useStyles = makeStyles(() =>
+const useStyles = makeStyles((theme) =>
createStyles({
selectInput: { minWidth: "10rem" },
tokenOverviewContainer: {
display: "flex",
+ width: "100%",
+ alignItems: "center",
"& div": {
- margin: ".5rem",
+ margin: theme.spacing(1),
+ flexBasis: "33%",
+ "&$tokenImageContainer": {
+ maxWidth: 40,
+ },
+ "&:last-child": {
+ textAlign: "right",
+ },
},
},
+ tokenImageContainer: {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "center",
+ width: 40,
+ },
tokenImage: {
- maxHeight: "2.5rem",
+ maxHeight: "2.5rem", //Eyeballing this based off the text size
},
})
);
@@ -86,7 +102,7 @@ const renderAccount = (
const symbol = getSymbol(account) || "Unknown";
return (
-
+
{uri &&
}
@@ -119,7 +135,7 @@ const renderNFTAccount = (
const name = account.name || "Unknown";
return (
-
+
{uri &&
}
@@ -437,9 +453,19 @@ export default function EthereumSourceTokenSelector(
setAdvancedMode(!advancedMode);
};
- const handleAutocompleteChange = (newValue: ParsedTokenAccount | null) => {
- setAutocompleteHolder(newValue);
- };
+ const handleAutocompleteChange = useCallback(
+ (event, newValue: ParsedTokenAccount | null) => {
+ setAutocompleteHolder(newValue);
+ },
+ []
+ );
+
+ const tokenAccountsData = tokenAccounts?.data;
+ const sortedOptions = useMemo(() => {
+ const options = tokenAccountsData || [];
+ options.sort(sortParsedTokenAccounts);
+ return options;
+ }, [tokenAccountsData]);
const isLoading =
props.covalent?.isFetching || props.tokenAccounts?.isFetching;
@@ -449,22 +475,19 @@ export default function EthereumSourceTokenSelector(
{
- handleAutocompleteChange(newValue);
- }}
+ onChange={handleAutocompleteChange}
disabled={disabled}
noOptionsText={
nft
? "No ERC-721 tokens found at the moment."
: "No ERC-20 tokens found at the moment."
}
- options={tokenAccounts?.data || []}
+ options={sortedOptions}
renderInput={(params) => (
)}
diff --git a/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx b/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx
index cf18b5cb..5333aaab 100644
--- a/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx
+++ b/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx
@@ -1,6 +1,11 @@
import { CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
-import { CircularProgress, TextField, Typography } from "@material-ui/core";
-import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
+import {
+ CircularProgress,
+ TextField,
+ Typography,
+ createStyles,
+ makeStyles,
+} from "@material-ui/core";
import { Alert, Autocomplete } from "@material-ui/lab";
import { createFilterOptions } from "@material-ui/lab/Autocomplete";
import { TokenInfo } from "@solana/spl-token-registry";
@@ -15,21 +20,46 @@ import {
WORMHOLE_V1_MINT_AUTHORITY,
} from "../../utils/consts";
import { ExtractedMintInfo, shortenAddress } from "../../utils/solana";
+import { sortParsedTokenAccounts } from "../../utils/sort";
import NFTViewer from "./NFTViewer";
import RefreshButtonWrapper from "./RefreshButtonWrapper";
-const useStyles = makeStyles((theme: Theme) =>
+const useStyles = makeStyles((theme) =>
createStyles({
selectInput: { minWidth: "10rem" },
tokenOverviewContainer: {
display: "flex",
+ width: "100%",
+ alignItems: "center",
"& div": {
- margin: ".5rem",
+ margin: theme.spacing(1),
+ flexBasis: "33%",
+ "&$tokenImageContainer": {
+ maxWidth: 40,
+ },
+ "&:last-child": {
+ textAlign: "right",
+ },
},
},
+ tokenImageContainer: {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "center",
+ width: 40,
+ },
tokenImage: {
maxHeight: "2.5rem", //Eyeballing this based off the text size
},
+ v1Warning: {
+ width: "100%",
+ },
+ migrationAlert: {
+ width: "100%",
+ "& .MuiAlert-message": {
+ width: "100%",
+ },
+ },
})
);
@@ -169,39 +199,39 @@ export default function SolanaSourceTokenSelector(
const name = getName(account) || "--";
const content = (
- <>
-
-
- {uri &&
}
-
-
- {symbol}
- {name}
-
-
- {account.isNativeAsset ? (
- {"Native"}
- ) : (
- <>
-
- {"Mint : " + mintPrettyString}
-
-
- {"Account :" + accountAddressPrettyString}
-
- >
- )}
-
+
+
+ {uri &&
}
+
+
+ {symbol}
+ {name}
+
+
+ {account.isNativeAsset ? (
+ {"Native"}
+ ) : (
+ <>
+
+ {"Mint : " + mintPrettyString}
+
+
+ {"Account :" + accountAddressPrettyString}
+
+ >
+ )}
+
+ {nft ? null : (
{"Balance"}
{account.uiAmountString}
-
- >
+ )}
+
);
const v1Warning = (
-
+
Wormhole v1 tokens are not eligible for transfer.
@@ -210,7 +240,7 @@ export default function SolanaSourceTokenSelector(
);
const migrationRender = (
-
+
This is a legacy asset eligible for migration.
@@ -226,7 +256,15 @@ export default function SolanaSourceTokenSelector(
? v1Warning
: content;
},
- [getLogo, getSymbol, getName, classes, isWormholev1, isMigrationEligible]
+ [
+ getLogo,
+ getSymbol,
+ getName,
+ classes,
+ isWormholev1,
+ isMigrationEligible,
+ nft,
+ ]
);
//The autocomplete doesn't rerender the option label unless the value changes.
@@ -244,18 +282,26 @@ export default function SolanaSourceTokenSelector(
//This exists to remove NFTs from the list of potential options. It requires reading the metaplex data, so it would be
//difficult to do before this point.
const filteredOptions = useMemo(() => {
- return props.accounts.filter((x) => {
- const zeroBalance = x.amount === "0";
- if (zeroBalance) {
- return false;
- }
- const isNFT =
- x.decimals === 0 &&
- metaplex.data?.get(x.mintKey)?.data?.uri &&
- mintAccounts?.data?.get(x.mintKey)?.supply === "1";
- return nft ? isNFT : !isNFT;
- });
- }, [mintAccounts?.data, metaplex.data, nft, props.accounts]);
+ const tokenList = props.accounts
+ .filter((x) => {
+ const zeroBalance = x.amount === "0";
+ if (zeroBalance) {
+ return false;
+ }
+ const isNFT =
+ x.decimals === 0 &&
+ metaplex.data?.get(x.mintKey)?.data?.uri &&
+ mintAccounts?.data?.get(x.mintKey)?.supply === "1";
+ return nft ? isNFT : !isNFT;
+ })
+ .map((account) => ({
+ ...account,
+ symbol: account.symbol || getSymbol(account) || undefined,
+ }));
+ tokenList.sort(sortParsedTokenAccounts);
+ return tokenList;
+ }, [mintAccounts?.data, metaplex.data, nft, props.accounts, getSymbol]);
+ console.log(filteredOptions);
const isOptionDisabled = useMemo(() => {
return (value: ParsedTokenAccount) => {
@@ -314,7 +360,6 @@ export default function SolanaSourceTokenSelector(
+const useStyles = makeStyles((theme) =>
createStyles({
selectInput: { minWidth: "10rem" },
tokenOverviewContainer: {
display: "flex",
+ width: "100%",
+ alignItems: "center",
"& div": {
- margin: ".5rem",
+ margin: theme.spacing(1),
+ "&$tokenImageContainer": {
+ maxWidth: 40,
+ },
},
},
+ tokenImageContainer: {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "center",
+ width: 40,
+ },
tokenImage: {
- maxHeight: "2.5rem",
+ maxHeight: "2.5rem", //Eyeballing this based off the text size
+ },
+ tokenSymbolContainer: {
+ flexBasis: 112,
},
})
);
@@ -168,10 +182,10 @@ export default function TerraSourceTokenSelector(
const renderOption = (option: TerraTokenMetadata) => {
return (
-
+
-
+
{option.symbol}
{option.protocol}
@@ -200,7 +214,6 @@ export default function TerraSourceTokenSelector(
+ a.isNativeAsset && !b.isNativeAsset
+ ? -1
+ : !a.isNativeAsset && b.isNativeAsset
+ ? 1
+ : a.symbol && b.symbol
+ ? a.symbol.localeCompare(b.symbol)
+ : a.symbol
+ ? -1
+ : b.symbol
+ ? 1
+ : 0;