Skip to content

Commit

Permalink
feat: Add icon overlay with one Eth asset on Arbitrum or Optimism (#5175
Browse files Browse the repository at this point in the history
)

### Description

Currently, when a user has one balance of Eth, users cannot tell the
difference between on different networks (Ethereum, Arbitrum, Optimism).
This change add an network icon over the token icon for Eth when held on
either Arb or Op.

### Test plan

Tests for presence of TokenIcon and presence / absence of NetworkIcon
depending on network, and passes all tests.

### Related issues

- Fixes ACT-1086

### Backwards compatibility

Passes all previous tests

### Network scalability

If a new NetworkId and/or Network are added in the future, the changes
in this PR will continue to work without code changes but will require
additional testing for new changes
  • Loading branch information
chriskeating603 committed Mar 29, 2024
1 parent 5914690 commit 9f68dea
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ android/app/src/main/res/mipmap*
ios/celo/Base.lproj/*
!ios/celo/Base.lproj/InfoPlist.strings
ios/celo/Images.xcassets/
ios/.xcode.env
src/brandingConfig.ts
src/icons/Logo.tsx
src/icons/Home.tsx
Expand Down
114 changes: 113 additions & 1 deletion src/components/TokenBalance.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ import { StatsigFeatureGates } from 'src/statsig/types'
import { NetworkId } from 'src/transactions/types'
import { ONE_DAY_IN_MILLIS } from 'src/utils/time'
import { createMockStore, getElementText } from 'test/utils'
import { mockPositions, mockTokenBalances } from 'test/values'
import {
mockARBTokenId,
mockEthTokenId,
mockOPTokenId,
mockPositions,
mockTokenBalances,
} from 'test/values'

jest.mock('src/statsig')

Expand Down Expand Up @@ -707,3 +713,109 @@ describe.each([
expect(getElementText(tree.getByTestId('TotalTokenBalance'))).toEqual('₱-')
})
})

describe('renders the network icon on the home screen to differentiate between ETH on Ethereum, Arbitrum, and Optimism', () => {
beforeEach(() => {
jest.clearAllMocks()
jest.mocked(getDynamicConfigParams).mockReturnValue({
showBalances: [
NetworkId['ethereum-sepolia'],
NetworkId['celo-alfajores'],
NetworkId['arbitrum-sepolia'],
NetworkId['op-sepolia'],
],
})
})

it('renders TokenIcon correctly with only ETH token balance on Ethereum', async () => {
const store = createMockStore({
...defaultStore,
tokens: {
tokenBalances: {
[mockEthTokenId]: {
...mockTokenBalances[mockEthTokenId],
balance: '0.508480716806023',
},
},
},
positions: {
positions: [],
},
})

const tree = render(
<Provider store={store}>
<HomeTokenBalance />
</Provider>
)

const tokenIconImage = tree.getByTestId('TokenIcon')
expect(tokenIconImage.props.source.uri).toEqual(mockTokenBalances[mockEthTokenId].imageUrl)
const networkIcon = tree.queryByTestId('NetworkIcon')
expect(networkIcon).toBeNull()
})

it('renders TokenIcon correctly with only ETH token balance on Optimism', async () => {
const store = createMockStore({
...defaultStore,
tokens: {
tokenBalances: {
[mockOPTokenId]: {
...mockTokenBalances[mockOPTokenId],
balance: '0.308480716806023',
networkIconUrl:
'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/OP.png',
},
},
},
positions: {
positions: [],
},
})

const tree = render(
<Provider store={store}>
<HomeTokenBalance />
</Provider>
)

const tokenIconImage = tree.getByTestId('TokenIcon')
expect(tokenIconImage.props.source.uri).toEqual(mockTokenBalances[mockOPTokenId].imageUrl)
const networkIconImage = tree.getByTestId('NetworkIcon')
expect(networkIconImage.props.source.uri).toEqual(
'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/OP.png'
)
})

it('renders TokenIcon correctly with only ETH token balance on Arbitrum', async () => {
const store = createMockStore({
...defaultStore,
tokens: {
tokenBalances: {
[mockARBTokenId]: {
...mockTokenBalances[mockARBTokenId],
balance: '0.108480716806023',
networkIconUrl:
'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ARB.png',
},
},
},
positions: {
positions: [],
},
})

const tree = render(
<Provider store={store}>
<HomeTokenBalance />
</Provider>
)

const tokenIconImage = tree.getByTestId('TokenIcon')
expect(tokenIconImage.props.source.uri).toEqual(mockTokenBalances[mockARBTokenId].imageUrl)
const networkIconImage = tree.getByTestId('NetworkIcon')
expect(networkIconImage.props.source.uri).toEqual(
'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ARB.png'
)
})
})
12 changes: 7 additions & 5 deletions src/components/TokenBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import BigNumber from 'bignumber.js'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import {
Image,
StyleProp,
StyleSheet,
Text,
Expand All @@ -20,6 +19,7 @@ import { toggleHideBalances } from 'src/app/actions'
import { hideHomeBalancesSelector, hideWalletBalancesSelector } from 'src/app/selectors'
import Dialog from 'src/components/Dialog'
import { formatValueToDisplay } from 'src/components/TokenDisplay'
import TokenIcon, { IconSize } from 'src/components/TokenIcon'
import Touchable from 'src/components/Touchable'
import { useShowOrHideAnimation } from 'src/components/useShowOrHideAnimation'
import { refreshAllBalances } from 'src/home/actions'
Expand Down Expand Up @@ -105,7 +105,11 @@ function TokenBalance({
const tokenBalance = tokensWithUsdValue[0].balance
return (
<View style={styles.oneBalance}>
<Image source={{ uri: tokensWithUsdValue[0].imageUrl }} style={styles.tokenImg} />
<TokenIcon
token={tokensWithUsdValue[0]}
size={IconSize.XLARGE}
viewStyle={styles.tokenImgView}
/>
<View style={styles.column}>
<TotalTokenBalance balanceDisplay={balanceDisplay ?? '-'} />
{!hideBalance && (
Expand Down Expand Up @@ -403,9 +407,7 @@ const styles = StyleSheet.create({
oneBalance: {
flexDirection: 'row',
},
tokenImg: {
width: 48,
height: 48,
tokenImgView: {
borderRadius: 24,
marginRight: 8,
},
Expand Down
7 changes: 7 additions & 0 deletions src/components/TokenIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export enum IconSize {
SMALL = 'small',
MEDIUM = 'medium',
LARGE = 'large',
XLARGE = 'xlarge',
}

const IconSizeToStyle = {
Expand All @@ -29,6 +30,12 @@ const IconSizeToStyle = {
networkImagePosition: 25,
tokenTextSize: 12,
},
[IconSize.XLARGE]: {
tokenImageSize: 48,
networkImageSize: 20,
networkImagePosition: 30,
tokenTextSize: 14,
},
}

interface Props {
Expand Down
30 changes: 30 additions & 0 deletions test/values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ export const mockCrealTokenId = `celo-alfajores:${mockCrealAddress}`
export const mockWBTCTokenId = `celo-alfajores:${mockWBTCAddress}`
export const mockEthTokenId = 'ethereum-sepolia:native'
export const mockUSDCTokenId = `ethereum-sepolia:${mockUSDCAddress}`
export const mockARBTokenId = `arbitrum-sepolia:native`
export const mockOPTokenId = `op-sepolia:native`

export const mockQrCodeData2 = {
address: mockAccount2Invite,
Expand Down Expand Up @@ -537,6 +539,34 @@ export const mockTokenBalances: Record<string, StoredTokenBalance> = {
balance: '0',
priceUsd: '1',
},
[mockARBTokenId]: {
name: 'Ethereum',
networkId: NetworkId['arbitrum-sepolia'],
tokenId: mockARBTokenId,
address: null,
symbol: 'ETH',
decimals: 18,
imageUrl:
'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png',
balance: '0',
priceUsd: '1500',
isNative: true,
priceFetchedAt: Date.now(),
},
[mockOPTokenId]: {
name: 'Ethereum',
networkId: NetworkId['op-sepolia'],
tokenId: mockOPTokenId,
address: null,
symbol: 'ETH',
decimals: 18,
imageUrl:
'https://raw.githubusercontent.com/valora-inc/address-metadata/main/assets/tokens/ETH.png',
balance: '0',
priceUsd: '1500',
isNative: true,
priceFetchedAt: Date.now(),
},
}

export const mockCeloTokenBalance: TokenBalance = {
Expand Down

0 comments on commit 9f68dea

Please sign in to comment.