Skip to content

Commit

Permalink
Overlay the original token logo and symbol for bridged tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
Lbqds committed Nov 5, 2024
1 parent 4ebe86e commit f44b022
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 25 deletions.
3 changes: 2 additions & 1 deletion bridge_ui/src/components/TokenSelectors/EvmTokenPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default function EvmTokenPicker(
);
} else {
return ethTokenToParsedTokenAccount(
chainId,
tokenAccount as ethers_contracts.TokenImplementation,
signerAddress
);
Expand All @@ -100,7 +101,7 @@ export default function EvmTokenPicker(
return Promise.reject({ error: t("Wallet is not connected.") });
}
},
[isReady, nft, provider, signerAddress, t]
[isReady, nft, provider, signerAddress, t, chainId]
);

const onChangeWrapper = useCallback(
Expand Down
2 changes: 2 additions & 0 deletions bridge_ui/src/components/Transfer/AddToMetamask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default function AddToMetamask() {
try {
const token = await getEthereumToken(targetAsset, provider);
const { symbol, decimals } = await ethTokenToParsedTokenAccount(
targetChain,
token,
signerAddress
);
Expand Down Expand Up @@ -74,6 +75,7 @@ export default function AddToMetamask() {
signerAddress,
hasCorrectEvmNetwork,
sourceParsedTokenAccount,
targetChain
]);
return provider &&
signerAddress &&
Expand Down
38 changes: 26 additions & 12 deletions bridge_ui/src/hooks/useGetSourceParsedTokenAccounts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
WSOL_ADDRESS,
WSOL_DECIMALS,
hexToUint8Array,
getTokenPoolId
getTokenPoolId,
tryNativeToHexString
} from "@alephium/wormhole-sdk";
import { Dispatch } from "@reduxjs/toolkit";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
Expand Down Expand Up @@ -125,10 +126,10 @@ import {
} from "../utils/solana";
import { fetchSingleMetadata } from "./useAlgoMetadata";
import { ALPH_TOKEN_ID, NodeProvider } from "@alephium/web3";
import { getAvailableBalances, getAlephiumTokenLogoURI } from "../utils/alephium";
import { getAvailableBalances, getAlephiumTokenLogoAndSymbol } from "../utils/alephium";
import { getRegisteredTokens } from "../utils/tokens";
import { useWallet } from "@alephium/web3-react";
import { getETHTokenLogoURI } from "../utils/evm";
import { getBSCTokenLogoAndSymbol, getETHTokenLogoAndSymbol } from "../utils/evm";
import { Alert } from "@material-ui/lab";
import parseError from "../utils/parseError";
import i18n from "../i18n";
Expand Down Expand Up @@ -622,13 +623,13 @@ export const getEVMAccounts = async (chainId: ChainId, signer: ethers.Signer, wa
if (tokenAccounts.find((t) => t.contract_address.toLowerCase() === result.tokenId.toLowerCase()) !== undefined) {
continue
}
const tokenLogoURI = await getTokenLogoURI(token.tokenChain, token.nativeAddress)
const info = await getTokenLogoAndSymbol(token.tokenChain, token.nativeAddress)
tokenAccounts.push({
contract_decimals: token.decimals,
contract_ticker_symbol: token.symbol,
contract_ticker_symbol: info?.symbol ?? token.symbol,
contract_name: token.name,
contract_address: result.tokenId,
logo_url: token.logo ?? tokenLogoURI,
logo_url: info?.logoURI ?? token.logo,
balance: result.balance.toString(),
quote: undefined,
quote_rate: undefined
Expand Down Expand Up @@ -774,7 +775,7 @@ const getAlephiumParsedTokenAccounts = async (address: string, provider: NodePro
const amount = balances.get(localTokenId.toLowerCase())
if (amount === undefined) continue

const tokenLogoURI = await getTokenLogoURI(token.tokenChain, token.nativeAddress)
const info = await getTokenLogoAndSymbol(token.tokenChain, token.nativeAddress)
const uiAmount = formatUnits(amount, token.decimals)
tokenAccounts.push(createParsedTokenAccount(
address,
Expand All @@ -783,9 +784,9 @@ const getAlephiumParsedTokenAccounts = async (address: string, provider: NodePro
token.decimals,
parseFloat(uiAmount),
uiAmount,
token.symbol,
info?.symbol ?? token.symbol,
token.name,
tokenLogoURI,
info?.logoURI ?? token.logo,
localTokenId === ALPH_TOKEN_ID
))
}
Expand All @@ -797,11 +798,24 @@ const getAlephiumParsedTokenAccounts = async (address: string, provider: NodePro
}
}

async function getTokenLogoURI(tokenChainId: ChainId, tokenId: string): Promise<string | undefined> {
async function getTokenLogoAndSymbol(tokenChainId: ChainId, tokenId: string): Promise<{ logoURI?: string, symbol?: string } | undefined> {
if (tokenChainId !== CHAIN_ID_ALEPHIUM) {
const wrappedIdOnALPH = getTokenPoolId(
ALEPHIUM_TOKEN_BRIDGE_CONTRACT_ID,
tokenChainId,
tryNativeToHexString(tokenId, tokenChainId),
ALEPHIUM_BRIDGE_GROUP_INDEX
)
const info = await getAlephiumTokenLogoAndSymbol(wrappedIdOnALPH)
if (info !== undefined) return info
}

if (tokenChainId === CHAIN_ID_ETH) {
return getETHTokenLogoURI(tokenId)
return getETHTokenLogoAndSymbol(tokenId)
} else if (tokenChainId === CHAIN_ID_ALEPHIUM) {
return getAlephiumTokenLogoURI(tokenId)
return getAlephiumTokenLogoAndSymbol(tokenId)
} else if (tokenChainId === CHAIN_ID_BSC) {
return getBSCTokenLogoAndSymbol(tokenId)
} else {
return undefined
}
Expand Down
9 changes: 9 additions & 0 deletions bridge_ui/src/utils/alephium.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ export async function getAlephiumTokenInfo(provider: NodeProvider, tokenId: stri
}
}

export async function getAlephiumTokenLogoAndSymbol(tokenId: string) {
if (tokenId === ALPH_TOKEN_ID) {
return { logoURI: alephiumIcon, symbol: 'ALPH' }
}
const tokenInfo = await getTokenFromTokenList(tokenId)
if (tokenInfo === undefined) return undefined
return { logoURI: tokenInfo.logoURI, symbol: tokenInfo.symbol }
}

export async function getAlephiumTokenLogoURI(tokenId: string): Promise<string | undefined> {
return tokenId === ALPH_TOKEN_ID
? alephiumIcon
Expand Down
57 changes: 45 additions & 12 deletions bridge_ui/src/utils/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,59 @@ interface TokenInfo {
logoURI: string
}

let _whitelist: TokenInfo[] | undefined = undefined
const TokenListURLs = {
[CHAIN_ID_ETH]: 'https://tokens-1inch-eth.ipns.dweb.link/',
[CHAIN_ID_BSC]: 'https://tokens.coingecko.com/binance-smart-chain/all.json'
}

let _tokenWhiteList: Map<ChainId, TokenInfo[] | undefined> = new Map()

function getTokenListURL(chainId: ChainId): string {
if (chainId === CHAIN_ID_BSC || chainId === CHAIN_ID_ETH) {
return TokenListURLs[chainId]
}
throw new Error(`Invalid evm chain id: ${chainId}`)
}

async function loadETHTokenWhitelist(): Promise<TokenInfo[]> {
if (_whitelist !== undefined) return _whitelist
const { data: { tokens } } = await axios.get('https://tokens-1inch-eth.ipns.dweb.link/')
_whitelist = tokens
async function loadEVMTokenWhitelist(chainId: ChainId): Promise<TokenInfo[]> {
const whitelist = _tokenWhiteList.get(chainId)
if (whitelist !== undefined) return whitelist
const url = getTokenListURL(chainId)
const { data: { tokens } } = await axios.get(url)
_tokenWhiteList.set(chainId, tokens)
return tokens
}

export async function checkETHToken(tokenAddress: string) {
async function checkEVMToken(chainId: ChainId, tokenAddress: string) {
if (CLUSTER !== 'mainnet') return

const tokenWhitelist = await loadETHTokenWhitelist()
const tokenWhitelist = await loadEVMTokenWhitelist(chainId)
if (tokenWhitelist.find((token) => token.address.toLowerCase() === tokenAddress.toLowerCase()) === undefined) {
throw new Error(`${i18n.t('Token {{ tokenAddress }} does not exist in the token list', { tokenAddress })}: https://tokenlists.org/token-list?url=tokens.1inch.eth`)
throw new Error(`${i18n.t('Token {{ tokenAddress }} does not exist in the token list', { tokenAddress })}: ${getTokenListURL(chainId)}`)
}
}

export async function getETHTokenLogoURI(tokenAddress: string): Promise<string | undefined> {
const tokenWhitelist = await loadETHTokenWhitelist()
return tokenWhitelist.find((token) => token.address.toLowerCase() === tokenAddress.toLowerCase())?.logoURI
async function getEVMTokenLogoAndSymbol(chainId: ChainId, tokenAddress: string) {
const tokenWhitelist = await loadEVMTokenWhitelist(chainId)
const tokenInfo = tokenWhitelist.find((token) => token.address.toLowerCase() === tokenAddress.toLowerCase())
if (tokenInfo === undefined) return undefined
return { logoURI: tokenInfo.logoURI, symbol: tokenInfo.symbol }
}

export async function checkETHToken(tokenAddress: string) {
await checkEVMToken(CHAIN_ID_ETH, tokenAddress)
}

export async function getETHTokenLogoAndSymbol(tokenAddress: string) {
return await getEVMTokenLogoAndSymbol(CHAIN_ID_ETH, tokenAddress)
}

export async function checkBSCToken(tokenAddress: string) {
await checkEVMToken(CHAIN_ID_BSC, tokenAddress)
}

export async function getBSCTokenLogoAndSymbol(tokenAddress: string) {
return await getEVMTokenLogoAndSymbol(CHAIN_ID_BSC, tokenAddress)
}

//This is a valuable intermediate step to the parsed token account, as the token has metadata information on it.
Expand All @@ -55,14 +87,15 @@ export async function getEthereumToken(
}

export async function ethTokenToParsedTokenAccount(
chainId: ChainId,
token: ethers_contracts.TokenImplementation,
signerAddress: string
) {
const decimals = await token.decimals();
const balance = await token.balanceOf(signerAddress);
const symbol = await token.symbol();
const name = await token.name();
const logoURI = await getETHTokenLogoURI(token.address)
const logoURI = (await getEVMTokenLogoAndSymbol(chainId, token.address))?.logoURI
return createParsedTokenAccount(
signerAddress,
token.address,
Expand Down

0 comments on commit f44b022

Please sign in to comment.