Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show Ether for custom gas token chains #1764

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/arb-token-bridge-ui/src/components/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const ArbTokenBridgeStoreSyncWrapper = (): JSX.Element | null => {
selectedTokenAddress === nativeCurrency.address ||
selectedTokenL2Address === nativeCurrency.address
) {
actions.app.setSelectedToken(null)
actions.app.setSelectedToken({ token: null })
Copy link
Contributor Author

@brtkx brtkx Jul 18, 2024

Choose a reason for hiding this comment

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

setSelectedToken payload has changed to include an optional flag isSelectedTokenEther.

When isSelectedTokenEther === true and token === null, everything will assume that the native currency is Ether.

When isSelectedTokenEther === false and token === null, everything will work as previously, which means it will default to the native currency on the child chain. Note this still could be ETH, isSelectedTokenEther just serves as an override to cover custom gas token scenarios.

When isSelectedTokenEther is not provided it will always set it to false, so that we don't have to refactor the majority of the existing code. All we have to do is to pass a token object instead.

See actions.ts and state.ts for more.

}
}, [selectedToken, nativeCurrency])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { ChevronDownIcon } from '@heroicons/react/24/outline'
import { twMerge } from 'tailwind-merge'

import { useAppState } from '../../state'
import { sanitizeImageSrc } from '../../util'
import { TokenSearch } from '../TransferPanel/TokenSearch'
import { sanitizeTokenSymbol } from '../../util/TokenUtils'
import { useNativeCurrency } from '../../hooks/useNativeCurrency'
Expand All @@ -16,53 +15,32 @@ import {
import { useNetworks } from '../../hooks/useNetworks'
import { useNetworksRelationship } from '../../hooks/useNetworksRelationship'
import { Transition } from '../common/Transition'
import { ether } from '../../constants'

export function TokenButton(): JSX.Element {
const {
app: {
selectedToken,
arbTokenBridge: { bridgeTokens },
arbTokenBridgeLoaded
}
app: { selectedToken, isSelectedTokenEther }
} = useAppState()
const [networks] = useNetworks()
const { childChainProvider } = useNetworksRelationship(networks)

const nativeCurrency = useNativeCurrency({ provider: childChainProvider })

const tokenLogo = useMemo<string | undefined>(() => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not used

const selectedAddress = selectedToken?.address
if (!selectedAddress) {
return nativeCurrency.logoUrl
}
if (!arbTokenBridgeLoaded) {
return undefined
}
if (typeof bridgeTokens === 'undefined') {
return undefined
}
const logo = bridgeTokens[selectedAddress]?.logoURI
if (logo) {
return sanitizeImageSrc(logo)
}
return undefined
}, [
nativeCurrency,
bridgeTokens,
selectedToken?.address,
arbTokenBridgeLoaded
])

const tokenSymbol = useMemo(() => {
if (!selectedToken) {
return nativeCurrency.symbol
return isSelectedTokenEther ? ether.symbol : nativeCurrency.symbol
}

return sanitizeTokenSymbol(selectedToken.symbol, {
erc20L1Address: selectedToken.address,
chainId: networks.sourceChain.id
})
}, [selectedToken, networks.sourceChain.id, nativeCurrency.symbol])
}, [
selectedToken,
networks.sourceChain.id,
isSelectedTokenEther,
nativeCurrency.symbol
])

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export function TokenImportDialog({
const selectToken = useCallback(
async (_token: ERC20BridgeToken) => {
await token.updateTokenData(_token.address)
actions.app.setSelectedToken(_token)
actions.app.setSelectedToken({ token: _token })
},
[token, actions]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import { StatusBadge } from '../common/StatusBadge'
import { ERC20BridgeToken } from '../../hooks/arbTokenBridge.types'
import { ExternalLink } from '../common/ExternalLink'
import { useAccountType } from '../../hooks/useAccountType'
import { useNativeCurrency } from '../../hooks/useNativeCurrency'
import {
isNativeCurrencyEther,
NativeCurrencyEther,
useNativeCurrency
} from '../../hooks/useNativeCurrency'
import { useNetworks } from '../../hooks/useNetworks'
import { useNetworksRelationship } from '../../hooks/useNetworksRelationship'
import { TokenLogoFallback } from './TokenInfo'
Expand Down Expand Up @@ -69,14 +73,23 @@ function BlockExplorerTokenLink({
)
}

function TokenListInfo({ token }: { token: ERC20BridgeToken | null }) {
function TokenListInfo({
token
}: {
token: ERC20BridgeToken | NativeCurrencyEther | null
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here, and in some of the following methods, we pass an additional NativeCurrencyEther. This way we can check for it and return ETH details as needed.

}) {
const [networks] = useNetworks()
const { childChain, childChainProvider } = useNetworksRelationship(networks)
const { childChain, childChainProvider, parentChain } =
useNetworksRelationship(networks)
const { isCustom: childChainNativeCurrencyIsCustom } = useNativeCurrency({
provider: childChainProvider
})

const tokenListInfo = useMemo(() => {
if (isNativeCurrencyEther(token)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

isNativeCurrencyEther is a type guard method that checks for NativeCurrencyEther type. This way we can early check for ETH stuff and keep the rest of the code as-is.

See useNativeCurrency.ts for more.

return null
}

if (!token) {
return null
}
Expand Down Expand Up @@ -109,6 +122,16 @@ function TokenListInfo({ token }: { token: ERC20BridgeToken | null }) {
)
}, [token])

if (isNativeCurrencyEther(token)) {
const parentChainName = getNetworkName(parentChain.id)

return (
<span className="flex text-xs text-white/70">
Native token on {parentChainName}
</span>
)
}

if (!token) {
const nativeTokenChain = getNetworkName(
(childChainNativeCurrencyIsCustom ? childChain : networks.sourceChain).id
Expand All @@ -135,18 +158,26 @@ function TokenListInfo({ token }: { token: ERC20BridgeToken | null }) {

interface TokenRowProps {
style?: React.CSSProperties
onTokenSelected: (token: ERC20BridgeToken | null) => void
token: ERC20BridgeToken | null
onTokenSelected: (
token: ERC20BridgeToken | NativeCurrencyEther | null
) => void
token: ERC20BridgeToken | NativeCurrencyEther | null
}

function useTokenInfo(token: ERC20BridgeToken | null) {
function useTokenInfo(token: ERC20BridgeToken | NativeCurrencyEther | null) {
const [networks] = useNetworks()
const { childChain, childChainProvider, parentChain, isDepositMode } =
useNetworksRelationship(networks)
const chainId = isDepositMode ? parentChain.id : childChain.id
const nativeCurrency = useNativeCurrency({ provider: childChainProvider })

const name = useMemo(() => {
if (isNativeCurrencyEther(token)) {
return sanitizeTokenName(token.name, {
chainId
})
}

if (token) {
return sanitizeTokenName(token.name, {
erc20L1Address: token.address,
Expand All @@ -158,6 +189,12 @@ function useTokenInfo(token: ERC20BridgeToken | null) {
}, [token, nativeCurrency.name, chainId])

const symbol = useMemo(() => {
if (isNativeCurrencyEther(token)) {
return sanitizeTokenSymbol(token.symbol, {
chainId
})
}

if (token) {
return sanitizeTokenSymbol(token.symbol, {
erc20L1Address: token.address,
Expand All @@ -169,6 +206,10 @@ function useTokenInfo(token: ERC20BridgeToken | null) {
}, [token, nativeCurrency.symbol, chainId])

const logoURI = useMemo(() => {
if (isNativeCurrencyEther(token)) {
return token.logoUrl
}

if (!token) {
return nativeCurrency.logoUrl
}
Expand All @@ -179,6 +220,10 @@ function useTokenInfo(token: ERC20BridgeToken | null) {
const balance = useBalanceOnSourceChain(token)

const isArbitrumToken = useMemo(() => {
if (isNativeCurrencyEther(token)) {
return false
}

if (!token) {
return false
}
Expand All @@ -198,6 +243,10 @@ function useTokenInfo(token: ERC20BridgeToken | null) {
}, [token, isArbitrumToken])

const isBridgeable = useMemo(() => {
if (isNativeCurrencyEther(token)) {
return true
}

if (!token) {
return true
}
Expand Down Expand Up @@ -236,7 +285,11 @@ function ArbitrumTokenBadge() {
)
}

function TokenBalance({ token }: { token: ERC20BridgeToken | null }) {
function TokenBalance({
token
}: {
token: ERC20BridgeToken | NativeCurrencyEther | null
}) {
const {
app: {
arbTokenBridge: { bridgeTokens }
Expand All @@ -246,15 +299,20 @@ function TokenBalance({ token }: { token: ERC20BridgeToken | null }) {
const { balance, symbol } = useTokenInfo(token)

const isArbitrumNativeUSDC =
isTokenArbitrumOneNativeUSDC(token?.address) ||
isTokenArbitrumSepoliaNativeUSDC(token?.address)
!isNativeCurrencyEther(token) &&
(isTokenArbitrumOneNativeUSDC(token?.address) ||
isTokenArbitrumSepoliaNativeUSDC(token?.address))

const tokenIsAddedToTheBridge = useMemo(() => {
// Can happen when switching networks.
if (typeof bridgeTokens === 'undefined') {
return true
}

if (isNativeCurrencyEther(token)) {
return true
}

if (!token) {
return true
}
Expand Down Expand Up @@ -289,7 +347,11 @@ function TokenBalance({ token }: { token: ERC20BridgeToken | null }) {
)
}

function TokenContractLink({ token }: { token: ERC20BridgeToken | null }) {
function TokenContractLink({
token
}: {
token: ERC20BridgeToken | NativeCurrencyEther | null
}) {
const [networks] = useNetworks()
const { childChain, childChainProvider, parentChain, isDepositMode } =
useNetworksRelationship(networks)
Expand All @@ -298,6 +360,10 @@ function TokenContractLink({ token }: { token: ERC20BridgeToken | null }) {

const isCustomFeeTokenRow = token === null && nativeCurrency.isCustom

if (isNativeCurrencyEther(token)) {
return null
}

if (isCustomFeeTokenRow && isDepositMode) {
return (
<BlockExplorerTokenLink
Expand Down
Loading
Loading