From 729f22f0eabb421141498231708eb36df62bb5bd Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 9 Feb 2024 12:09:08 -0500 Subject: [PATCH 01/12] save --- .../FastComponents/FastBalanceCoinRow.tsx | 14 +++++--------- .../FastComponents/FastCoinIcon.tsx | 1 + 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastBalanceCoinRow.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastBalanceCoinRow.tsx index 2ed25dbf1ad..a2da80d7fb4 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastBalanceCoinRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastBalanceCoinRow.tsx @@ -5,11 +5,13 @@ import { Icon } from '../../../../components/icons'; import { ButtonPressAnimation } from '../../../animations'; import { ExtendedState } from '../core/RawRecyclerList'; -import FastCoinIcon from './FastCoinIcon'; + import { Text } from '@/design-system'; import { useAccountAsset, useCoinListFinishEditingOptions } from '@/hooks'; import Routes from '@/navigation/routesNames'; import { borders, colors, padding, shadow } from '@/styles'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; +import { ParsedAddressAsset } from '@/entities'; interface CoinCheckButtonProps { isHidden: boolean; @@ -63,7 +65,7 @@ interface MemoizedBalanceCoinRowProps { const MemoizedBalanceCoinRow = React.memo( ({ uniqueId, nativeCurrency, theme, navigate, nativeCurrencySymbol, isHidden, maybeCallback }: MemoizedBalanceCoinRowProps) => { - const item = useAccountAsset(uniqueId, nativeCurrency); + const item = useAccountAsset(uniqueId, nativeCurrency) as any; const handlePress = useCallback(() => { if (maybeCallback.current) { @@ -94,13 +96,7 @@ const MemoizedBalanceCoinRow = React.memo( <ButtonPressAnimation onPress={handlePress} scaleTo={0.96} testID={`balance-coin-row-${item?.name}`}> <View style={[sx.container]}> <View style={sx.iconContainer}> - <FastCoinIcon - address={item?.address} - network={item?.network} - mainnetAddress={item?.mainnet_address} - symbol={item?.symbol} - theme={theme} - /> + <RainbowCoinIcon size={40} icon={item?.icon_url} network={item?.network} symbol={item?.symbol} theme={theme} /> </View> <View style={[sx.innerContainer, isHidden && sx.hiddenRow]}> diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx index fc98617f2f7..ee3ae0da0d9 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx @@ -86,6 +86,7 @@ export default React.memo(function FastCoinIcon({ <Image source={ContractInteraction} style={sx.contract} /> ) : ( <FastFallbackCoinIconImage + icon={icon} address={resolvedAddress} network={resolvedNetwork} shadowColor={shadowColor} From 0ee904b7e4b31cbbd0ddadf03fe3beace9a29bca Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 9 Feb 2024 12:10:01 -0500 Subject: [PATCH 02/12] save new files --- src/components/coin-icon/RainbowCoinIcon.tsx | 90 ++++++++++++++++++ src/components/images/FastImgixImage.tsx | 96 ++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 src/components/coin-icon/RainbowCoinIcon.tsx create mode 100644 src/components/images/FastImgixImage.tsx diff --git a/src/components/coin-icon/RainbowCoinIcon.tsx b/src/components/coin-icon/RainbowCoinIcon.tsx new file mode 100644 index 00000000000..d0508e57929 --- /dev/null +++ b/src/components/coin-icon/RainbowCoinIcon.tsx @@ -0,0 +1,90 @@ +import React from 'react'; +import { StyleSheet, View } from 'react-native'; +import { Network } from '@/networks/types'; +import { borders, fonts } from '@/styles'; +import { ThemeContextProps } from '@/theme'; +import { FallbackIcon as CoinIconTextFallback } from '@/utils'; + +import { FastFallbackCoinIconImage } from '../asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage'; +import { FastChainBadge } from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinBadge'; + +const fallbackTextStyles = { + fontFamily: fonts.family.SFProRounded, + fontWeight: fonts.weight.bold, + letterSpacing: fonts.letterSpacing.roundedTight, + marginBottom: 0.5, + textAlign: 'center', +}; + +const fallbackIconStyle = { + ...borders.buildCircleAsObject(40), + position: 'absolute', +}; + +export default React.memo(function FastCoinIcon({ + size = 40, + icon, + network, + symbol, + theme, + colors, + ignoreBadge, + badgeXPosition, + badgeYPosition, +}: { + size?: number; + icon: string; + network: Network; + symbol: string; + theme: ThemeContextProps; + colors?: { + primary?: string; + fallback?: string; + }; + ignoreBadge?: boolean; + badgeXPosition?: number; + badgeYPosition?: number; +}) { + const fallbackIconColor = colors?.primary || colors?.fallback || theme.colors.purpleUniswap; + + const shadowColor = theme.isDarkMode ? theme.colors.shadow : colors?.primary || colors?.fallback || theme.colors.shadow; + + return ( + <View style={sx.container}> + <FastFallbackCoinIconImage icon={icon} shadowColor={shadowColor} symbol={symbol} theme={theme} size={size}> + {() => ( + <CoinIconTextFallback + color={fallbackIconColor} + height={size} + style={fallbackIconStyle} + symbol={symbol} + textStyles={fallbackTextStyles} + width={size} + /> + )} + </FastFallbackCoinIconImage> + + {!ignoreBadge && network && <FastChainBadge network={network} theme={theme} />} + </View> + ); +}); + +const sx = StyleSheet.create({ + container: { + elevation: 6, + overflow: 'visible', + }, + reactCoinIconContainer: { + alignItems: 'center', + justifyContent: 'center', + }, + withShadow: { + elevation: 6, + shadowOffset: { + height: 4, + width: 0, + }, + shadowOpacity: 0.3, + shadowRadius: 6, + }, +}); diff --git a/src/components/images/FastImgixImage.tsx b/src/components/images/FastImgixImage.tsx new file mode 100644 index 00000000000..e44dcfaa47f --- /dev/null +++ b/src/components/images/FastImgixImage.tsx @@ -0,0 +1,96 @@ +import * as React from 'react'; +import FastImage, { FastImageProps, Source } from 'react-native-fast-image'; + +import { maybeSignSource } from '../../handlers/imgix'; + +export type ImgixImageProps = FastImageProps & { + readonly Component?: React.ElementType; + readonly size: number; +}; + +// Here we're emulating the pattern used in react-native-fast-image: +// https://github.com/DylanVann/react-native-fast-image/blob/0439f7190f141e51a391c84890cdd8a7067c6ad3/src/index.tsx#L146 +type HiddenImgixImageProps = { + forwardedRef?: React.Ref<any>; + maxRetries?: number; + retryOnError?: boolean; + size: number; + fm?: string; +}; +type MergedImgixImageProps = ImgixImageProps & HiddenImgixImageProps; + +// ImgixImage must be a class Component to support Animated.createAnimatedComponent. +class ImgixImage extends React.PureComponent<MergedImgixImageProps, ImgixImageProps & { retryCount: number }> { + static getDerivedStateFromProps(props: MergedImgixImageProps) { + const { source, size, fm } = props; + const options = { + ...(fm && { fm: fm }), + ...(size && { + h: size, + w: size, + }), + }; + + return { + retryCount: 0, + source: !!source && typeof source === 'object' ? maybeSignSource(source, options) : source, + }; + } + + handleError = (err: any) => { + const { onError, retryOnError, maxRetries = 5 } = this.props; + const { retryCount } = this.state; + // We don't want to retry if there is a 404. + const isNotFound = err?.nativeEvent?.statusCode === 404 || err?.nativeEvent?.message?.includes('404'); + const shouldRetry = retryOnError && !isNotFound; + + if (shouldRetry && retryCount < maxRetries) { + this.setState(({ retryCount }) => ({ retryCount: retryCount + 1 })); + } else { + // @ts-expect-error + onError?.(err); + } + }; + + render() { + const { Component: maybeComponent, ...props } = this.props; + // Use the local state as the signing source, as opposed to the prop directly. + // (The source prop may point to an untrusted URL.) + const { retryCount, source } = this.state; + const Component = maybeComponent || FastImage; + return <Component {...props} key={`${JSON.stringify(source)}-${retryCount}`} onError={this.handleError} source={source} />; + } +} + +const preload = (sources: Source[], size?: number, fm?: string): void => { + if (sources.length) { + const options = { + ...(fm && { fm: fm }), + ...(size && { + h: size, + w: size, + }), + }; + return FastImage.preload(sources.map(source => maybeSignSource(source, options))); + } + return; +}; + +const getCachePath = (source: Source) => FastImage.getCachePath(maybeSignSource(source)); + +const ImgixImageWithForwardRef = React.forwardRef((props: ImgixImageProps, ref: React.Ref<any>) => ( + <ImgixImage forwardedRef={ref} {...props} /> +)); + +const { cacheControl, clearDiskCache, clearMemoryCache, contextTypes, priority, resizeMode } = FastImage; + +export default Object.assign(ImgixImageWithForwardRef, { + cacheControl, + clearDiskCache, + clearMemoryCache, + getCachePath, + contextTypes, + preload, + priority, + resizeMode, +}); From b80ff53dedb30667a54f315732454bbd17720ad7 Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Thu, 15 Feb 2024 17:14:49 -0500 Subject: [PATCH 03/12] save --- .../FastComponents/FastBalanceCoinRow.tsx | 9 +++++++- .../FastComponents/FastCoinIcon.tsx | 1 - .../FastCurrencySelectionRow.tsx | 21 +++++++++---------- .../FastFallbackCoinIconImage.tsx | 11 +++++----- .../RecyclerAssetList2/WrappedNFT.tsx | 1 - src/components/coin-icon/RainbowCoinIcon.tsx | 10 ++++----- .../coin-row/FastTransactionCoinRow.tsx | 14 ++++++------- src/components/coin-row/SendCoinRow.js | 8 ++++--- src/components/exchange/ExchangeField.tsx | 12 ++++++++--- .../exchange/ExchangeInputField.tsx | 7 +++++++ .../exchange/ExchangeOutputField.tsx | 7 +++++++ src/components/exchange/ExchangeTokenRow.tsx | 16 +++++++------- src/entities/tokens.ts | 6 ++---- src/handlers/imgix.ts | 2 ++ src/resources/assets/externalAssetsQuery.ts | 2 ++ src/screens/ExchangeModal.tsx | 5 +++++ 16 files changed, 82 insertions(+), 50 deletions(-) diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastBalanceCoinRow.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastBalanceCoinRow.tsx index a2da80d7fb4..b247a42ba90 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastBalanceCoinRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastBalanceCoinRow.tsx @@ -96,7 +96,14 @@ const MemoizedBalanceCoinRow = React.memo( <ButtonPressAnimation onPress={handlePress} scaleTo={0.96} testID={`balance-coin-row-${item?.name}`}> <View style={[sx.container]}> <View style={sx.iconContainer}> - <RainbowCoinIcon size={40} icon={item?.icon_url} network={item?.network} symbol={item?.symbol} theme={theme} /> + <RainbowCoinIcon + size={40} + icon={item?.icon_url} + network={item?.network} + symbol={item?.symbol} + theme={theme} + colors={item?.colors} + /> </View> <View style={[sx.innerContainer, isHidden && sx.hiddenRow]}> diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx index ee3ae0da0d9..fc98617f2f7 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx @@ -86,7 +86,6 @@ export default React.memo(function FastCoinIcon({ <Image source={ContractInteraction} style={sx.contract} /> ) : ( <FastFallbackCoinIconImage - icon={icon} address={resolvedAddress} network={resolvedNetwork} shadowColor={shadowColor} diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx index d319d0584d4..336cd11236c 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx @@ -10,14 +10,14 @@ import RadialGradient from 'react-native-radial-gradient'; import { ButtonPressAnimation } from '../../../animations'; import { CoinRowHeight } from '../../../coin-row'; import { FloatingEmojis } from '../../../floating-emojis'; -import FastCoinIcon from './FastCoinIcon'; import ContextMenuButton from '@/components/native-context-menu/contextMenu'; import { Text } from '@/design-system'; import { isNativeAsset } from '@/handlers/assets'; import { Network } from '@/networks/types'; -import { useAccountAsset } from '@/hooks'; import { colors, fonts, fontWithWidth, getFontSize } from '@/styles'; import { deviceUtils } from '@/utils'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; const SafeRadialGradient = (IS_TESTING === 'true' ? View : RadialGradient) as typeof RadialGradient; @@ -99,7 +99,6 @@ export default React.memo(function FastCurrencySelectionRow({ contextMenuProps, symbol, address, - mainnet_address, name, testID, network, @@ -108,10 +107,9 @@ export default React.memo(function FastCurrencySelectionRow({ }: FastCurrencySelectionRowProps) { const { colors } = theme; - // TODO https://github.com/rainbow-me/rainbow/pull/3313/files#r876259954 - const item = useAccountAsset(uniqueId, nativeCurrency); + const { data: item } = useExternalToken({ address, network, currency: nativeCurrency }); const rowTestID = `${testID}-exchange-coin-row-${symbol ?? item?.symbol ?? ''}-${network || Network.mainnet}`; - const isInfoButtonVisible = !item?.isNativeAsset || (!isNativeAsset(address ?? item?.address, network) && !showBalance); + const isInfoButtonVisible = !isNativeAsset(address, network) && !showBalance; return ( <View style={sx.row}> @@ -124,12 +122,13 @@ export default React.memo(function FastCurrencySelectionRow({ > <View style={sx.rootContainer}> <View style={sx.iconContainer}> - <FastCoinIcon - address={address || item?.address} - network={favorite ? Network.mainnet : network} - mainnetAddress={mainnet_address ?? item?.mainnet_address} - symbol={symbol ?? item?.symbol} + <RainbowCoinIcon + size={40} + icon={item?.iconUrl || ''} + network={network} + symbol={item?.symbol || symbol} theme={theme} + colors={item?.colors || undefined} /> </View> <View style={sx.innerContainer}> diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage.tsx index dc26e258b9c..92a641ad89b 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage.tsx @@ -14,24 +14,25 @@ const ImageState = { const imagesCache: { [imageUrl: string]: keyof typeof ImageState } = {}; export const FastFallbackCoinIconImage = React.memo(function FastFallbackCoinIconImage({ - address, + size = 40, + icon, network, symbol, shadowColor, theme, children, }: { + size?: number; + icon?: string; theme: ThemeContextProps; - address: string; network: Network; symbol: string; shadowColor: string; children: () => React.ReactNode; }) { const { colors } = theme; - const imageUrl = getUrlForTrustIconFallback(address, network)!; - const key = `${symbol}-${imageUrl}`; + const key = `${icon}`; const [cacheStatus, setCacheStatus] = useState(imagesCache[key]); @@ -66,7 +67,7 @@ export const FastFallbackCoinIconImage = React.memo(function FastFallbackCoinIco {shouldShowImage && ( <ImageWithCachedMetadata cache={ImgixImage.cacheControl.immutable} - imageUrl={imageUrl} + imageUrl={icon} onError={onError} onLoad={onLoad} size={40} diff --git a/src/components/asset-list/RecyclerAssetList2/WrappedNFT.tsx b/src/components/asset-list/RecyclerAssetList2/WrappedNFT.tsx index 0f17c9e0330..785997d7b3b 100644 --- a/src/components/asset-list/RecyclerAssetList2/WrappedNFT.tsx +++ b/src/components/asset-list/RecyclerAssetList2/WrappedNFT.tsx @@ -26,7 +26,6 @@ export default React.memo(function WrappedNFT({ const asset = useMemo( () => ({ ...assetCollectible, - ...(IS_TESTING === 'true' ? { image_original_url: null, image_preview_url: null, image_url: null } : {}), }), [assetCollectible] ); diff --git a/src/components/coin-icon/RainbowCoinIcon.tsx b/src/components/coin-icon/RainbowCoinIcon.tsx index d0508e57929..6cb02ae8ef8 100644 --- a/src/components/coin-icon/RainbowCoinIcon.tsx +++ b/src/components/coin-icon/RainbowCoinIcon.tsx @@ -7,6 +7,7 @@ import { FallbackIcon as CoinIconTextFallback } from '@/utils'; import { FastFallbackCoinIconImage } from '../asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage'; import { FastChainBadge } from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinBadge'; +import { TokenColors } from '@/graphql/__generated__/metadata'; const fallbackTextStyles = { fontFamily: fonts.family.SFProRounded, @@ -33,14 +34,11 @@ export default React.memo(function FastCoinIcon({ badgeYPosition, }: { size?: number; - icon: string; + icon?: string; network: Network; symbol: string; theme: ThemeContextProps; - colors?: { - primary?: string; - fallback?: string; - }; + colors?: TokenColors; ignoreBadge?: boolean; badgeXPosition?: number; badgeYPosition?: number; @@ -51,7 +49,7 @@ export default React.memo(function FastCoinIcon({ return ( <View style={sx.container}> - <FastFallbackCoinIconImage icon={icon} shadowColor={shadowColor} symbol={symbol} theme={theme} size={size}> + <FastFallbackCoinIconImage network={network} icon={icon} shadowColor={shadowColor} symbol={symbol} theme={theme} size={size}> {() => ( <CoinIconTextFallback color={fallbackIconColor} diff --git a/src/components/coin-row/FastTransactionCoinRow.tsx b/src/components/coin-row/FastTransactionCoinRow.tsx index 6e7db63b310..a03c06aba0f 100644 --- a/src/components/coin-row/FastTransactionCoinRow.tsx +++ b/src/components/coin-row/FastTransactionCoinRow.tsx @@ -1,7 +1,6 @@ import React, { useCallback } from 'react'; import { StyleSheet, View } from 'react-native'; import { ButtonPressAnimation } from '../animations'; -import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; import FastTransactionStatusBadge from './FastTransactionStatusBadge'; import { Text, globalColors, useColorMode } from '@/design-system'; import { TransactionStatusTypes, TransactionTypes } from '@/entities'; @@ -13,6 +12,7 @@ import { CardSize } from '../unique-token/CardSize'; import { ChainBadge } from '../coin-icon'; import { Network } from '@/networks/types'; import { ethereumUtils } from '@/utils'; +import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; const BottomRow = React.memo(function BottomRow({ description, @@ -71,7 +71,6 @@ const BottomRow = React.memo(function BottomRow({ export default React.memo(function TransactionCoinRow({ item, theme }: { item: any; theme: ThemeContextProps }) { const { colorMode } = useColorMode(); - const { mainnetAddress } = item; const { colors } = theme; const navigation = useNavigation(); @@ -121,12 +120,13 @@ export default React.memo(function TransactionCoinRow({ item, theme }: { item: a </View> ) : ( <View style={sx.iconContainer}> - <FastCoinIcon - address={mainnetAddress || item.address} - network={item.network} - mainnetAddress={mainnetAddress} - symbol={item.symbol} + <RainbowCoinIcon + size={40} + icon={item?.icon_url} + network={item?.network} + symbol={item?.symbol} theme={theme} + colors={item?.colors} /> </View> )} diff --git a/src/components/coin-row/SendCoinRow.js b/src/components/coin-row/SendCoinRow.js index 2735ccd1dbf..d6f6c5fd1a0 100644 --- a/src/components/coin-row/SendCoinRow.js +++ b/src/components/coin-row/SendCoinRow.js @@ -3,7 +3,7 @@ import { TouchableWithoutFeedback } from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; import { buildAssetUniqueIdentifier } from '../../helpers/assets'; import { useTheme } from '../../theme/ThemeContext'; -import { deviceUtils, magicMemo } from '../../utils'; +import { deviceUtils } from '../../utils'; import { ButtonPressAnimation } from '../animations'; import { Text } from '../text'; import CoinName from './CoinName'; @@ -12,7 +12,7 @@ import { isL2Network } from '@/handlers/web3'; import { useColorForAsset } from '@/hooks'; import styled from '@/styled-thing'; import { padding } from '@/styles'; -import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; +import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; const isSmallPhone = android || deviceUtils.dimensions.height <= 667; const isTinyPhone = deviceUtils.dimensions.height <= 568; @@ -124,10 +124,12 @@ const SendCoinRow = ({ {...item} {...props} mainnetAddress={item?.mainnet_address} + icon={item?.icon_url} + colors={item?.colors} badgeYPosition={0} bottomRowRender={BottomRow} containerStyles={selected ? containerSelectedStyles : containerStyles} - coinIconRender={FastCoinIcon} + coinIconRender={RainbowCoinIcon} isHidden={false} item={item} selected={selected} diff --git a/src/components/exchange/ExchangeField.tsx b/src/components/exchange/ExchangeField.tsx index 60866656bd9..5f13a223f36 100644 --- a/src/components/exchange/ExchangeField.tsx +++ b/src/components/exchange/ExchangeField.tsx @@ -10,6 +10,7 @@ import { borders } from '@/styles'; import { useTheme } from '@/theme'; import { AccentColorProvider, Box, Space } from '@/design-system'; import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; +import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; const ExchangeFieldHeight = android ? 64 : 38; const ExchangeFieldPadding: Space = android ? '15px (Deprecated)' : '19px (Deprecated)'; @@ -22,6 +23,11 @@ const Input = styled(ExchangeInput).attrs({ }); interface ExchangeFieldProps { + icon: string; + colors: { + primary: string; + fallback: string; + }; address: string; color: string; mainnetAddress?: string; @@ -45,8 +51,8 @@ interface ExchangeFieldProps { const ExchangeField: ForwardRefRenderFunction<TextInput, ExchangeFieldProps> = ( { - address, - mainnetAddress, + icon, + colors, amount, color, disableCurrencySelection, @@ -138,7 +144,7 @@ const ExchangeField: ForwardRefRenderFunction<TextInput, ExchangeFieldProps> = ( > <Box paddingRight="10px"> {symbol ? ( - <FastCoinIcon address={address} mainnetAddress={mainnetAddress} symbol={symbol} network={network} theme={theme} /> + <RainbowCoinIcon size={40} icon={icon} network={network} symbol={symbol} theme={theme} colors={colors} /> ) : ( <Box> <AccentColorProvider color={theme.colors.alpha(theme.colors.blueGreyDark, 0.1)}> diff --git a/src/components/exchange/ExchangeInputField.tsx b/src/components/exchange/ExchangeInputField.tsx index 67cd160e147..7eb359cd267 100644 --- a/src/components/exchange/ExchangeInputField.tsx +++ b/src/components/exchange/ExchangeInputField.tsx @@ -6,6 +6,7 @@ import ExchangeMaxButton from './ExchangeMaxButton'; import ExchangeNativeField from './ExchangeNativeField'; import { Network } from '@/helpers'; import styled from '@/styled-thing'; +import { TokenColors } from '@/graphql/__generated__/metadata'; const Container = styled(ColumnWithMargins).attrs({ margin: 5 })({ paddingTop: android ? 0 : 6, @@ -34,6 +35,8 @@ interface ExchangeInputFieldProps { onPressMaxBalance: () => void; onPressSelectInputCurrency: (chainId: any) => void; inputAmount: string | null; + inputCurrencyIcon?: string; + inputCurrencyColors?: TokenColors; inputCurrencyAddress: string; inputCurrencyMainnetAddress?: string; inputCurrencyNetwork?: string; @@ -53,6 +56,8 @@ export default function ExchangeInputField({ inputCurrencyAddress, inputCurrencyMainnetAddress, inputCurrencySymbol, + inputCurrencyIcon, + inputCurrencyColors, inputFieldRef, loading, nativeAmount, @@ -71,6 +76,8 @@ export default function ExchangeInputField({ return ( <Container> <ExchangeField + icon={inputCurrencyIcon} + colors={inputCurrencyColors} address={inputCurrencyAddress} color={color} amount={inputAmount} diff --git a/src/components/exchange/ExchangeOutputField.tsx b/src/components/exchange/ExchangeOutputField.tsx index dfbac8846ca..c81b23ef0a2 100644 --- a/src/components/exchange/ExchangeOutputField.tsx +++ b/src/components/exchange/ExchangeOutputField.tsx @@ -3,6 +3,7 @@ import { TextInput } from 'react-native'; import ExchangeField from './ExchangeField'; import { Box } from '@rainbow-me/design-system'; import { Network } from '@rainbow-me/helpers'; +import { TokenColors } from '@/graphql/__generated__/metadata'; interface ExchangeOutputFieldProps { color: string; @@ -13,6 +14,8 @@ interface ExchangeOutputFieldProps { onPressSelectOutputCurrency: () => void; onTapWhileDisabled?: () => void; outputAmount: string | null; + outputCurrencyIcon?: string; + outputCurrencyColors?: TokenColors; outputCurrencyAddress: string; outputCurrencyMainnetAddress?: string; outputCurrencyNetwork?: string; @@ -32,6 +35,8 @@ export default function ExchangeOutputField({ onPressSelectOutputCurrency, onTapWhileDisabled, outputAmount, + outputCurrencyIcon, + outputCurrencyColors, outputCurrencyAddress, outputCurrencyMainnetAddress, outputCurrencySymbol, @@ -49,6 +54,8 @@ export default function ExchangeOutputField({ width="full" > <ExchangeField + icon={outputCurrencyIcon} + colors={outputCurrencyColors} address={outputCurrencyAddress} amount={outputAmount} color={color} diff --git a/src/components/exchange/ExchangeTokenRow.tsx b/src/components/exchange/ExchangeTokenRow.tsx index 5e92b465a8f..a2733301bac 100644 --- a/src/components/exchange/ExchangeTokenRow.tsx +++ b/src/components/exchange/ExchangeTokenRow.tsx @@ -11,6 +11,7 @@ import { FloatingEmojis } from '../floating-emojis'; import { IS_IOS } from '@/env'; import { FavStar, Info } from '../asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow'; import { View } from 'react-native'; +import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; interface ExchangeTokenRowProps { item: any; @@ -28,7 +29,6 @@ export default React.memo(function ExchangeTokenRow({ contextMenuProps, symbol, address, - mainnet_address, name, testID, network, @@ -44,7 +44,7 @@ export default React.memo(function ExchangeTokenRow({ const rowTestID = `${testID}-exchange-coin-row-${symbol ?? item?.symbol ?? ''}-${network || Network.mainnet}`; const isInfoButtonVisible = !item?.isNativeAsset || (!isNativeAsset(address ?? item?.address, network) && !showBalance); - + console.log({ item }); return ( <Columns alignVertical="center" space="10px"> <Column> @@ -60,13 +60,13 @@ export default React.memo(function ExchangeTokenRow({ <Columns alignVertical="center" space="10px"> <Column width="content"> <View style={{ height: 59, paddingTop: 9 }}> - <Box - as={FastCoinIcon} - address={address || item?.address} - network={network || Network.mainnet} - mainnetAddress={mainnet_address ?? item?.mainnet_address} - symbol={symbol ?? item?.symbol} + <RainbowCoinIcon + size={40} + icon={item?.icon_url || item?.iconUrl || ''} + network={network} + symbol={item?.symbol || symbol} theme={theme} + colors={item?.colors || undefined} /> </View> </Column> diff --git a/src/entities/tokens.ts b/src/entities/tokens.ts index ed769313ec6..045a00dfa1c 100644 --- a/src/entities/tokens.ts +++ b/src/entities/tokens.ts @@ -2,6 +2,7 @@ import { ChainId } from '@rainbow-me/swaps'; import { EthereumAddress } from '.'; import { Chain } from '@wagmi/chains'; import { Network } from '@/networks/types'; +import { TokenColors } from '@/graphql/__generated__/metadata'; export interface ZerionAssetPrice { value: number; @@ -55,10 +56,7 @@ export interface ParsedAddressAsset extends Asset, Partial<RainbowTokenOwnFields }; chainId?: number; color?: string; - colors?: { - primary?: string; - fallback?: string; - }; + colors?: TokenColors; icon_url?: string; price?: { changed_at?: number; diff --git a/src/handlers/imgix.ts b/src/handlers/imgix.ts index e70046cb12e..5df0d639337 100644 --- a/src/handlers/imgix.ts +++ b/src/handlers/imgix.ts @@ -6,6 +6,7 @@ import { Source } from 'react-native-fast-image'; import parse from 'url-parse'; import { isCloudinaryStorageIconLink, signCloudinaryIconUrl } from '@/handlers/cloudinary'; import { logger, RainbowError } from '@/logger'; +import { GOOGLE_USER_CONTENT_URL } from '@/utils/getFullResUrl'; const shouldCreateImgixClient = (): ImgixClient | null => { if (typeof domain === 'string' && !!domain.length && typeof secureURLToken === 'string' && !!secureURLToken.length) { @@ -135,6 +136,7 @@ export const maybeSignUri = ( export const maybeSignSource = (source: Source, options?: Record<string, unknown>): Source => { if (!!source && typeof source === 'object') { const { uri: externalImageUri, ...extras } = source; + return { ...extras, uri: maybeSignUri(externalImageUri, options), diff --git a/src/resources/assets/externalAssetsQuery.ts b/src/resources/assets/externalAssetsQuery.ts index 21aff27fa1f..964d2f547d3 100644 --- a/src/resources/assets/externalAssetsQuery.ts +++ b/src/resources/assets/externalAssetsQuery.ts @@ -19,6 +19,7 @@ const EXTERNAL_TOKEN_STALE_TIME = 1000 * 60; // 1 minute // Types type ExternalToken = Pick<Token, 'decimals' | 'iconUrl' | 'name' | 'networks' | 'symbol' | 'colors' | 'price'>; export type FormattedExternalAsset = ExternalToken & { + icon_url: string; native: { change: string; price: { @@ -49,6 +50,7 @@ const formatExternalAsset = (asset: ExternalToken, nativeCurrency: NativeCurrenc change: asset?.price?.relativeChange24h ? convertAmountToPercentageDisplay(`${asset?.price?.relativeChange24h}`) : '', price: convertAmountAndPriceToNativeDisplay(1, asset?.price?.value || 0, nativeCurrency), }, + icon_url: asset.iconUrl, }; }; diff --git a/src/screens/ExchangeModal.tsx b/src/screens/ExchangeModal.tsx index ab7365fb4d4..7e9371eb8ba 100644 --- a/src/screens/ExchangeModal.tsx +++ b/src/screens/ExchangeModal.tsx @@ -773,6 +773,7 @@ export default function ExchangeModal({ fromDiscover, ignoreInitialTypeCheck, te return navigateToSwapDetailsModal(); }, [loading, navigateToSwapDetailsModal]); + console.log({ outputCurrency }); return ( <Wrapper keyboardType={KeyboardType.numpad}> <Box height="full" width="full"> @@ -801,6 +802,8 @@ export default function ExchangeModal({ fromDiscover, ignoreInitialTypeCheck, te inputCurrencyMainnetAddress={inputCurrency?.mainnet_address} inputCurrencySymbol={inputCurrency?.symbol} inputFieldRef={inputFieldRef} + inputCurrencyIcon={inputCurrency?.icon_url || inputCurrency?.iconUrl} + inputCurrencyColors={inputCurrency?.colors} loading={loading} nativeAmount={nativeAmountDisplay} nativeCurrency={nativeCurrency} @@ -831,6 +834,8 @@ export default function ExchangeModal({ fromDiscover, ignoreInitialTypeCheck, te loading={loading} outputAmount={outputAmountDisplay} outputCurrencyAddress={outputCurrency?.address} + outputCurrencyIcon={outputCurrency?.icon_url || outputCurrency?.iconUrl} + outputCurrencyColors={outputCurrency?.colors} outputCurrencyMainnetAddress={outputCurrency?.mainnet_address} outputCurrencySymbol={outputCurrency?.symbol} outputFieldRef={outputFieldRef} From 86b78c97c7f0c7193e3efa1ef46cf440bec11745 Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Thu, 15 Feb 2024 17:38:28 -0500 Subject: [PATCH 04/12] save --- .../images/ImageWithCachedMetadata.js | 3 +- src/hooks/useSwapCurrencyHandlers.ts | 2 +- src/screens/CurrencySelectModal.tsx | 28 ++++++++++++++----- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/components/images/ImageWithCachedMetadata.js b/src/components/images/ImageWithCachedMetadata.js index 10829a6daeb..6d7a215ecef 100644 --- a/src/components/images/ImageWithCachedMetadata.js +++ b/src/components/images/ImageWithCachedMetadata.js @@ -1,6 +1,7 @@ import React, { useCallback, useMemo } from 'react'; import ImgixImage from './ImgixImage'; import { useImageMetadata } from '@/hooks'; +import FastImgixImage from './FastImgixImage'; const ImageWithCachedMetadata = ({ cache = ImgixImage.cacheControl.web, imageUrl, onLoad, ...props }, ref) => { const { onCacheImageMetadata } = useImageMetadata(imageUrl); @@ -17,7 +18,7 @@ const ImageWithCachedMetadata = ({ cache = ImgixImage.cacheControl.web, imageUrl [onCacheImageMetadata, onLoad] ); - return <ImgixImage {...props} onLoad={handleLoad} ref={ref} source={source} />; + return <FastImgixImage {...props} onLoad={handleLoad} ref={ref} source={source} />; }; export default React.forwardRef(ImageWithCachedMetadata); diff --git a/src/hooks/useSwapCurrencyHandlers.ts b/src/hooks/useSwapCurrencyHandlers.ts index 4c83da275f6..e030608e205 100644 --- a/src/hooks/useSwapCurrencyHandlers.ts +++ b/src/hooks/useSwapCurrencyHandlers.ts @@ -146,7 +146,7 @@ export default function useSwapCurrencyHandlers({ setLastFocusedInputHandle?.(inputFieldRef); handleNavigate?.(newOutputCurrency); }, - [crosschainSwapsEnabled, dispatch, inputFieldRef, nativeCurrency, setLastFocusedInputHandle] + [crosschainSwapsEnabled, dispatch, inputFieldRef, setLastFocusedInputHandle] ); const navigateToSelectInputCurrency = useCallback( diff --git a/src/screens/CurrencySelectModal.tsx b/src/screens/CurrencySelectModal.tsx index f89136b3510..d6ac2404fa1 100644 --- a/src/screens/CurrencySelectModal.tsx +++ b/src/screens/CurrencySelectModal.tsx @@ -38,9 +38,10 @@ import { useTheme } from '@/theme'; import { IS_TEST } from '@/env'; import { useSortedUserAssets } from '@/resources/assets/useSortedUserAssets'; import DiscoverSearchInput from '@/components/discover/DiscoverSearchInput'; -import { prefetchExternalToken } from '@/resources/assets/externalAssetsQuery'; +import { externalTokenQueryKey, fetchExternalToken } from '@/resources/assets/externalAssetsQuery'; import { getNetworkFromChainId } from '@/utils/ethereumUtils'; import { getNetworkObj } from '@/networks'; +import { queryClient } from '@/react-query/queryClient'; export interface EnrichedExchangeAsset extends SwappableAsset { ens: boolean; @@ -347,20 +348,33 @@ export default function CurrencySelectModal() { let newAsset = item; - const selectAsset = () => { + const selectAsset = async () => { if (!item?.balance) { const network = getNetworkFromChainId(currentChainId); - prefetchExternalToken({ - address: item.address, - network, - currency: nativeCurrency, - }); + + const externalAsset = await queryClient.fetchQuery( + externalTokenQueryKey({ + address: item.address, + network, + currency: nativeCurrency, + }), + async () => + fetchExternalToken({ + address: item.address, + network, + currency: nativeCurrency, + }), + { + staleTime: Infinity, + } + ); // if the asset is external we need to add the network specific information newAsset = { ...newAsset, decimals: item?.networks?.[currentChainId]?.decimals || item.decimals, address: item?.address || item?.networks?.[currentChainId]?.address, network: getNetworkFromChainId(currentChainId), + ...externalAsset, }; } setIsTransitioning(true); // continue to display list during transition From c1cba419cf42b9e74b342978b6bd8464c8b60512 Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Thu, 15 Feb 2024 22:52:16 -0500 Subject: [PATCH 05/12] fin --- src/components/L2Disclaimer.js | 11 +- .../FastComponents/FastCoinIcon.tsx | 141 -- .../FastCurrencySelectionRow.tsx | 7 +- .../FastFallbackCoinIconImage.tsx | 23 +- src/components/cards/EthCard.tsx | 4 +- .../cards/MintsCard/CollectionCell.tsx | 33 +- src/components/cards/NFTOffersCard/Offer.tsx | 34 +- src/components/coin-icon/CoinIconGroup.js | 51 - src/components/coin-icon/EthCoinIcon.tsx | 25 + src/components/coin-icon/RainbowCoinIcon.tsx | 10 +- src/components/coin-icon/index.js | 1 - src/components/coin-row/CoinRow.js | 28 +- .../exchange/CurrencySelectModalHeader.tsx | 14 +- src/components/exchange/ExchangeField.tsx | 11 +- src/components/exchange/ExchangeTokenRow.tsx | 3 - src/components/exchange/NetworkSwitcher.js | 5 +- src/components/exchange/NetworkSwitcherv2.tsx | 5 +- .../expanded-state/AvailableNetworks.js | 8 +- .../expanded-state/AvailableNetworksv2.tsx | 5 +- .../chart/ChartExpandedStateHeader.js | 25 +- .../swap-details/CurrencyTile.js | 16 +- .../swap-details/SwapDetailsRefuelRow.js | 26 +- src/components/gas/GasSpeedButton.js | 3 +- src/components/positions/PositionsCard.tsx | 22 +- .../token-info/TokenInfoBalanceValue.js | 18 +- .../DefaultTransactionConfirmationSection.js | 21 - .../sections/MessageSigningSection.js | 15 - .../TransactionConfirmationSection.js | 71 - .../WalletConnectV2ListItem.tsx | 3 +- src/resources/assets/assets.ts | 2 +- src/resources/assets/externalAssetsQuery.ts | 4 +- src/resources/assets/types.ts | 15 +- .../AddCash/components/ProviderCard.tsx | 9 +- src/screens/ExchangeModal.tsx | 4 +- src/screens/ExplainSheet.js | 1739 +++++++++-------- src/screens/MintsSheet/card/Card.tsx | 6 +- src/screens/NFTOffersSheet/OfferRow.tsx | 20 +- src/screens/NFTSingleOfferSheet/index.tsx | 48 +- src/screens/SendConfirmationSheet.tsx | 34 +- .../components/CurrencySection.android.tsx | 23 +- src/screens/SignTransactionSheet.tsx | 24 +- src/screens/WalletConnectApprovalSheet.js | 5 +- src/screens/mints/MintSheet.tsx | 10 +- src/screens/positions/SubPositionListItem.tsx | 21 +- .../TransactionDetailsValueAndFeeSection.tsx | 26 +- 45 files changed, 1225 insertions(+), 1404 deletions(-) delete mode 100644 src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx delete mode 100644 src/components/coin-icon/CoinIconGroup.js create mode 100644 src/components/coin-icon/EthCoinIcon.tsx delete mode 100644 src/components/transaction/sections/DefaultTransactionConfirmationSection.js delete mode 100644 src/components/transaction/sections/MessageSigningSection.js delete mode 100644 src/components/transaction/sections/TransactionConfirmationSection.js diff --git a/src/components/L2Disclaimer.js b/src/components/L2Disclaimer.js index 74111cce4ad..3c791c74f7b 100644 --- a/src/components/L2Disclaimer.js +++ b/src/components/L2Disclaimer.js @@ -2,18 +2,15 @@ import React from 'react'; import RadialGradient from 'react-native-radial-gradient'; import Divider from './Divider'; import ButtonPressAnimation from './animations/ButtonPressAnimation'; -import { CoinIcon } from './coin-icon'; import ChainBadge from './coin-icon/ChainBadge'; import { Column, Row } from './layout'; import { Text } from './text'; -import { isL2Asset } from '@/handlers/assets'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import { padding, position } from '@/styles'; import { darkModeThemeColors } from '@/styles/colors'; -import { ethereumUtils } from '@/utils'; import { getNetworkObj } from '@/networks'; import * as lang from '@/languages'; import { isL2Network } from '@/handlers/web3'; +import { EthCoinIcon } from './coin-icon/EthCoinIcon'; const L2Disclaimer = ({ network, @@ -47,11 +44,7 @@ const L2Disclaimer = ({ <Row borderRadius={16} marginHorizontal={marginHorizontal} style={padding.object(android ? 6 : 10, 10, android ? 6 : 10, 10)}> <RadialGradient {...radialGradientProps} borderRadius={16} radius={600} /> <Column justify="center"> - {isL2 ? ( - <ChainBadge network={network} position="relative" size="small" forceDark={forceDarkMode} /> - ) : ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} /> - )} + {isL2 ? <ChainBadge network={network} position="relative" size="small" forceDark={forceDarkMode} /> : <EthCoinIcon size={20} />} </Column> <Column flex={1} justify="center" marginHorizontal={8}> <Text diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx deleted file mode 100644 index fc98617f2f7..00000000000 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import React from 'react'; -import { Image, StyleSheet, View } from 'react-native'; -import { FastChainBadge } from './FastCoinBadge'; -import { FastFallbackCoinIconImage } from './FastFallbackCoinIconImage'; -import ContractInteraction from '@/assets/contractInteraction.png'; -import EthIcon from '@/assets/eth-icon.png'; -import { useColorForAsset } from '@/hooks'; -import { Network } from '@/networks/types'; -import { borders, fonts } from '@/styles'; -import { ThemeContextProps } from '@/theme'; -import { FallbackIcon as CoinIconTextFallback, isETH } from '@/utils'; -import { getUniqueId } from '@/utils/ethereumUtils'; - -const fallbackTextStyles = { - fontFamily: fonts.family.SFProRounded, - fontWeight: fonts.weight.bold, - letterSpacing: fonts.letterSpacing.roundedTight, - marginBottom: 0.5, - textAlign: 'center', -}; - -const fallbackIconStyle = { - ...borders.buildCircleAsObject(40), - position: 'absolute', -}; - -/** - * If mainnet asset is available, get the token under /ethereum/ (token) url. - * Otherwise let it use whatever type it has - * @param param0 - optional mainnetAddress, address and network - * @returns a proper type and address to use for the url - */ -function resolveNetworkAndAddress({ address, mainnetAddress, network }: { mainnetAddress?: string; address: string; network: Network }) { - if (mainnetAddress) { - return { - resolvedAddress: mainnetAddress, - resolvedNetwork: Network.mainnet, - }; - } - - return { - resolvedAddress: address, - resolvedNetwork: network, - }; -} - -export default React.memo(function FastCoinIcon({ - address, - mainnetAddress, - network, - symbol, - theme, -}: { - address: string; - mainnetAddress?: string; - network: Network; - symbol: string; - theme: ThemeContextProps; -}) { - const { colors } = theme; - - const { resolvedNetwork, resolvedAddress } = resolveNetworkAndAddress({ - address, - mainnetAddress, - network, - }); - - const fallbackIconColor = useColorForAsset({ - address: resolvedAddress, - network: resolvedNetwork, - uniqueId: getUniqueId(resolvedAddress, resolvedNetwork), - }); - - const shadowColor = theme.isDarkMode ? colors.shadow : fallbackIconColor; - - const eth = isETH(resolvedAddress); - const shouldRenderContract = symbol === 'contract'; - - return ( - <View style={sx.container}> - {eth ? ( - <View style={[sx.coinIconFallback, sx.reactCoinIconContainer, sx.withShadow, { shadowColor }]}> - <Image source={EthIcon} style={sx.coinIconFallback} /> - </View> - ) : shouldRenderContract ? ( - <Image source={ContractInteraction} style={sx.contract} /> - ) : ( - <FastFallbackCoinIconImage - address={resolvedAddress} - network={resolvedNetwork} - shadowColor={shadowColor} - symbol={symbol} - theme={theme} - > - {() => ( - <CoinIconTextFallback - color={fallbackIconColor} - height={40} - style={fallbackIconStyle} - symbol={symbol} - textStyles={fallbackTextStyles} - width={40} - /> - )} - </FastFallbackCoinIconImage> - )} - - {network && <FastChainBadge network={network} theme={theme} />} - </View> - ); -}); - -const sx = StyleSheet.create({ - coinIconFallback: { - borderRadius: 20, - height: 40, - overflow: 'visible', - width: 40, - }, - container: { - elevation: 6, - overflow: 'visible', - }, - contract: { - height: 40, - width: 40, - }, - reactCoinIconContainer: { - alignItems: 'center', - justifyContent: 'center', - }, - withShadow: { - elevation: 6, - shadowOffset: { - height: 4, - width: 0, - }, - shadowOpacity: 0.3, - shadowRadius: 6, - }, -}); diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx index 336cd11236c..db7ecc30d92 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastCurrencySelectionRow.tsx @@ -87,7 +87,8 @@ const deviceWidth = deviceUtils.dimensions.width; export default React.memo(function FastCurrencySelectionRow({ item: { - uniqueId, + native, + balance, showBalance, showFavoriteButton, onPress, @@ -162,10 +163,10 @@ export default React.memo(function FastCurrencySelectionRow({ {showBalance && ( <View style={[sx.column, sx.balanceColumn]}> <Text align="right" color="primary (Deprecated)" size="16px / 22px (Deprecated)" weight="medium"> - {item?.native?.balance?.display ?? `${nativeCurrencySymbol}0.00`} + {native?.balance?.display ?? `${nativeCurrencySymbol}0.00`} </Text> <Text align="right" color={{ custom: theme.colors.blueGreyDark50 }} size="14px / 19px (Deprecated)" weight="medium"> - {item?.balance?.display ?? ''} + {balance?.display ?? ''} </Text> </View> )} diff --git a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage.tsx b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage.tsx index 92a641ad89b..623754b9b2d 100644 --- a/src/components/asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage.tsx +++ b/src/components/asset-list/RecyclerAssetList2/FastComponents/FastFallbackCoinIconImage.tsx @@ -3,7 +3,6 @@ import { StyleSheet, View } from 'react-native'; import { Network } from '@/networks/types'; import { ImageWithCachedMetadata, ImgixImage } from '@/components/images'; import { ThemeContextProps } from '@/theme'; -import { getUrlForTrustIconFallback } from '@/utils'; const ImageState = { ERROR: 'ERROR', @@ -16,8 +15,6 @@ const imagesCache: { [imageUrl: string]: keyof typeof ImageState } = {}; export const FastFallbackCoinIconImage = React.memo(function FastFallbackCoinIconImage({ size = 40, icon, - network, - symbol, shadowColor, theme, children, @@ -63,15 +60,15 @@ export const FastFallbackCoinIconImage = React.memo(function FastFallbackCoinIco ); return ( - <View style={[sx.coinIconContainer, sx.withShadow, { shadowColor }]}> + <View style={[sx.coinIconContainer, sx.withShadow, { shadowColor, height: size, width: size }]}> {shouldShowImage && ( <ImageWithCachedMetadata cache={ImgixImage.cacheControl.immutable} imageUrl={icon} onError={onError} onLoad={onLoad} - size={40} - style={[sx.coinIconFallback, isLoaded && { backgroundColor: colors.white }]} + size={size} + style={[sx.coinIconFallback, isLoaded && { backgroundColor: colors.white }, { height: size, width: size }]} /> )} @@ -84,26 +81,12 @@ const sx = StyleSheet.create({ coinIconContainer: { alignItems: 'center', borderRadius: 20, - height: 40, justifyContent: 'center', overflow: 'visible', - width: 40, }, coinIconFallback: { borderRadius: 20, - height: 40, overflow: 'hidden', - width: 40, - }, - container: { - elevation: 6, - height: 59, - overflow: 'visible', - paddingTop: 9, - }, - contract: { - height: 40, - width: 40, }, fallbackWrapper: { left: 0, diff --git a/src/components/cards/EthCard.tsx b/src/components/cards/EthCard.tsx index 06e02679189..99998061341 100644 --- a/src/components/cards/EthCard.tsx +++ b/src/components/cards/EthCard.tsx @@ -11,7 +11,6 @@ import Routes from '@/navigation/routesNames'; import { analyticsV2 } from '@/analytics'; import { ETH_ADDRESS } from '@/references'; import { ChartPath, ChartPathProvider } from '@/react-native-animated-charts/src'; -import { CoinIcon } from '../coin-icon'; import Labels from '../value-chart/ExtremeLabels'; import showWalletErrorAlert from '@/helpers/support'; import { IS_IOS } from '@/env'; @@ -25,6 +24,7 @@ import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; import assetTypes from '@/entities/assetTypes'; import { Network } from '@/networks/types'; import { getUniqueId } from '@/utils/ethereumUtils'; +import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; export const ETH_CARD_HEIGHT = 284.3; @@ -156,7 +156,7 @@ export const EthCard = () => { </> ) : ( <> - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ethAsset.symbol} network={Network.mainnet} /> + <EthCoinIcon size={20} /> <Text size="17pt" color={{ custom: colorForAsset }} weight="heavy"> {ethAsset?.name} </Text> diff --git a/src/components/cards/MintsCard/CollectionCell.tsx b/src/components/cards/MintsCard/CollectionCell.tsx index cce23211e10..6120b161fe3 100644 --- a/src/components/cards/MintsCard/CollectionCell.tsx +++ b/src/components/cards/MintsCard/CollectionCell.tsx @@ -1,19 +1,18 @@ import React, { useCallback, useEffect, useState } from 'react'; import { globalColors } from '@/design-system/color/palettes'; import { convertRawAmountToRoundedDecimal } from '@/helpers/utilities'; -import { CoinIcon } from '@/components/coin-icon'; import { AccentColorProvider, Bleed, Box, Cover, Inline, Inset, Text } from '@/design-system'; import { ButtonPressAnimation } from '@/components/animations'; import { useTheme } from '@/theme'; -import { Linking, View } from 'react-native'; +import { View } from 'react-native'; import { MintableCollection } from '@/graphql/__generated__/arc'; -import ethereumUtils, { getNetworkFromChainId } from '@/utils/ethereumUtils'; -import { getNetworkObj } from '@/networks'; +import ethereumUtils, { getNetworkFromChainId, useNativeAssetForNetwork } from '@/utils/ethereumUtils'; import { analyticsV2 } from '@/analytics'; import * as i18n from '@/languages'; import { IS_IOS } from '@/env'; import { ImgixImage } from '@/components/images'; import { navigateToMintCollection } from '@/resources/reservoir/mints'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; export const NFT_IMAGE_SIZE = 111; @@ -38,11 +37,11 @@ export function Placeholder() { } export function CollectionCell({ collection }: { collection: MintableCollection }) { - const { isDarkMode } = useTheme(); + const theme = useTheme(); const [mediaRendered, setMediaRendered] = useState(false); - const currency = getNetworkObj(getNetworkFromChainId(collection.chainId)).nativeCurrency; + const currency = useNativeAssetForNetwork(getNetworkFromChainId(collection.chainId)); const amount = convertRawAmountToRoundedDecimal(collection.mintStatus.price, 18, 6); @@ -100,7 +99,7 @@ export function CollectionCell({ collection }: { collection: MintableCollection : { shadowColor: globalColors.grey100, elevation: 12, - shadowOpacity: isDarkMode ? 1 : 0.6, + shadowOpacity: theme.isDarkMode ? 1 : 0.6, } } > @@ -128,15 +127,17 @@ export function CollectionCell({ collection }: { collection: MintableCollection }} > {!isFree && ( - <CoinIcon - address={currency.address} - size={12} - symbol={currency.symbol} - style={{ marginRight: 4, marginVertical: -4 }} - network={getNetworkFromChainId(collection.chainId)} - mainnet_address={currency?.mainnetAddress} - ignoreBadge - /> + <View style={{ marginRight: 4, marginVertical: -4 }}> + <RainbowCoinIcon + icon={currency?.icon_url || ''} + size={12} + network={getNetworkFromChainId(collection.chainId)} + symbol={currency?.symbol || ''} + theme={theme} + colors={currency?.colors} + ignoreBadge + /> + </View> )} <View style={{ width: NFT_IMAGE_SIZE - 16 }}> <Text color="label" size="11pt" weight="bold" numberOfLines={1}> diff --git a/src/components/cards/NFTOffersCard/Offer.tsx b/src/components/cards/NFTOffersCard/Offer.tsx index 07dc5a8260a..b78e42756d9 100644 --- a/src/components/cards/NFTOffersCard/Offer.tsx +++ b/src/components/cards/NFTOffersCard/Offer.tsx @@ -5,7 +5,6 @@ import { TextColor, globalColors } from '@/design-system/color/palettes'; import { ImgixImage } from '@/components/images'; import MaskedView from '@react-native-masked-view/masked-view'; import { convertAmountToNativeDisplay, getFormattedTimeQuantity, handleSignificantDecimals } from '@/helpers/utilities'; -import { CoinIcon } from '@/components/coin-icon'; import { NftOffer, SortCriterion } from '@/graphql/__generated__/arc'; import { AccentColorProvider, Box, Inline, Inset, Text, useBackgroundColor, useColorMode } from '@/design-system'; import { RainbowError, logger } from '@/logger'; @@ -20,6 +19,10 @@ import { useRecoilValue } from 'recoil'; import { nftOffersSortAtom } from '@/components/nft-offers/SortMenu'; import { View } from 'react-native'; import Svg, { Path } from 'react-native-svg'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; +import { useAccountSettings } from '@/hooks'; +import { Network } from '@/networks/types'; const TWO_HOURS_MS = 2 * 60 * 60 * 1000; export const CELL_HORIZONTAL_PADDING = 7; @@ -62,7 +65,13 @@ export const FakeOffer = () => { export const Offer = ({ offer }: { offer: NftOffer }) => { const { navigate } = useNavigation(); const { colorMode } = useColorMode(); - const { isDarkMode } = useTheme(); + const theme = useTheme(); + const { nativeCurrency } = useAccountSettings(); + const { data: externalAsset } = useExternalToken({ + address: offer.paymentToken.address, + network: offer.network as Network, + currency: nativeCurrency, + }); const surfacePrimaryElevated = useBackgroundColor('surfacePrimaryElevated'); const surfaceSecondaryElevated = useBackgroundColor('surfaceSecondaryElevated'); @@ -210,7 +219,7 @@ export const Offer = ({ offer }: { offer: NftOffer }) => { width: NFT_IMAGE_SIZE, height: NFT_IMAGE_SIZE, borderRadius: 12, - backgroundColor: isDarkMode ? surfaceSecondaryElevated : surfacePrimaryElevated, + backgroundColor: theme.isDarkMode ? surfaceSecondaryElevated : surfacePrimaryElevated, }} size={CardSize} /> @@ -225,14 +234,17 @@ export const Offer = ({ offer }: { offer: NftOffer }) => { alignItems: 'center', }} > - <CoinIcon - address={offer.paymentToken.address} - size={12} - symbol={offer.paymentToken.symbol} - style={{ marginRight: 4 }} - network={offer.network} - ignoreBadge - /> + <View style={{ marginRight: 4 }}> + <RainbowCoinIcon + size={12} + icon={externalAsset?.icon_url} + network={offer?.network as Network} + symbol={offer.paymentToken.symbol} + theme={theme} + colors={externalAsset?.colors} + ignoreBadge + /> + </View> <Text color="label" size="13pt" weight="heavy"> {cryptoAmount} </Text> diff --git a/src/components/coin-icon/CoinIconGroup.js b/src/components/coin-icon/CoinIconGroup.js deleted file mode 100644 index d2542c01824..00000000000 --- a/src/components/coin-icon/CoinIconGroup.js +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useMemo } from 'react'; -import { View } from 'react-primitives'; -import { Column, Row } from '../layout'; -import CoinIcon from './CoinIcon'; -import { neverRerender } from '@/utils'; - -// Note that `width` is always smaller than `iconSize`. We do this to force the -// `CoinIcon`'s to overlap each other (imagine the Olympics logo). -const sizesTable = [ - { breakIndex: false, iconSize: 40, width: 30 }, - { breakIndex: false, iconSize: 40, width: 30 }, - { breakIndex: false, iconSize: 30, width: 20 }, - { breakIndex: false, iconSize: 25, width: 15 }, - { breakIndex: 1, iconSize: 20, width: 15 }, - { breakIndex: 2, iconSize: 20, width: 15 }, - { breakIndex: 3, iconSize: 20, width: 15 }, - { breakIndex: 4, iconSize: 20, width: 15 }, -]; - -const TokenRowsComponent = ({ tokenRows, iconSize, width }) => - tokenRows.map((setOfTokens, lineIndex) => ( - <Row key={`coinLine_${lineIndex}`}> - {setOfTokens.map((token, index) => ( - <View key={`coin_${index}_${lineIndex}`} width={width} zIndex={-index}> - <CoinIcon address={token?.address} size={iconSize} symbol={token?.symbol} /> - </View> - ))} - </Row> - )); - -function CoinIconGroup({ tokens }) { - const { breakIndex, iconSize, width } = useMemo(() => sizesTable[tokens.length - 1], [tokens]); - - const tokenRows = useMemo(() => { - return [tokens.slice(0, breakIndex), tokens.slice(breakIndex, tokens.length)]; - }, [breakIndex, tokens]); - - return ( - <Column - align={breakIndex ? 'center' : 'start'} - // shouldRasterizeIOS fixes a strange framerate choppiness we see in the - // pools list on iOS only. Appears to be the amount of coinIcons onscreen at once. - shouldRasterizeIOS - width={70} - > - <TokenRowsComponent iconSize={iconSize} tokenRows={tokenRows} width={width} /> - </Column> - ); -} - -export default neverRerender(CoinIconGroup); diff --git a/src/components/coin-icon/EthCoinIcon.tsx b/src/components/coin-icon/EthCoinIcon.tsx new file mode 100644 index 00000000000..ab85e04a8bb --- /dev/null +++ b/src/components/coin-icon/EthCoinIcon.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { Network } from '@/networks/types'; +import { ThemeContextProps, useTheme } from '@/theme'; +import { useNativeAssetForNetwork } from '@/utils/ethereumUtils'; +import RainbowCoinIcon from './RainbowCoinIcon'; +import { ETH_SYMBOL } from '@/references'; + +type EthCoinIconProps = { + size?: number; +}; + +export const EthCoinIcon = ({ size = 40 }: EthCoinIconProps) => { + const ethAsset = useNativeAssetForNetwork(Network.mainnet); + const theme = useTheme(); + return ( + <RainbowCoinIcon + size={size} + icon={ethAsset?.icon_url} + network={Network.mainnet} + symbol={ethAsset?.symbol || ETH_SYMBOL} + theme={theme} + colors={ethAsset?.colors} + /> + ); +}; diff --git a/src/components/coin-icon/RainbowCoinIcon.tsx b/src/components/coin-icon/RainbowCoinIcon.tsx index 6cb02ae8ef8..b036de4f50f 100644 --- a/src/components/coin-icon/RainbowCoinIcon.tsx +++ b/src/components/coin-icon/RainbowCoinIcon.tsx @@ -17,12 +17,12 @@ const fallbackTextStyles = { textAlign: 'center', }; -const fallbackIconStyle = { - ...borders.buildCircleAsObject(40), +const fallbackIconStyle = (size: number) => ({ + ...borders.buildCircleAsObject(size), position: 'absolute', -}; +}); -export default React.memo(function FastCoinIcon({ +export default React.memo(function RainbowCoinIcon({ size = 40, icon, network, @@ -54,7 +54,7 @@ export default React.memo(function FastCoinIcon({ <CoinIconTextFallback color={fallbackIconColor} height={size} - style={fallbackIconStyle} + style={fallbackIconStyle(size)} symbol={symbol} textStyles={fallbackTextStyles} width={size} diff --git a/src/components/coin-icon/index.js b/src/components/coin-icon/index.js index 3ca0cb2d48e..962de1fe0b4 100644 --- a/src/components/coin-icon/index.js +++ b/src/components/coin-icon/index.js @@ -1,7 +1,6 @@ export { default as ChainBadge } from './ChainBadge'; export { default as CoinIcon, CoinIconSize } from './CoinIcon'; export { default as CoinIconFallback } from './CoinIconFallback'; -export { default as CoinIconGroup } from './CoinIconGroup'; export { default as CoinIconIndicator } from './CoinIconIndicator'; export { default as RequestCoinIcon } from './RequestCoinIcon'; export { default as RequestVendorLogoIcon } from './RequestVendorLogoIcon'; diff --git a/src/components/coin-row/CoinRow.js b/src/components/coin-row/CoinRow.js index e0ed394251b..ccaae419140 100644 --- a/src/components/coin-row/CoinRow.js +++ b/src/components/coin-row/CoinRow.js @@ -1,5 +1,5 @@ import React, { createElement } from 'react'; -import { CoinIcon, CoinIconGroup, CoinIconSize } from '../coin-icon'; +import { CoinIcon, CoinIconSize } from '../coin-icon'; import { Column, Row } from '../layout'; import { useAccountSettings } from '@/hooks'; import styled from '@/styled-thing'; @@ -49,21 +49,17 @@ export default function CoinRow({ const { nativeCurrency, nativeCurrencySymbol } = useAccountSettings(); return ( <Container style={containerStyles}> - {isPool ? ( - <CoinIconGroup tokens={tokens} /> - ) : ( - createElement(coinIconRender, { - address, - badgeXPosition, - badgeYPosition, - isFirstCoinRow, - isHidden, - isPinned, - symbol, - network, - ...props, - }) - )} + {createElement(coinIconRender, { + address, + badgeXPosition, + badgeYPosition, + isFirstCoinRow, + isHidden, + isPinned, + symbol, + network, + ...props, + })} <Content isHidden={isHidden} justify="center" style={contentStyles}> <Row align="center" testID={`${testID}-${symbol || ''}-${network}`}> {topRowRender({ diff --git a/src/components/exchange/CurrencySelectModalHeader.tsx b/src/components/exchange/CurrencySelectModalHeader.tsx index 489ee96e973..410c3af81c4 100644 --- a/src/components/exchange/CurrencySelectModalHeader.tsx +++ b/src/components/exchange/CurrencySelectModalHeader.tsx @@ -1,12 +1,13 @@ import { useRoute } from '@react-navigation/native'; import React, { useCallback } from 'react'; import { delayNext } from '../../hooks/useMagicAutofocus'; -import { CoinIcon } from '../coin-icon'; import { BackButton } from '../header'; import { SheetHandleFixedToTop } from '../sheet'; import { Box, Inset, Text } from '@/design-system'; import { useNavigation } from '@/navigation'; import Routes from '@/navigation/routesNames'; +import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; +import { useTheme } from '@/theme'; export const CurrencySelectModalHeaderHeight = 59; @@ -25,6 +26,7 @@ export default function CurrencySelectModalHeader({ const { params: { defaultOutputAsset, title, showCoinIcon }, } = useRoute<any>(); + const theme = useTheme(); const handlePressBack = useCallback(() => { // @ts-expect-error – updating read-only property @@ -53,7 +55,15 @@ export default function CurrencySelectModalHeader({ )} {showCoinIcon && ( <Inset right="4px"> - <CoinIcon size={20} {...defaultOutputAsset} badgeSize="tiny" badgeXPosition={-3} /> + <RainbowCoinIcon + size={20} + icon={defaultOutputAsset?.icon_url} + network={defaultOutputAsset?.network} + colors={defaultOutputAsset?.colors} + symbol={defaultOutputAsset?.symbol} + theme={theme} + ignoreBadge + /> </Inset> )} diff --git a/src/components/exchange/ExchangeField.tsx b/src/components/exchange/ExchangeField.tsx index 5f13a223f36..d97883e562e 100644 --- a/src/components/exchange/ExchangeField.tsx +++ b/src/components/exchange/ExchangeField.tsx @@ -1,7 +1,7 @@ import React, { FocusEvent, ForwardRefRenderFunction, MutableRefObject, useCallback, useEffect, useState } from 'react'; import { StyleProp, TextInput, TouchableWithoutFeedback, ViewStyle } from 'react-native'; import { TokenSelectionButton } from '../buttons'; -import { ChainBadge, CoinIcon, CoinIconSize } from '../coin-icon'; +import { ChainBadge, CoinIconSize } from '../coin-icon'; import { EnDash } from '../text'; import ExchangeInput from './ExchangeInput'; import { Network } from '@/helpers'; @@ -9,8 +9,8 @@ import styled from '@/styled-thing'; import { borders } from '@/styles'; import { useTheme } from '@/theme'; import { AccentColorProvider, Box, Space } from '@/design-system'; -import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; +import { TokenColors } from '@/graphql/__generated__/metadata'; const ExchangeFieldHeight = android ? 64 : 38; const ExchangeFieldPadding: Space = android ? '15px (Deprecated)' : '19px (Deprecated)'; @@ -23,11 +23,8 @@ const Input = styled(ExchangeInput).attrs({ }); interface ExchangeFieldProps { - icon: string; - colors: { - primary: string; - fallback: string; - }; + icon?: string; + colors?: TokenColors; address: string; color: string; mainnetAddress?: string; diff --git a/src/components/exchange/ExchangeTokenRow.tsx b/src/components/exchange/ExchangeTokenRow.tsx index a2733301bac..7ec55d01060 100644 --- a/src/components/exchange/ExchangeTokenRow.tsx +++ b/src/components/exchange/ExchangeTokenRow.tsx @@ -4,8 +4,6 @@ import { Box, Column, Columns, Inline, Stack, Text } from '@/design-system'; import { isNativeAsset } from '@/handlers/assets'; import { Network } from '@/networks/types'; import { useAsset, useDimensions } from '@/hooks'; - -import FastCoinIcon from '../asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; import { ButtonPressAnimation } from '../animations'; import { FloatingEmojis } from '../floating-emojis'; import { IS_IOS } from '@/env'; @@ -44,7 +42,6 @@ export default React.memo(function ExchangeTokenRow({ const rowTestID = `${testID}-exchange-coin-row-${symbol ?? item?.symbol ?? ''}-${network || Network.mainnet}`; const isInfoButtonVisible = !item?.isNativeAsset || (!isNativeAsset(address ?? item?.address, network) && !showBalance); - console.log({ item }); return ( <Columns alignVertical="center" space="10px"> <Column> diff --git a/src/components/exchange/NetworkSwitcher.js b/src/components/exchange/NetworkSwitcher.js index 281c61031dc..d27fd987a83 100644 --- a/src/components/exchange/NetworkSwitcher.js +++ b/src/components/exchange/NetworkSwitcher.js @@ -2,15 +2,14 @@ import lang from 'i18n-js'; import React from 'react'; import RadialGradient from 'react-native-radial-gradient'; import Divider from '../Divider'; -import { CoinIcon } from '../coin-icon'; import ChainBadge from '../coin-icon/ChainBadge'; import { ContextMenuButton } from '../context-menu'; import { Column, Row } from '../layout'; import { Text } from '../text'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import { padding, position } from '@/styles'; import { ethereumUtils, showActionSheetWithOptions } from '@/utils'; import { RainbowNetworks, getNetworkObj } from '@/networks'; +import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; const networkMenuItems = () => { return RainbowNetworks.filter(network => network.features.swaps).map(network => ({ @@ -87,7 +86,7 @@ const NetworkSwitcherv1 = ({ {currentChainId !== 1 ? ( <ChainBadge network={ethereumUtils.getNetworkFromChainId(currentChainId)} position="relative" size="small" /> ) : ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} /> + <EthCoinIcon size={20} /> )} </Column> <Column flex={1} justify="center" marginHorizontal={8}> diff --git a/src/components/exchange/NetworkSwitcherv2.tsx b/src/components/exchange/NetworkSwitcherv2.tsx index 596c023db26..330de9a2f34 100644 --- a/src/components/exchange/NetworkSwitcherv2.tsx +++ b/src/components/exchange/NetworkSwitcherv2.tsx @@ -2,14 +2,13 @@ import React, { useRef, useMemo } from 'react'; import { ScrollView } from 'react-native'; import RadialGradient from 'react-native-radial-gradient'; import { ButtonPressAnimation } from '../animations'; -import { CoinIcon } from '../coin-icon'; import ChainBadge from '../coin-icon/ChainBadge'; import { Bleed, Box, Columns, Inline, Text } from '@/design-system'; import { Network } from '@/helpers'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@rainbow-me/references'; import { position } from '@rainbow-me/styles'; import { useTheme } from '@/theme'; import { sortNetworks } from '@/networks'; +import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; const NetworkSwitcherv2 = ({ currentChainId, @@ -79,7 +78,7 @@ const NetworkSwitcherv2 = ({ )} <Inline alignHorizontal="center" alignVertical="center" horizontalSpace="4px" wrap={false}> {network === Network.mainnet ? ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} network={network} /> + <EthCoinIcon size={20} /> ) : ( <ChainBadge network={network} position="relative" size="small" /> )} diff --git a/src/components/expanded-state/AvailableNetworks.js b/src/components/expanded-state/AvailableNetworks.js index ab1fb2df130..4377749ef1a 100644 --- a/src/components/expanded-state/AvailableNetworks.js +++ b/src/components/expanded-state/AvailableNetworks.js @@ -5,7 +5,6 @@ import RadialGradient from 'react-native-radial-gradient'; import { Box } from '@/design-system'; import networkInfo from '@/helpers/networkInfo'; import { useNavigation } from '@/navigation'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import Routes from '@/navigation/routesNames'; import { padding, position } from '@/styles'; import { ethereumUtils } from '@/utils'; @@ -15,6 +14,7 @@ import { Column, Row } from '../layout'; import { ChainBadge, CoinIcon } from '../coin-icon'; import Divider from '../Divider'; import { Text } from '../text'; +import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; const AvailableNetworksv1 = ({ asset, networks, hideDivider, marginBottom = 24, marginHorizontal = 19, prominent }) => { const { colors } = useTheme(); @@ -69,11 +69,7 @@ const AvailableNetworksv1 = ({ asset, networks, hideDivider, marginBottom = 24, width={{ custom: 22 }} zIndex={availableNetworks?.length - index} > - {network !== 'mainnet' ? ( - <ChainBadge network={network} position="relative" size="small" /> - ) : ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} /> - )} + {network !== 'mainnet' ? <ChainBadge network={network} position="relative" size="small" /> : <EthCoinIcon size={20} />} </Box> ); })} diff --git a/src/components/expanded-state/AvailableNetworksv2.tsx b/src/components/expanded-state/AvailableNetworksv2.tsx index edd975fb331..d15af381327 100644 --- a/src/components/expanded-state/AvailableNetworksv2.tsx +++ b/src/components/expanded-state/AvailableNetworksv2.tsx @@ -2,11 +2,9 @@ import lang from 'i18n-js'; import React, { useCallback, useMemo } from 'react'; import RadialGradient from 'react-native-radial-gradient'; import Divider from '../Divider'; -import { CoinIcon } from '../coin-icon'; import ChainBadge from '../coin-icon/ChainBadge'; import { Box, Inline, Text } from '@/design-system'; import { useNavigation } from '@/navigation'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import Routes from '@/navigation/routesNames'; import { position } from '@/styles'; import { ethereumUtils } from '@/utils'; @@ -18,6 +16,7 @@ import { ButtonPressAnimation } from '../animations'; import ContextMenuButton from '@/components/native-context-menu/contextMenu'; import { implementation } from '@/entities/dispersion'; import { RainbowNetworks, getNetworkObj } from '@/networks'; +import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; const NOOP = () => null; @@ -158,7 +157,7 @@ const AvailableNetworksv2 = ({ {network !== Network.mainnet ? ( <ChainBadge network={network} position="relative" size="small" /> ) : ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} network={Network.mainnet} /> + <EthCoinIcon size={20} /> )} </Box> ); diff --git a/src/components/expanded-state/chart/ChartExpandedStateHeader.js b/src/components/expanded-state/chart/ChartExpandedStateHeader.js index f90438ab96d..18bbb2b9890 100644 --- a/src/components/expanded-state/chart/ChartExpandedStateHeader.js +++ b/src/components/expanded-state/chart/ChartExpandedStateHeader.js @@ -1,7 +1,6 @@ import lang from 'i18n-js'; import React, { useMemo } from 'react'; import { runOnJS, useAnimatedReaction } from 'react-native-reanimated'; -import { CoinIcon, CoinIconGroup } from '../../coin-icon'; import { Column, ColumnWithMargins, Row, RowWithMargins } from '../../layout'; import ChartContextButton from './ChartContextButton'; import { ChartDateLabel, ChartHeaderSubtitle, ChartPercentChangeLabel, ChartPriceLabel } from './chart-data-labels'; @@ -11,8 +10,7 @@ import { convertAmountToNativeDisplay } from '@/helpers/utilities'; import { useAccountSettings, useBooleanState } from '@/hooks'; import styled from '@/styled-thing'; import { padding } from '@/styles'; -import FastCoinIcon from '@/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; -import { Network } from '@/networks/types'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; const noPriceData = lang.t('expanded_state.chart.no_price_data'); @@ -112,19 +110,14 @@ export default function ChartExpandedStateHeader({ return ( <Container showChart={showChart}> <Row align="center" justify="space-between" testID={testID ? `${testID}-expanded-state-header` : 'expanded-state-header'}> - {tokens.length === 1 ? ( - <FastCoinIcon - badgeXPosition={-7} - badgeYPosition={0} - address={asset?.address} - mainnetAddress={asset?.mainnet_address || asset?.mainnetAddress} - network={asset?.network || Network.mainnet} - symbol={asset?.symbol} - theme={theme} - /> - ) : ( - <CoinIconGroup tokens={tokens} /> - )} + <RainbowCoinIcon + size={40} + icon={asset?.icon_url} + network={asset?.network} + symbol={asset?.symbol} + theme={theme} + colors={asset?.colors} + /> <ChartContextButton asset={asset} color={color} /> </Row> diff --git a/src/components/expanded-state/swap-details/CurrencyTile.js b/src/components/expanded-state/swap-details/CurrencyTile.js index 6b8c22d428d..3ae675a1cb5 100644 --- a/src/components/expanded-state/swap-details/CurrencyTile.js +++ b/src/components/expanded-state/swap-details/CurrencyTile.js @@ -1,6 +1,5 @@ import React from 'react'; import { useSelector } from 'react-redux'; -import { CoinIcon } from '../../coin-icon'; import { Centered } from '../../layout'; import { Text, TruncatedText } from '../../text'; import { Box, Column, Columns, Row, Rows } from '@/design-system'; @@ -9,6 +8,7 @@ import { SwapModalField } from '@/redux/swap'; import styled from '@/styled-thing'; import { position } from '@/styles'; import { convertAmountToNativeDisplay } from '@/helpers/utilities'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; export const CurrencyTileHeight = android ? 153 : 143; @@ -63,6 +63,7 @@ export default function CurrencyTile({ const inputAsExact = useSelector(state => state.swap.independentField !== SwapModalField.output); const { nativeCurrency } = useAccountSettings(); const colorForAsset = useColorForAsset(asset); + const theme = useTheme(); const { address, mainnet_address, symbol, network } = asset; const isOther = (inputAsExact && type === 'output') || (!inputAsExact && type === 'input'); @@ -74,14 +75,13 @@ export default function CurrencyTile({ <Box paddingHorizontal="15px (Deprecated)"> <Rows alignHorizontal="center" alignVertical="center" space="10px"> <Row height="content"> - <CoinIcon - address={address} - badgeXPosition={-5} - badgeYPosition={0} - mainnet_address={mainnet_address} + <RainbowCoinIcon size={50} - symbol={symbol} - network={network} + icon={asset?.icon_url} + network={asset?.network} + symbol={asset?.symbol} + colors={asset?.colors} + theme={theme} /> </Row> <Row height="content"> diff --git a/src/components/expanded-state/swap-details/SwapDetailsRefuelRow.js b/src/components/expanded-state/swap-details/SwapDetailsRefuelRow.js index 3c655624ac2..7c9dc8c9458 100644 --- a/src/components/expanded-state/swap-details/SwapDetailsRefuelRow.js +++ b/src/components/expanded-state/swap-details/SwapDetailsRefuelRow.js @@ -9,8 +9,8 @@ import { ImgixImage } from '@/components/images'; import CaretImageSource from '@/assets/family-dropdown-arrow.png'; import Spinner from '@/components/Spinner'; import { useTheme } from '@/theme'; -import { CoinIcon } from '@/components/coin-icon'; import { useNativeAssetForNetwork } from '@/utils/ethereumUtils'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; const CaretIcon = styled(ImgixImage).attrs(({ theme: { colors } }) => ({ resizeMode: ImgixImage.resizeMode.contain, @@ -50,15 +50,13 @@ export default function SwapDetailsRefuelRow({ tradeDetails, testID }) { <> <Column width="content"> <Box paddingRight="2px" marginTop={ICON_ALIGN_MARGIN} marginBottom={ICON_ALIGN_MARGIN}> - <CoinIcon - address={fromNativeAsset?.address} - mainnet_address={fromNativeAsset?.mainnet_address} - symbol={fromAsset?.symbol} + <RainbowCoinIcon size={20} + icon={fromNativeAsset?.icon_url} network={fromNetwork} - badgeXPosition={-6} - badgeYPosition={0} - badgeSize="tiny" + symbol={fromAsset?.symbol} + colors={fromNativeAsset?.colors} + ignoreBadge /> </Box> </Column> @@ -69,15 +67,13 @@ export default function SwapDetailsRefuelRow({ tradeDetails, testID }) { </Column> <Column width="content"> <Box paddingLeft="4px" marginTop={ICON_ALIGN_MARGIN} marginBottom={ICON_ALIGN_MARGIN}> - <CoinIcon - address={toNativeAsset?.address} - mainnet_address={toNativeAsset?.mainnet_address} - symbol={toAsset?.symbol} + <RainbowCoinIcon size={20} + icon={toNativeAsset?.icon_url} network={toNetwork} - badgeXPosition={-6} - badgeYPosition={0} - badgeSize="tiny" + symbol={toAsset?.symbol} + colors={toNativeAsset?.colors} + ignoreBadge /> </Box> </Column> diff --git a/src/components/gas/GasSpeedButton.js b/src/components/gas/GasSpeedButton.js index e698691639f..a065d0c30e3 100644 --- a/src/components/gas/GasSpeedButton.js +++ b/src/components/gas/GasSpeedButton.js @@ -29,6 +29,7 @@ import { ethereumUtils, gasUtils } from '@/utils'; import { getNetworkObj } from '@/networks'; import { IS_ANDROID } from '@/env'; import { ContextMenu } from '../context-menu'; +import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; const { GAS_EMOJIS, GAS_ICONS, GasSpeedOrder, CUSTOM, URGENT, NORMAL, FAST, getGasLabel } = gasUtils; @@ -501,7 +502,7 @@ const GasSpeedButton = ({ }} > {currentNetwork === Network.mainnet ? ( - <CoinIcon address={nativeFeeCurrency.address} size={18} symbol={nativeFeeCurrency.symbol} network={currentNetwork} /> + <EthCoinIcon size={18} /> ) : ( <ChainBadge network={currentNetwork} size="gas" position="relative" /> )} diff --git a/src/components/positions/PositionsCard.tsx b/src/components/positions/PositionsCard.tsx index a374c234f6c..b0f3f2df34a 100644 --- a/src/components/positions/PositionsCard.tsx +++ b/src/components/positions/PositionsCard.tsx @@ -15,6 +15,9 @@ import { capitalize, uniqBy } from 'lodash'; import { RainbowDeposit, RainbowPosition } from '@/resources/defi/types'; import { ethereumUtils } from '@/utils'; import { Network } from '@/networks/types'; +import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; +import { useAccountSettings } from '@/hooks'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; type PositionCardProps = { position: RainbowPosition; @@ -26,6 +29,23 @@ type CoinStackToken = { symbol: string; }; +function CoinIconForStack({ token }: { token: CoinStackToken }) { + const theme = useTheme(); + const { nativeCurrency } = useAccountSettings(); + const { data: externalAsset } = useExternalToken({ address: token.address, network: token.network, currency: nativeCurrency }); + + return ( + <RainbowCoinIcon + size={16} + icon={externalAsset?.icon_url} + network={token?.network as Network} + symbol={token.symbol} + theme={theme} + colors={externalAsset?.colors} + ignoreBadge + /> + ); +} function CoinIconStack({ tokens }: { tokens: CoinStackToken[] }) { const { colors } = useTheme(); @@ -45,7 +65,7 @@ function CoinIconStack({ tokens }: { tokens: CoinStackToken[] }) { borderWidth: 2, }} > - <CoinIcon address={token.address} size={16} symbol={token.symbol} network={token.network} ignoreBadge /> + <CoinIconForStack token={token} /> </Box> ); })} diff --git a/src/components/token-info/TokenInfoBalanceValue.js b/src/components/token-info/TokenInfoBalanceValue.js index d209332ee7f..6e951169d28 100644 --- a/src/components/token-info/TokenInfoBalanceValue.js +++ b/src/components/token-info/TokenInfoBalanceValue.js @@ -1,10 +1,12 @@ import React from 'react'; -import { CoinIcon } from '../coin-icon'; import { RowWithMargins } from '../layout'; import TokenInfoValue from './TokenInfoValue'; import { useColorForAsset } from '@/hooks'; import styled from '@/styled-thing'; import { magicMemo } from '@/utils'; +import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; +import { useTheme } from '@/theme'; +import { View } from 'react-native'; const InfoValue = styled(TokenInfoValue)(android ? { height: 37.7 } : {}); @@ -12,6 +14,8 @@ const TokenInfoBalanceValue = ({ align, asset, ...props }) => { const { address, balance, symbol, type, value } = asset; const color = useColorForAsset(asset); + const theme = useTheme(); + return ( <RowWithMargins {...props} @@ -20,7 +24,17 @@ const TokenInfoBalanceValue = ({ align, asset, ...props }) => { margin={5} marginKey={align === 'left' ? 'marginRight' : 'marginLeft'} > - <CoinIcon address={address} ignoreBadge size={20} symbol={symbol} type={type} /> + <View style={{ marginRight: 5 }}> + <RainbowCoinIcon + size={20} + icon={asset?.icon_url} + network={asset?.network} + symbol={asset?.symbol} + theme={theme} + colors={asset?.colors} + ignoreBadge + /> + </View> <InfoValue color={color}>{balance?.display || value}</InfoValue> </RowWithMargins> ); diff --git a/src/components/transaction/sections/DefaultTransactionConfirmationSection.js b/src/components/transaction/sections/DefaultTransactionConfirmationSection.js deleted file mode 100644 index a65b424ec05..00000000000 --- a/src/components/transaction/sections/DefaultTransactionConfirmationSection.js +++ /dev/null @@ -1,21 +0,0 @@ -import lang from 'i18n-js'; -import React from 'react'; -import { Text, TruncatedAddress } from '../../text'; -import TransactionRow from '../TransactionRow'; -import TransactionSheet from '../TransactionSheet'; - -export default function DefaultTransactionConfirmationSection({ address, value = '0' }) { - const { colors } = useTheme(); - return ( - <TransactionSheet> - <TransactionRow title={lang.t('wallet.action.to')}> - <TruncatedAddress address={address} color={colors.alpha(colors.blueGreyDark, 0.6)} size="lmedium" truncationLength={15} /> - </TransactionRow> - <TransactionRow title={lang.t('wallet.action.value')}> - <Text color={colors.alpha(colors.blueGreyDark, 0.6)} size="lmedium" uppercase> - {value} ETH - </Text> - </TransactionRow> - </TransactionSheet> - ); -} diff --git a/src/components/transaction/sections/MessageSigningSection.js b/src/components/transaction/sections/MessageSigningSection.js deleted file mode 100644 index d8191961c12..00000000000 --- a/src/components/transaction/sections/MessageSigningSection.js +++ /dev/null @@ -1,15 +0,0 @@ -import lang from 'i18n-js'; -import React from 'react'; -import TransactionMessage from '../TransactionMessage'; -import TransactionRow from '../TransactionRow'; -import TransactionSheet from '../TransactionSheet'; - -export default function MessageSigningSection({ message, method }) { - return ( - <TransactionSheet method={method}> - <TransactionRow title={lang.t('wallet.message_signing.message')}> - <TransactionMessage message={message} method={method} /> - </TransactionRow> - </TransactionSheet> - ); -} diff --git a/src/components/transaction/sections/TransactionConfirmationSection.js b/src/components/transaction/sections/TransactionConfirmationSection.js deleted file mode 100644 index 6a226800b90..00000000000 --- a/src/components/transaction/sections/TransactionConfirmationSection.js +++ /dev/null @@ -1,71 +0,0 @@ -import React from 'react'; -import LinearGradient from 'react-native-linear-gradient'; -import ActivityIndicator from '../../../components/ActivityIndicator'; -import Spinner from '../../../components/Spinner'; -import { CoinIcon } from '../../coin-icon'; -import { Centered, Column, RowWithMargins } from '../../layout'; -import { Text, TruncatedText } from '../../text'; -import TransactionSheet from '../TransactionSheet'; -import { formatFixedDecimals } from '@/helpers/utilities'; -import styled from '@/styled-thing'; -import { padding } from '@/styles'; - -const Amount = styled(TruncatedText).attrs(({ theme: { colors } }) => ({ - color: colors.dark, - letterSpacing: 'roundedTight', - size: 'larger', - uppercase: true, - weight: 'bold', -}))({}); - -const AmountRow = styled(LinearGradient).attrs(({ theme: { colors } }) => ({ - colors: colors.gradients.lighterGrey, - end: { x: 0, y: 0.5 }, - start: { x: 1, y: 0.5 }, -}))({ - ...padding.object(android ? 1 : 7, 12, android ? 2 : 9, 11), - borderRadius: 40, - marginBottom: 17, - marginLeft: 'auto', - marginRight: 'auto', - marginTop: 'auto', - overflow: 'hidden', -}); - -const NativeAmount = styled(Text).attrs(({ theme: { colors } }) => ({ - align: 'center', - color: colors.dark, - letterSpacing: 'zero', - size: 'headline', - weight: 'heavy', -}))({ - marginBottom: android ? -10 : 10, - marginTop: android ? 0 : 19, -}); - -const LoadingSpinner = styled(android ? Spinner : ActivityIndicator).attrs(({ theme: { colors } }) => ({ - color: colors.alpha(colors.blueGreyDark, 0.3), - size: 50, -}))({ - marginBottom: android ? -10 : 19, - marginTop: 12, -}); - -export default function TransactionConfirmationSection({ address, amount, nativeAmountDisplay = '', symbol, method }) { - return ( - <TransactionSheet method={method}> - <Centered>{!nativeAmountDisplay ? <LoadingSpinner /> : <NativeAmount>{nativeAmountDisplay}</NativeAmount>}</Centered> - <Centered /> - <AmountRow> - <Column> - <RowWithMargins align="center" margin={5}> - <CoinIcon address={address} size={20} symbol={symbol} /> - <Amount> - {formatFixedDecimals(amount, 10)} {symbol} - </Amount> - </RowWithMargins> - </Column> - </AmountRow> - </TransactionSheet> - ); -} diff --git a/src/components/walletconnect-list/WalletConnectV2ListItem.tsx b/src/components/walletconnect-list/WalletConnectV2ListItem.tsx index f8df35aeceb..5e7abcd6d6a 100644 --- a/src/components/walletconnect-list/WalletConnectV2ListItem.tsx +++ b/src/components/walletconnect-list/WalletConnectV2ListItem.tsx @@ -27,6 +27,7 @@ import ChainBadge from '@/components/coin-icon/ChainBadge'; import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import { Network } from '@/helpers'; +import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; const CONTAINER_PADDING = 15; const VENDOR_LOGO_ICON_SIZE = 50; @@ -232,7 +233,7 @@ export function WalletConnectV2ListItem({ session, reload }: { session: SessionT {network !== Network.mainnet ? ( <ChainBadge network={network} position="relative" size="small" /> ) : ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} network={network} /> + <EthCoinIcon size={20} /> )} </Box> ); diff --git a/src/resources/assets/assets.ts b/src/resources/assets/assets.ts index 6742f454655..3ecdbbbf6d6 100644 --- a/src/resources/assets/assets.ts +++ b/src/resources/assets/assets.ts @@ -50,7 +50,7 @@ export function parseAsset({ address, asset }: { address: string; asset: AddysAs const parsedAsset = { address, color: asset?.colors?.primary, - colors: asset?.colors, + colors: asset.colors, chainId, chainName, decimals: asset?.decimals, diff --git a/src/resources/assets/externalAssetsQuery.ts b/src/resources/assets/externalAssetsQuery.ts index 964d2f547d3..e22cb9b320e 100644 --- a/src/resources/assets/externalAssetsQuery.ts +++ b/src/resources/assets/externalAssetsQuery.ts @@ -19,7 +19,7 @@ const EXTERNAL_TOKEN_STALE_TIME = 1000 * 60; // 1 minute // Types type ExternalToken = Pick<Token, 'decimals' | 'iconUrl' | 'name' | 'networks' | 'symbol' | 'colors' | 'price'>; export type FormattedExternalAsset = ExternalToken & { - icon_url: string; + icon_url?: string; native: { change: string; price: { @@ -50,7 +50,7 @@ const formatExternalAsset = (asset: ExternalToken, nativeCurrency: NativeCurrenc change: asset?.price?.relativeChange24h ? convertAmountToPercentageDisplay(`${asset?.price?.relativeChange24h}`) : '', price: convertAmountAndPriceToNativeDisplay(1, asset?.price?.value || 0, nativeCurrency), }, - icon_url: asset.iconUrl, + icon_url: asset?.iconUrl || undefined, }; }; diff --git a/src/resources/assets/types.ts b/src/resources/assets/types.ts index cbcbba5543d..39a5f41ea6d 100644 --- a/src/resources/assets/types.ts +++ b/src/resources/assets/types.ts @@ -1,5 +1,6 @@ import { Network } from '@/helpers/networkTypes'; import { NativeCurrencyKey, ParsedAddressAsset } from '@/entities'; +import { TokenColors } from '@/graphql/__generated__/metadata'; export type AddysAccountAssetsResponse = { meta: AddysAccountAssetsMeta; @@ -27,7 +28,7 @@ export type AddysAddressAsset = { export type AddysAsset = { asset_code: string; - colors: AddysAssetColors; + colors: TokenColors; decimals: number; icon_url?: string; name: string; @@ -38,12 +39,6 @@ export type AddysAsset = { type?: string; }; -export type AddysAssetColors = { - fallback?: string; - primary: string; - shadow?: string; -}; - export type AddysNetworkDetails = { address: string; decimals: number; @@ -58,11 +53,7 @@ export type AddysAssetPrice = { export interface ParsedAsset { address: string; color?: string; - colors?: { - primary?: string; - fallback?: string; - shadow?: string; - }; + colors?: TokenColors; chainId?: number; chainName?: string; decimals: number; diff --git a/src/screens/AddCash/components/ProviderCard.tsx b/src/screens/AddCash/components/ProviderCard.tsx index 17bdfae2763..0c507d73cbf 100644 --- a/src/screens/AddCash/components/ProviderCard.tsx +++ b/src/screens/AddCash/components/ProviderCard.tsx @@ -5,10 +5,8 @@ import chroma from 'chroma-js'; import { IS_IOS } from '@/env'; import { Box, Text, Inline, Bleed, useBackgroundColor } from '@/design-system'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import { Network } from '@/helpers/networkTypes'; import ChainBadge from '@/components/coin-icon/ChainBadge'; -import { CoinIcon } from '@/components/coin-icon'; import { Ramp as RampLogo } from '@/components/icons/svg/Ramp'; import { Ratio as RatioLogo } from '@/components/icons/svg/Ratio'; @@ -19,6 +17,7 @@ import { FiatProviderName } from '@/entities/f2c'; import { convertAPINetworkToInternalNetwork } from '@/screens/AddCash/utils'; import { ProviderConfig, CalloutType, PaymentMethod } from '@/screens/AddCash/types'; import * as i18n from '@/languages'; +import { EthCoinIcon } from '@/components/coin-icon/EthCoinIcon'; type PaymentMethodConfig = { name: string; @@ -97,11 +96,7 @@ function NetworkIcons({ networks }: { networks: Network[] }) { borderRadius: 30, }} > - {network !== Network.mainnet ? ( - <ChainBadge network={network} position="relative" size="small" /> - ) : ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} network={network} /> - )} + {network !== Network.mainnet ? <ChainBadge network={network} position="relative" size="small" /> : <EthCoinIcon size={20} />} </Box> ); })} diff --git a/src/screens/ExchangeModal.tsx b/src/screens/ExchangeModal.tsx index a7d474c89dd..5a762b473e0 100644 --- a/src/screens/ExchangeModal.tsx +++ b/src/screens/ExchangeModal.tsx @@ -799,7 +799,7 @@ export default function ExchangeModal({ fromDiscover, ignoreInitialTypeCheck, te inputCurrencyMainnetAddress={inputCurrency?.mainnet_address} inputCurrencySymbol={inputCurrency?.symbol} inputFieldRef={inputFieldRef} - inputCurrencyIcon={inputCurrency?.icon_url || inputCurrency?.iconUrl} + inputCurrencyIcon={inputCurrency?.icon_url} inputCurrencyColors={inputCurrency?.colors} loading={loading} nativeAmount={nativeAmountDisplay} @@ -831,7 +831,7 @@ export default function ExchangeModal({ fromDiscover, ignoreInitialTypeCheck, te loading={loading} outputAmount={outputAmountDisplay} outputCurrencyAddress={outputCurrency?.address} - outputCurrencyIcon={outputCurrency?.icon_url || outputCurrency?.iconUrl} + outputCurrencyIcon={outputCurrency?.icon_url} outputCurrencyColors={outputCurrency?.colors} outputCurrencyMainnetAddress={outputCurrency?.mainnet_address} outputCurrencySymbol={outputCurrency?.symbol} diff --git a/src/screens/ExplainSheet.js b/src/screens/ExplainSheet.js index 88c2d0584cc..10a24340660 100644 --- a/src/screens/ExplainSheet.js +++ b/src/screens/ExplainSheet.js @@ -1,7 +1,7 @@ import { useRoute } from '@react-navigation/native'; import lang from 'i18n-js'; import React, { useCallback, useMemo } from 'react'; -import { Linking } from 'react-native'; +import { Linking, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { ChainBadge, CoinIcon, DashedWrapper } from '../components/coin-icon'; import { Centered, Column, ColumnWithMargins, Row, RowWithMargins } from '../components/layout'; @@ -26,7 +26,6 @@ import networkTypes from '@/helpers/networkTypes'; import { delay, toFixedDecimals } from '@/helpers/utilities'; import { useDimensions } from '@/hooks'; import { ImgixImage } from '@/components/images'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import styled from '@/styled-thing'; import { fonts, fontWithWidth, padding, position } from '@/styles'; import { ethereumUtils, gasUtils, getTokenMetadata } from '@/utils'; @@ -37,6 +36,8 @@ import { isL2Network } from '@/handlers/web3'; import { IS_ANDROID } from '@/env'; import * as i18n from '@/languages'; import { getNetworkObj } from '@/networks'; +import { EthCoinIcon } from '@/components/coin-icon/EthCoinIcon'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; const { GAS_TRENDS } = gasUtils; const APP_ICON_SIZE = 64; @@ -382,883 +383,923 @@ const navigateToAppIconSettings = async (navigate, goBack) => { navigate(Routes.SETTINGS_SHEET, { screen: 'AppIconSection' }); }; -export const explainers = (params, colors) => ({ - op_rewards_airdrop_timing: { - emoji: '📦', - title: i18n.t(i18n.l.rewards.op.airdrop_timing.title), - text: i18n.t(i18n.l.rewards.op.airdrop_timing.text), - extraHeight: IS_ANDROID ? -65 : 10, - readMoreLink: buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/OP-rewards-with-Rainbow', - query: { - campaign: 'explain', - }, - }), - }, - op_rewards_amount_distributed: { - emoji: '💰', - title: i18n.t(i18n.l.rewards.op.amount_distributed.title), - text: i18n.t(i18n.l.rewards.op.amount_distributed.text), - extraHeight: IS_ANDROID ? -110 : -65, - }, - op_rewards_bridge: { - emoji: '🌉', - title: i18n.t(i18n.l.rewards.op.bridge.title, { - percent: params?.percent || 0, - }), - text: i18n.t(i18n.l.rewards.op.bridge.text, { - percent: params?.percent || 0, - }), - extraHeight: IS_ANDROID ? -65 : 10, - }, - op_rewards_swap: { - emoji: '🔀', - title: i18n.t(i18n.l.rewards.op.swap.title, { - percent: params?.percent || 0, - }), - text: i18n.t(i18n.l.rewards.op.swap.text, { - percent: params?.percent || 0, - }), - extraHeight: IS_ANDROID ? -65 : 10, - }, - op_rewards_position: { - emoji: '🏆', - title: i18n.t(i18n.l.rewards.op.position.title), - text: i18n.t(i18n.l.rewards.op.position.text), - extraHeight: IS_ANDROID ? -110 : -65, - }, - optimism_app_icon: { - logo: <OptimismAppIcon />, - extraHeight: -35, - text: OPTIMISM_APP_ICON_EXPLAINER, - title: lang.t('explain.icon_unlock.title', { partner: 'Optimism' }), - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.optimismRed, - bgColor: colors?.optimismRed06, +export const explainers = (params, theme) => { + const colors = theme.colors; + return { + op_rewards_airdrop_timing: { + emoji: '📦', + title: i18n.t(i18n.l.rewards.op.airdrop_timing.title), + text: i18n.t(i18n.l.rewards.op.airdrop_timing.text), + extraHeight: IS_ANDROID ? -65 : 10, + readMoreLink: buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/OP-rewards-with-Rainbow', + query: { + campaign: 'explain', + }, + }), }, - }, - finiliar_app_icon: { - logo: <FiniliarAppIcon />, - extraHeight: -90, - text: FINILIAR_APP_ICON_EXPLAINER, - title: FINILIAR_APP_ICON_TITLE, - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.finiliarPink, - bgColor: colors?.finiliarPink06, + op_rewards_amount_distributed: { + emoji: '💰', + title: i18n.t(i18n.l.rewards.op.amount_distributed.title), + text: i18n.t(i18n.l.rewards.op.amount_distributed.text), + extraHeight: IS_ANDROID ? -110 : -65, }, - }, - golddoge_app_icon: { - logo: <GoldDogeAppIcon />, - extraHeight: -65, - text: GOLDDOGE_APP_ICON_EXPLAINER, - title: lang.t('explain.icon_unlock.title', { partner: 'DOGE' }), - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.dogeGold, - bgColor: colors?.dogeGold06, + op_rewards_bridge: { + emoji: '🌉', + title: i18n.t(i18n.l.rewards.op.bridge.title, { + percent: params?.percent || 0, + }), + text: i18n.t(i18n.l.rewards.op.bridge.text, { + percent: params?.percent || 0, + }), + extraHeight: IS_ANDROID ? -65 : 10, }, - }, - raindoge_app_icon: { - logo: <RainDogeAppIcon />, - extraHeight: -65, - text: RAINDOGE_APP_ICON_EXPLAINER, - title: lang.t('explain.icon_unlock.title', { partner: 'The Doge NFT' }), - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.dogeGold, - bgColor: colors?.dogeGold06, + op_rewards_swap: { + emoji: '🔀', + title: i18n.t(i18n.l.rewards.op.swap.title, { + percent: params?.percent || 0, + }), + text: i18n.t(i18n.l.rewards.op.swap.text, { + percent: params?.percent || 0, + }), + extraHeight: IS_ANDROID ? -65 : 10, }, - }, - pooly_app_icon: { - logo: <PoolyAppIcon />, - extraHeight: -90, - text: POOLY_APP_ICON_EXPLAINER, - title: POOLY_APP_ICON_TITLE, - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.poolyPurple, - bgColor: colors?.poolyPurple06, + op_rewards_position: { + emoji: '🏆', + title: i18n.t(i18n.l.rewards.op.position.title), + text: i18n.t(i18n.l.rewards.op.position.text), + extraHeight: IS_ANDROID ? -110 : -65, }, - }, - smol_app_icon: { - logo: <SmolAppIcon />, - extraHeight: -65, - text: SMOL_APP_ICON_EXPLAINER, - title: lang.t('explain.icon_unlock.title', { partner: 'SMOL' }), - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.smolPurple, - bgColor: colors?.smolPurple06, + optimism_app_icon: { + logo: <OptimismAppIcon />, + extraHeight: -35, + text: OPTIMISM_APP_ICON_EXPLAINER, + title: lang.t('explain.icon_unlock.title', { partner: 'Optimism' }), + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.optimismRed, + bgColor: colors?.optimismRed06, + }, }, - }, - zora_app_icon: { - logo: <ZoraAppIcon />, - extraHeight: -90, - text: ZORA_APP_ICON_EXPLAINER, - title: lang.t('explain.icon_unlock.title', { partner: 'Zora' }), - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.appleBlue, - bgColor: colors?.appleBlue06, + finiliar_app_icon: { + logo: <FiniliarAppIcon />, + extraHeight: -90, + text: FINILIAR_APP_ICON_EXPLAINER, + title: FINILIAR_APP_ICON_TITLE, + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.finiliarPink, + bgColor: colors?.finiliarPink06, + }, }, - }, - zorb_app_icon: { - logo: <ZorbAppIcon />, - extraHeight: -65, - text: ZORB_APP_ICON_EXPLAINER, - title: ZORB_APP_ICON_TITLE, - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.zorbPink, - bgColor: colors?.zorbPink06, + golddoge_app_icon: { + logo: <GoldDogeAppIcon />, + extraHeight: -65, + text: GOLDDOGE_APP_ICON_EXPLAINER, + title: lang.t('explain.icon_unlock.title', { partner: 'DOGE' }), + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.dogeGold, + bgColor: colors?.dogeGold06, + }, }, - }, - poolboy_app_icon: { - logo: <PoolboyAppIcon />, - extraHeight: -90, - text: POOLBOY_APP_ICON_EXPLAINER, - title: POOLBOY_APP_ICON_TITLE, - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.poolboyPink, - bgColor: colors?.poolboyPink06, + raindoge_app_icon: { + logo: <RainDogeAppIcon />, + extraHeight: -65, + text: RAINDOGE_APP_ICON_EXPLAINER, + title: lang.t('explain.icon_unlock.title', { partner: 'The Doge NFT' }), + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.dogeGold, + bgColor: colors?.dogeGold06, + }, }, - }, - adworld_app_icon: { - logo: <AdworldAppIcon />, - extraHeight: -90, - text: ADWORLD_APP_ICON_EXPLAINER, - title: ADWORLD_APP_ICON_TITLE, - button: { - onPress: navigateToAppIconSettings, - label: lang.t('explain.icon_unlock.button'), - textColor: colors?.adworldRed, - bgColor: colors?.adworldRed06, + pooly_app_icon: { + logo: <PoolyAppIcon />, + extraHeight: -90, + text: POOLY_APP_ICON_EXPLAINER, + title: POOLY_APP_ICON_TITLE, + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.poolyPurple, + bgColor: colors?.poolyPurple06, + }, }, - }, - output_disabled: { - extraHeight: -30, - title: params?.inputToken - ? lang.t(`explain.output_disabled.${params?.isCrosschainSwap ? 'title_crosschain' : 'title'}`, { - inputToken: params?.inputToken, - fromNetwork: getNetworkObj(params?.fromNetwork).name, - }) - : lang.t('explain.output_disabled.title_empty'), - - text: params?.isCrosschainSwap - ? lang.t(`explain.output_disabled.${params?.isBridgeSwap ? 'text_bridge' : 'text_crosschain'}`, { - inputToken: params?.inputToken, - outputToken: params?.outputToken, - fromNetwork: getNetworkObj(params?.fromNetwork).name, - toNetwork: getNetworkObj(params?.toNetwork).name, - }) - : lang.t('explain.output_disabled.text', { - fromNetwork: getNetworkObj(params?.fromNetwork)?.name, - inputToken: params?.inputToken, - outputToken: params?.outputToken, - }), - logo: !isL2Network(params?.fromNetwork) ? ( - <CoinIcon address={ETH_ADDRESS} size={40} symbol={ETH_SYMBOL} /> - ) : ( - <ChainBadge network={params?.fromNetwork} marginBottom={8} position="relative" size="large" /> - ), - }, - floor_price: { - emoji: '📊', - extraHeight: -102, - text: FLOOR_PRICE_EXPLAINER, - title: lang.t('explain.floor_price.title'), - }, - gas: { - logo: ( - <CoinIcon - address={params?.nativeAsset?.address} - size={40} - symbol={params?.nativeAsset?.symbol} - type={params?.network?.toLowerCase()} - /> - ), - extraHeight: 2, - text: gasExplainer(params?.network), - title: lang.t('explain.gas.title', { - networkName: params?.network, - }), - }, - ens_primary_name: { - extraHeight: 50, - emoji: '❓', - text: ENS_PRIMARY_NAME_EXPLAINER, - title: ENS_PRIMARY_NAME_TITLE, - }, - ens_manager: { - extraHeight: -30, - emoji: '❓', - text: ENS_MANAGER_EXPLAINER, - title: ENS_MANAGER_TITLE, - }, - ens_owner: { - extraHeight: 0, - emoji: '❓', - text: ENS_OWNER_EXPLAINER, - title: ENS_OWNER_TITLE, - }, - ens_resolver: { - extraHeight: -60, - emoji: '❓', - text: ENS_RESOLVER_EXPLAINER, - title: ENS_RESOLVER_TITLE, - }, - ens_configuration: { - extraHeight: android ? 100 : 80, - emoji: '❓', - text: ENS_CONFIGURATION_EXPLAINER, - title: ENS_CONFIGURATION_TITLE, - }, - ensOnChainDataWarning: { - extraHeight: -30, - emoji: '✋', - text: ENS_ON_CHAIN_DATA_WARNING_EXPLAINER, - title: ENS_ON_CHAIN_DATA_WARNING_TITLE, - }, - currentBaseFeeStable: { - emoji: '🌞', - extraHeight: android ? 42 : 28, - text: BASE_CURRENT_BASE_FEE_EXPLAINER + CURRENT_BASE_FEE_EXPLAINER_STABLE, - title: CURRENT_BASE_FEE_TITLE, - }, - currentBaseFeeFalling: { - emoji: '📉', - extraHeight: android ? 22 : 2, - text: BASE_CURRENT_BASE_FEE_EXPLAINER + CURRENT_BASE_FEE_EXPLAINER_FALLING, - title: CURRENT_BASE_FEE_TITLE, - }, - currentBaseFeeRising: { - emoji: '🥵', - extraHeight: android ? 62 : 54, - text: BASE_CURRENT_BASE_FEE_EXPLAINER + CURRENT_BASE_FEE_EXPLAINER_RISING, - title: CURRENT_BASE_FEE_TITLE, - }, - currentBaseFeeSurging: { - emoji: '🎢', - extraHeight: android ? 102 : 54, - text: BASE_CURRENT_BASE_FEE_EXPLAINER + CURRENT_BASE_FEE_EXPLAINER_SURGING, - title: CURRENT_BASE_FEE_TITLE, - }, - currentBaseFeeNotrend: { - emoji: '⛽', - extraHeight: android ? -18 : -40, - text: BASE_CURRENT_BASE_FEE_EXPLAINER, - title: CURRENT_BASE_FEE_TITLE, - }, - maxBaseFee: { - emoji: '📈', - extraHeight: -31, - text: MAX_BASE_FEE_EXPLAINER, - title: lang.t('explain.max_base_fee.title'), - }, - minerTip: { - emoji: '⛏', - extraHeight: -31, - text: MINER_TIP_EXPLAINER, - title: lang.t('explain.miner_tip.title'), - }, - sending_funds_to_contract: { - emoji: '✋', - extraHeight: 80, - text: SENDING_FUNDS_TO_CONTRACT, - title: lang.t('explain.sending_to_contract.title'), - }, - verified: { - emoji: '', - text: VERIFIED_EXPLAINER, - title: lang.t('explain.verified.title'), - }, - unverified: { - extraHeight: 120, - emoji: '⚠️', - button: { - label: lang.t('button.continue'), - bgColor: colors?.alpha(colors?.blueGreyDark80, 0.04), - textColor: colors?.blueGreyDark80, + smol_app_icon: { + logo: <SmolAppIcon />, + extraHeight: -65, + text: SMOL_APP_ICON_EXPLAINER, + title: lang.t('explain.icon_unlock.title', { partner: 'SMOL' }), + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.smolPurple, + bgColor: colors?.smolPurple06, + }, }, - secondaryButton: { - label: lang.t('button.go_back_lowercase'), - textColor: colors?.appleBlue, - bgColor: colors?.clearBlue, + zora_app_icon: { + logo: <ZoraAppIcon />, + extraHeight: -90, + text: ZORA_APP_ICON_EXPLAINER, + title: lang.t('explain.icon_unlock.title', { partner: 'Zora' }), + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.appleBlue, + bgColor: colors?.appleBlue06, + }, }, - title: lang.t('explain.unverified.title', { - symbol: params?.asset?.symbol, - }), - stillCurious: ( - <Text {...getBodyTextPropsWithColor(colors)}> - {lang.t('explain.unverified.fragment1')} - <Text - color={colors?.appleBlue} - onPress={() => ethereumUtils.openTokenEtherscanURL(params?.asset.address, params?.asset?.network)} - size="large" - suppressHighlighting - weight="semibold" - > - {lang.t('explain.unverified.fragment2')} - </Text> - {lang.t('explain.unverified.fragment3')} - </Text> - ), - }, - optimism: { - emoji: '⛽️', - extraHeight: 150, - logo: <ChainBadge network={networkTypes.optimism} marginBottom={8} position="relative" size="large" />, - readMoreLink: buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', - query: { - campaign: 'explain', + zorb_app_icon: { + logo: <ZorbAppIcon />, + extraHeight: -65, + text: ZORB_APP_ICON_EXPLAINER, + title: ZORB_APP_ICON_TITLE, + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.zorbPink, + bgColor: colors?.zorbPink06, }, - }), - text: OPTIMISM_EXPLAINER, - title: lang.t('explain.optimism.title'), - }, - arbitrum: { - emoji: '⛽️', - extraHeight: 144, - logo: <ChainBadge network={networkTypes.arbitrum} marginBottom={8} position="relative" size="large" />, - readMoreLink: buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', - query: { - campaign: 'explain', + }, + poolboy_app_icon: { + logo: <PoolboyAppIcon />, + extraHeight: -90, + text: POOLBOY_APP_ICON_EXPLAINER, + title: POOLBOY_APP_ICON_TITLE, + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.poolboyPink, + bgColor: colors?.poolboyPink06, }, - }), - text: ARBITRUM_EXPLAINER, - title: lang.t('explain.arbitrum.title'), - }, - polygon: { - emoji: '⛽️', - extraHeight: 120, - logo: <ChainBadge network={networkTypes.polygon} marginBottom={8} position="relative" size="large" />, - readMoreLink: buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', - query: { - campaign: 'explain', + }, + adworld_app_icon: { + logo: <AdworldAppIcon />, + extraHeight: -90, + text: ADWORLD_APP_ICON_EXPLAINER, + title: ADWORLD_APP_ICON_TITLE, + button: { + onPress: navigateToAppIconSettings, + label: lang.t('explain.icon_unlock.button'), + textColor: colors?.adworldRed, + bgColor: colors?.adworldRed06, }, - }), - text: POLYGON_EXPLAINER, - title: lang.t('explain.polygon.title'), - }, - bsc: { - emoji: '⛽️', - extraHeight: IS_ANDROID ? 120 : 160, - logo: <ChainBadge network={networkTypes.bsc} marginBottom={8} position="relative" size="large" />, - readMoreLink: buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', - query: { - campaign: 'explain', + }, + output_disabled: { + extraHeight: -30, + title: params?.inputToken + ? lang.t(`explain.output_disabled.${params?.isCrosschainSwap ? 'title_crosschain' : 'title'}`, { + inputToken: params?.inputToken, + fromNetwork: getNetworkObj(params?.fromNetwork).name, + }) + : lang.t('explain.output_disabled.title_empty'), + + text: params?.isCrosschainSwap + ? lang.t(`explain.output_disabled.${params?.isBridgeSwap ? 'text_bridge' : 'text_crosschain'}`, { + inputToken: params?.inputToken, + outputToken: params?.outputToken, + fromNetwork: getNetworkObj(params?.fromNetwork).name, + toNetwork: getNetworkObj(params?.toNetwork).name, + }) + : lang.t('explain.output_disabled.text', { + fromNetwork: getNetworkObj(params?.fromNetwork)?.name, + inputToken: params?.inputToken, + outputToken: params?.outputToken, + }), + logo: !isL2Network(params?.fromNetwork) ? ( + <EthCoinIcon size={40} /> + ) : ( + <ChainBadge network={params?.fromNetwork} marginBottom={8} position="relative" size="large" /> + ), + }, + floor_price: { + emoji: '📊', + extraHeight: -102, + text: FLOOR_PRICE_EXPLAINER, + title: lang.t('explain.floor_price.title'), + }, + gas: { + logo: ( + <RainbowCoinIcon + size={40} + icon={params?.nativeAsset?.icon} + symbol={params?.nativeAsset?.symbol} + network={params?.network?.toLowerCase()} + colors={params?.nativeAsset?.colors} + theme={theme} + /> + ), + extraHeight: 2, + text: gasExplainer(params?.network), + title: lang.t('explain.gas.title', { + networkName: params?.network, + }), + }, + ens_primary_name: { + extraHeight: 50, + emoji: '❓', + text: ENS_PRIMARY_NAME_EXPLAINER, + title: ENS_PRIMARY_NAME_TITLE, + }, + ens_manager: { + extraHeight: -30, + emoji: '❓', + text: ENS_MANAGER_EXPLAINER, + title: ENS_MANAGER_TITLE, + }, + ens_owner: { + extraHeight: 0, + emoji: '❓', + text: ENS_OWNER_EXPLAINER, + title: ENS_OWNER_TITLE, + }, + ens_resolver: { + extraHeight: -60, + emoji: '❓', + text: ENS_RESOLVER_EXPLAINER, + title: ENS_RESOLVER_TITLE, + }, + ens_configuration: { + extraHeight: android ? 100 : 80, + emoji: '❓', + text: ENS_CONFIGURATION_EXPLAINER, + title: ENS_CONFIGURATION_TITLE, + }, + ensOnChainDataWarning: { + extraHeight: -30, + emoji: '✋', + text: ENS_ON_CHAIN_DATA_WARNING_EXPLAINER, + title: ENS_ON_CHAIN_DATA_WARNING_TITLE, + }, + currentBaseFeeStable: { + emoji: '🌞', + extraHeight: android ? 42 : 28, + text: BASE_CURRENT_BASE_FEE_EXPLAINER + CURRENT_BASE_FEE_EXPLAINER_STABLE, + title: CURRENT_BASE_FEE_TITLE, + }, + currentBaseFeeFalling: { + emoji: '📉', + extraHeight: android ? 22 : 2, + text: BASE_CURRENT_BASE_FEE_EXPLAINER + CURRENT_BASE_FEE_EXPLAINER_FALLING, + title: CURRENT_BASE_FEE_TITLE, + }, + currentBaseFeeRising: { + emoji: '🥵', + extraHeight: android ? 62 : 54, + text: BASE_CURRENT_BASE_FEE_EXPLAINER + CURRENT_BASE_FEE_EXPLAINER_RISING, + title: CURRENT_BASE_FEE_TITLE, + }, + currentBaseFeeSurging: { + emoji: '🎢', + extraHeight: android ? 102 : 54, + text: BASE_CURRENT_BASE_FEE_EXPLAINER + CURRENT_BASE_FEE_EXPLAINER_SURGING, + title: CURRENT_BASE_FEE_TITLE, + }, + currentBaseFeeNotrend: { + emoji: '⛽', + extraHeight: android ? -18 : -40, + text: BASE_CURRENT_BASE_FEE_EXPLAINER, + title: CURRENT_BASE_FEE_TITLE, + }, + maxBaseFee: { + emoji: '📈', + extraHeight: -31, + text: MAX_BASE_FEE_EXPLAINER, + title: lang.t('explain.max_base_fee.title'), + }, + minerTip: { + emoji: '⛏', + extraHeight: -31, + text: MINER_TIP_EXPLAINER, + title: lang.t('explain.miner_tip.title'), + }, + sending_funds_to_contract: { + emoji: '✋', + extraHeight: 80, + text: SENDING_FUNDS_TO_CONTRACT, + title: lang.t('explain.sending_to_contract.title'), + }, + verified: { + emoji: '', + text: VERIFIED_EXPLAINER, + title: lang.t('explain.verified.title'), + }, + unverified: { + extraHeight: 120, + emoji: '⚠️', + button: { + label: lang.t('button.continue'), + bgColor: colors?.alpha(colors?.blueGreyDark80, 0.04), + textColor: colors?.blueGreyDark80, }, - }), - text: BSC_EXPLAINER, - title: lang.t('explain.bsc.title'), - }, - zora: { - emoji: '⛽️', - extraHeight: 144, - logo: <ChainBadge network={networkTypes.zora} marginBottom={8} position="relative" size="large" />, - readMoreLink: buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', - query: { - campaign: 'explain', + secondaryButton: { + label: lang.t('button.go_back_lowercase'), + textColor: colors?.appleBlue, + bgColor: colors?.clearBlue, }, - }), - text: ZORA_EXPLAINER, - title: lang.t('explain.zora.title'), - }, - base: { - emoji: '⛽️', - extraHeight: 144, - logo: <ChainBadge network={networkTypes.base} marginBottom={8} position="relative" size="large" />, - readMoreLink: buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', - query: { - campaign: 'explain', + title: lang.t('explain.unverified.title', { + symbol: params?.asset?.symbol, + }), + stillCurious: ( + <Text {...getBodyTextPropsWithColor(colors)}> + {lang.t('explain.unverified.fragment1')} + <Text + color={colors?.appleBlue} + onPress={() => ethereumUtils.openTokenEtherscanURL(params?.asset.address, params?.asset?.network)} + size="large" + suppressHighlighting + weight="semibold" + > + {lang.t('explain.unverified.fragment2')} + </Text> + {lang.t('explain.unverified.fragment3')} + </Text> + ), + }, + optimism: { + emoji: '⛽️', + extraHeight: 150, + logo: <ChainBadge network={networkTypes.optimism} marginBottom={8} position="relative" size="large" />, + readMoreLink: buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + query: { + campaign: 'explain', + }, + }), + text: OPTIMISM_EXPLAINER, + title: lang.t('explain.optimism.title'), + }, + arbitrum: { + emoji: '⛽️', + extraHeight: 144, + logo: <ChainBadge network={networkTypes.arbitrum} marginBottom={8} position="relative" size="large" />, + readMoreLink: buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + query: { + campaign: 'explain', + }, + }), + text: ARBITRUM_EXPLAINER, + title: lang.t('explain.arbitrum.title'), + }, + polygon: { + emoji: '⛽️', + extraHeight: 120, + logo: <ChainBadge network={networkTypes.polygon} marginBottom={8} position="relative" size="large" />, + readMoreLink: buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + query: { + campaign: 'explain', + }, + }), + text: POLYGON_EXPLAINER, + title: lang.t('explain.polygon.title'), + }, + bsc: { + emoji: '⛽️', + extraHeight: IS_ANDROID ? 120 : 160, + logo: <ChainBadge network={networkTypes.bsc} marginBottom={8} position="relative" size="large" />, + readMoreLink: buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + query: { + campaign: 'explain', + }, + }), + text: BSC_EXPLAINER, + title: lang.t('explain.bsc.title'), + }, + zora: { + emoji: '⛽️', + extraHeight: 144, + logo: <ChainBadge network={networkTypes.zora} marginBottom={8} position="relative" size="large" />, + readMoreLink: buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + query: { + campaign: 'explain', + }, + }), + text: ZORA_EXPLAINER, + title: lang.t('explain.zora.title'), + }, + base: { + emoji: '⛽️', + extraHeight: 144, + logo: <ChainBadge network={networkTypes.base} marginBottom={8} position="relative" size="large" />, + readMoreLink: buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + query: { + campaign: 'explain', + }, + }), + text: BASE_EXPLAINER, + title: lang.t('explain.base.title'), + }, + failed_wc_connection: { + emoji: '😵', + extraHeight: -50, + text: lang.t('explain.failed_walletconnect.text'), + title: lang.t('explain.failed_walletconnect.title'), + }, + failed_wc_invalid_methods: { + emoji: '😵', + extraHeight: -100, + text: lang.t('explain.failed_wc_invalid_methods.text'), + title: lang.t('explain.failed_wc_invalid_methods.title'), + }, + failed_wc_invalid_chains: { + emoji: '😵', + extraHeight: -100, + text: lang.t('explain.failed_wc_invalid_chains.text'), + title: lang.t('explain.failed_wc_invalid_chains.title'), + }, + failed_wc_invalid_chain: { + emoji: '😵', + extraHeight: -100, + text: lang.t('explain.failed_wc_invalid_chain.text'), + title: lang.t('explain.failed_wc_invalid_chain.title'), + }, + backup: { + emoji: '🔐', + extraHeight: 20, + text: BACKUP_EXPLAINER, + title: lang.t('explain.backup.title'), + }, + rainbow_fee: { + emoji: '🌈', + extraHeight: -100, + text: lang.t('explain.rainbow_fee.text', { + feePercentage: params?.feePercentage, + }), + title: 'Rainbow Fee', + }, + swapResetInputs: { + button: { + label: `Continue with ${getNetworkObj(params?.network)?.name}`, + bgColor: colors?.networkColors[params?.network] && colors?.alpha(colors?.networkColors[params?.network], 0.06), + textColor: colors?.networkColors[params?.network] && colors?.networkColors?.[params?.network], }, - }), - text: BASE_EXPLAINER, - title: lang.t('explain.base.title'), - }, - failed_wc_connection: { - emoji: '😵', - extraHeight: -50, - text: lang.t('explain.failed_walletconnect.text'), - title: lang.t('explain.failed_walletconnect.title'), - }, - failed_wc_invalid_methods: { - emoji: '😵', - extraHeight: -100, - text: lang.t('explain.failed_wc_invalid_methods.text'), - title: lang.t('explain.failed_wc_invalid_methods.title'), - }, - failed_wc_invalid_chains: { - emoji: '😵', - extraHeight: -100, - text: lang.t('explain.failed_wc_invalid_chains.text'), - title: lang.t('explain.failed_wc_invalid_chains.title'), - }, - failed_wc_invalid_chain: { - emoji: '😵', - extraHeight: -100, - text: lang.t('explain.failed_wc_invalid_chain.text'), - title: lang.t('explain.failed_wc_invalid_chain.title'), - }, - backup: { - emoji: '🔐', - extraHeight: 20, - text: BACKUP_EXPLAINER, - title: lang.t('explain.backup.title'), - }, - rainbow_fee: { - emoji: '🌈', - extraHeight: -100, - text: lang.t('explain.rainbow_fee.text', { - feePercentage: params?.feePercentage, - }), - title: 'Rainbow Fee', - }, - swapResetInputs: { - button: { - label: `Continue with ${getNetworkObj(params?.network)?.name}`, - bgColor: colors?.networkColors[params?.network] && colors?.alpha(colors?.networkColors[params?.network], 0.06), - textColor: colors?.networkColors[params?.network] && colors?.networkColors?.[params?.network], + emoji: '🔐', + extraHeight: -90, + text: SWAP_RESET_EXPLAINER, + title: `Switching to ${getNetworkObj(params?.network)?.name}`, + logo: + params?.network !== 'mainnet' ? ( + <ChainBadge network={networkTypes[params?.network]} marginBottom={8} position="relative" size="large" /> + ) : ( + <EthCoinIcon size={40} /> + ), }, - emoji: '🔐', - extraHeight: -90, - text: SWAP_RESET_EXPLAINER, - title: `Switching to ${getNetworkObj(params?.network)?.name}`, - logo: - params?.network !== 'mainnet' ? ( - <ChainBadge network={networkTypes[params?.network]} marginBottom={8} position="relative" size="large" /> - ) : ( - <CoinIcon address={ETH_ADDRESS} size={40} symbol={ETH_ADDRESS} /> - ), - }, - f2cSemiSupportedAssetPurchased: { - emoji: '🎉', - title: i18n.t(i18n.l.wallet.add_cash_v2.explain_sheet.semi_supported.title), - text: i18n.t(i18n.l.wallet.add_cash_v2.explain_sheet.semi_supported.title), - extraHeight: -80, - }, - insufficientLiquidity: { - extraHeight: -20, - emoji: '🏦', - title: lang.t('explain.insufficient_liquidity.title'), - stillCurious: ( - <Text {...getBodyTextPropsWithColor(colors)}> - {lang.t('explain.insufficient_liquidity.fragment1')} - <Text - color={colors?.appleBlue} - onPress={() => - Linking.openURL( - buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-liquidity-providing', - query: { - campaign: 'explain', - }, - }) - ) - } - size="large" - suppressHighlighting - weight="semibold" - > - {lang.t('explain.insufficient_liquidity.fragment2')} + f2cSemiSupportedAssetPurchased: { + emoji: '🎉', + title: i18n.t(i18n.l.wallet.add_cash_v2.explain_sheet.semi_supported.title), + text: i18n.t(i18n.l.wallet.add_cash_v2.explain_sheet.semi_supported.title), + extraHeight: -80, + }, + insufficientLiquidity: { + extraHeight: -20, + emoji: '🏦', + title: lang.t('explain.insufficient_liquidity.title'), + stillCurious: ( + <Text {...getBodyTextPropsWithColor(colors)}> + {lang.t('explain.insufficient_liquidity.fragment1')} + <Text + color={colors?.appleBlue} + onPress={() => + Linking.openURL( + buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/a-beginners-guide-to-liquidity-providing', + query: { + campaign: 'explain', + }, + }) + ) + } + size="large" + suppressHighlighting + weight="semibold" + > + {lang.t('explain.insufficient_liquidity.fragment2')} + </Text> + {lang.t('explain.insufficient_liquidity.fragment3')} </Text> - {lang.t('explain.insufficient_liquidity.fragment3')} - </Text> - ), - }, - feeOnTransfer: { - extraHeight: -70, - logo: ( - <RowWithMargins justify="center" margin={35} marginBottom={10}> - <CoinIcon size={40} {...params?.inputCurrency} /> - </RowWithMargins> - ), - title: lang.t('explain.fee_on_transfer.title'), - stillCurious: ( - <Text {...getBodyTextPropsWithColor(colors)}> - {lang.t('explain.fee_on_transfer.fragment1', { - tokenName: params?.inputCurrency?.symbol, - })} - <Text - color={colors?.appleBlue} - onPress={() => - Linking.openURL( - buildRainbowLearnUrl({ - url: 'https://support.rainbow.me/en/articles/8324868-fee-on-transfer-tokens', - query: { - campaign: 'explain', - }, - }) - ) - } - size="large" - suppressHighlighting - weight="semibold" - > - {lang.t('explain.fee_on_transfer.fragment2')} + ), + }, + feeOnTransfer: { + extraHeight: -70, + logo: ( + <RowWithMargins justify="center" margin={35} marginBottom={10}> + <RainbowCoinIcon + size={40} + icon={params?.inputCurrency?.icon} + symbol={params?.inputCurrency?.symbol} + network={params?.inputCurrency?.network} + colors={params?.inputCurrency?.colors} + theme={theme} + /> + </RowWithMargins> + ), + title: lang.t('explain.fee_on_transfer.title'), + stillCurious: ( + <Text {...getBodyTextPropsWithColor(colors)}> + {lang.t('explain.fee_on_transfer.fragment1', { + tokenName: params?.inputCurrency?.symbol, + })} + <Text + color={colors?.appleBlue} + onPress={() => + Linking.openURL( + buildRainbowLearnUrl({ + url: 'https://support.rainbow.me/en/articles/8324868-fee-on-transfer-tokens', + query: { + campaign: 'explain', + }, + }) + ) + } + size="large" + suppressHighlighting + weight="semibold" + > + {lang.t('explain.fee_on_transfer.fragment2')} + </Text> + {lang.t('explain.fee_on_transfer.fragment3')} </Text> - {lang.t('explain.fee_on_transfer.fragment3')} - </Text> - ), - }, - noRouteFound: { - extraHeight: -90, - emoji: '🚧', - title: lang.t('explain.no_route_found.title'), - stillCurious: ( - <> - <Text {...getBodyTextPropsWithColor(colors)}>{lang.t('explain.no_route_found.fragment1')}</Text> - <Text {...getBodyTextPropsWithColor(colors)}>{lang.t('explain.no_route_found.fragment2')}</Text> - </> - ), - }, - noQuote: { - extraHeight: -90, - emoji: '🏦', - title: lang.t('explain.no_quote.title'), - text: lang.t('explain.no_quote.text'), - logo: ( - <RowWithMargins justify="center" margin={35} marginBottom={10}> - <CoinIcon size={40} {...params?.inputCurrency} /> - <DoubleChevron /> - <CoinIcon size={40} {...params?.outputCurrency} /> - </RowWithMargins> - ), - }, - crossChainGas: { - extraHeight: 40, - title: lang.t('explain.cross_chain_swap.title'), - text: lang.t('explain.cross_chain_swap.text'), - logo: ( - <RowWithMargins justify="center" margin={35} marginBottom={10}> - <CoinIcon size={40} {...params?.inputCurrency} /> - <DoubleChevron /> - <CoinIcon size={40} {...params?.outputCurrency} /> - </RowWithMargins> - ), - }, - availableNetworks: { - buttonText: `Go to Hop`, - extraHeight: -90, - text: availableNetworksExplainer(params?.tokenSymbol, params?.networks), - title: - params?.networks?.length > 1 - ? lang.t('explain.available_networks.title_plural', { - length: params?.networks?.length, - }) - : lang.t('explain.available_networks.title_singular', { - network: params?.networks?.[0], - }), - logo: ( - <Row justify="center" marginBottom={10}> - {params?.networks?.map((network, index) => { - return ( - <Box - height={{ custom: 40 }} - key={`networks-${network}`} - marginLeft={{ - custom: index > 0 ? -12 : params?.networks?.length % 2 === 0 ? -2 : -30, - }} - style={{ - borderColor: colors.transparent, - borderRadius: 0, - borderWidth: 1, - zIndex: index, - }} - width={{ custom: 40 }} - zIndex={params?.networks?.length - index} - > - {network !== 'mainnet' ? ( - <ChainBadge network={network} position="relative" size="large" /> - ) : ( - <CoinIcon address={ETH_ADDRESS} size={40} style={{ marginTop: 4 }} symbol={ETH_SYMBOL} /> - )} - </Box> - ); - })} - </Row> - ), - }, - obtainL2Assets: { - extraHeight: 40, - button: { - label: lang.t('explain.go_to_hop_with_icon.text'), - bgColor: colors?.alpha(colors?.blueGreyDark80, 0.04), - textColor: colors?.blueGreyDark80, + ), }, - secondaryButton: { - label: lang.t('button.go_back_lowercase'), - textColor: colors?.appleBlue, - bgColor: colors?.clearBlue, + noRouteFound: { + extraHeight: -90, + emoji: '🚧', + title: lang.t('explain.no_route_found.title'), + stillCurious: ( + <> + <Text {...getBodyTextPropsWithColor(colors)}>{lang.t('explain.no_route_found.fragment1')}</Text> + <Text {...getBodyTextPropsWithColor(colors)}>{lang.t('explain.no_route_found.fragment2')}</Text> + </> + ), }, - stillCurious: ( - <Text {...getBodyTextPropsWithColor(colors)}> - {lang.t('explain.obtain_l2_asset.fragment1', { - networkName: params?.networkName, - tokenName: params?.assetName, - })} - <Text - color={colors?.appleBlue} - onPress={() => - Linking.openURL( - buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', - query: { - campaign: 'explain', - }, - }) - ) - } - size="large" - suppressHighlighting - weight="semibold" - > - {lang.t('explain.obtain_l2_asset.fragment2', { + noQuote: { + extraHeight: -90, + emoji: '🏦', + title: lang.t('explain.no_quote.title'), + text: lang.t('explain.no_quote.text'), + logo: ( + <RowWithMargins justify="center" margin={35} marginBottom={10}> + <RainbowCoinIcon + size={40} + icon={params?.inputCurrency?.icon} + symbol={params?.inputCurrency?.symbol} + network={params?.inputCurrency?.network} + colors={params?.inputCurrency?.colors} + theme={theme} + /> + <DoubleChevron /> + <RainbowCoinIcon + size={40} + icon={params?.outputCurrency?.icon} + symbol={params?.outputCurrency?.symbol} + network={params?.outputCurrency?.network} + colors={params?.outputCurrency?.colors} + theme={theme} + /> + </RowWithMargins> + ), + }, + crossChainGas: { + extraHeight: 40, + title: lang.t('explain.cross_chain_swap.title'), + text: lang.t('explain.cross_chain_swap.text'), + logo: ( + <RowWithMargins justify="center" margin={35} marginBottom={10}> + <RainbowCoinIcon + size={40} + icon={params?.inputCurrency?.icon} + symbol={params?.inputCurrency?.symbol} + network={params?.inputCurrency?.network} + colors={params?.inputCurrency?.colors} + theme={theme} + /> + <DoubleChevron /> + <RainbowCoinIcon + size={40} + icon={params?.outputCurrency?.icon} + symbol={params?.outputCurrency?.symbol} + network={params?.outputCurrency?.network} + colors={params?.outputCurrency?.colors} + theme={theme} + /> + </RowWithMargins> + ), + }, + availableNetworks: { + buttonText: `Go to Hop`, + extraHeight: -90, + text: availableNetworksExplainer(params?.tokenSymbol, params?.networks), + title: + params?.networks?.length > 1 + ? lang.t('explain.available_networks.title_plural', { + length: params?.networks?.length, + }) + : lang.t('explain.available_networks.title_singular', { + network: params?.networks?.[0], + }), + logo: ( + <Row justify="center" marginBottom={10}> + {params?.networks?.map((network, index) => { + return ( + <Box + height={{ custom: 40 }} + key={`networks-${network}`} + marginLeft={{ + custom: index > 0 ? -12 : params?.networks?.length % 2 === 0 ? -2 : -30, + }} + style={{ + borderColor: colors.transparent, + borderRadius: 0, + borderWidth: 1, + zIndex: index, + }} + width={{ custom: 40 }} + zIndex={params?.networks?.length - index} + > + {network !== 'mainnet' ? ( + <ChainBadge network={network} position="relative" size="large" /> + ) : ( + <View style={{ marginTop: 4 }}> + <EthCoinIcon size={40} /> + </View> + )} + </Box> + ); + })} + </Row> + ), + }, + obtainL2Assets: { + extraHeight: 40, + button: { + label: lang.t('explain.go_to_hop_with_icon.text'), + bgColor: colors?.alpha(colors?.blueGreyDark80, 0.04), + textColor: colors?.blueGreyDark80, + }, + secondaryButton: { + label: lang.t('button.go_back_lowercase'), + textColor: colors?.appleBlue, + bgColor: colors?.clearBlue, + }, + stillCurious: ( + <Text {...getBodyTextPropsWithColor(colors)}> + {lang.t('explain.obtain_l2_asset.fragment1', { networkName: params?.networkName, + tokenName: params?.assetName, })} + <Text + color={colors?.appleBlue} + onPress={() => + Linking.openURL( + buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/a-beginners-guide-to-layer-2-networks', + query: { + campaign: 'explain', + }, + }) + ) + } + size="large" + suppressHighlighting + weight="semibold" + > + {lang.t('explain.obtain_l2_asset.fragment2', { + networkName: params?.networkName, + })} + </Text> + {lang.t('explain.obtain_l2_asset.fragment3')} </Text> - {lang.t('explain.obtain_l2_asset.fragment3')} - </Text> - ), - logo: <ChainBadge network={params?.network} marginBottom={8} position="relative" size="large" />, - title: lang.t('explain.obtain_l2_asset.title', { - networkName: params?.networkName, - }), - }, - flashbots: { - extraHeight: android ? 20 : 0, - emoji: '🤖', - stillCurious: ( - <Text {...getBodyTextPropsWithColor(colors)}> - {lang.t('explain.flashbots.still_curious.fragment1')} - <Text - color={colors?.appleBlue} - onPress={() => - Linking.openURL( - buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/protecting-transactions-with-flashbots', - query: { - campaign: 'explain', - }, - }) - ) - } - size="large" - suppressHighlighting - weight="semibold" - > - {lang.t('explain.flashbots.still_curious.fragment2')} + ), + logo: <ChainBadge network={params?.network} marginBottom={8} position="relative" size="large" />, + title: lang.t('explain.obtain_l2_asset.title', { + networkName: params?.networkName, + }), + }, + flashbots: { + extraHeight: android ? 20 : 0, + emoji: '🤖', + stillCurious: ( + <Text {...getBodyTextPropsWithColor(colors)}> + {lang.t('explain.flashbots.still_curious.fragment1')} + <Text + color={colors?.appleBlue} + onPress={() => + Linking.openURL( + buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/protecting-transactions-with-flashbots', + query: { + campaign: 'explain', + }, + }) + ) + } + size="large" + suppressHighlighting + weight="semibold" + > + {lang.t('explain.flashbots.still_curious.fragment2')} + </Text> + {lang.t('explain.flashbots.still_curious.fragment3')} </Text> - {lang.t('explain.flashbots.still_curious.fragment3')} - </Text> - ), - text: lang.t('explain.flashbots.text'), - title: lang.t('explain.flashbots.title'), - }, - routeSwaps: { - extraHeight: android ? 20 : 0, - emoji: '🔀', - stillCurious: ( - <Text {...getBodyTextPropsWithColor(colors)}> - {lang.t('explain.swap_routing.still_curious.fragment1')} - <Text - color={colors?.appleBlue} - onPress={() => - Linking.openURL( - buildRainbowLearnUrl({ - url: 'https://learn.rainbow.me/swap-with-confidence-with-rainbow', - query: { - campaign: 'explain', - }, - }) - ) - } - size="large" - suppressHighlighting - weight="semibold" - > - {lang.t('explain.swap_routing.still_curious.fragment2')} + ), + text: lang.t('explain.flashbots.text'), + title: lang.t('explain.flashbots.title'), + }, + routeSwaps: { + extraHeight: android ? 20 : 0, + emoji: '🔀', + stillCurious: ( + <Text {...getBodyTextPropsWithColor(colors)}> + {lang.t('explain.swap_routing.still_curious.fragment1')} + <Text + color={colors?.appleBlue} + onPress={() => + Linking.openURL( + buildRainbowLearnUrl({ + url: 'https://learn.rainbow.me/swap-with-confidence-with-rainbow', + query: { + campaign: 'explain', + }, + }) + ) + } + size="large" + suppressHighlighting + weight="semibold" + > + {lang.t('explain.swap_routing.still_curious.fragment2')} + </Text> + {lang.t('explain.swap_routing.still_curious.fragment3')} </Text> - {lang.t('explain.swap_routing.still_curious.fragment3')} - </Text> - ), - text: lang.t('explain.swap_routing.text'), - title: lang.t('explain.swap_routing.title'), - }, - slippage: { - extraHeight: 126, - emoji: '🌊', - stillCurious: ( - <Text {...getBodyTextPropsWithColor(colors)}> - {lang.t('explain.slippage.still_curious.fragment1')} - <Text - color={colors?.appleBlue} - onPress={() => Linking.openURL('https://academy.shrimpy.io/post/what-is-slippage-how-to-avoid-slippage-on-defi-exchanges')} - size="large" - suppressHighlighting - weight="semibold" - > - {lang.t('explain.slippage.still_curious.fragment2')} + ), + text: lang.t('explain.swap_routing.text'), + title: lang.t('explain.swap_routing.title'), + }, + slippage: { + extraHeight: 126, + emoji: '🌊', + stillCurious: ( + <Text {...getBodyTextPropsWithColor(colors)}> + {lang.t('explain.slippage.still_curious.fragment1')} + <Text + color={colors?.appleBlue} + onPress={() => Linking.openURL('https://academy.shrimpy.io/post/what-is-slippage-how-to-avoid-slippage-on-defi-exchanges')} + size="large" + suppressHighlighting + weight="semibold" + > + {lang.t('explain.slippage.still_curious.fragment2')} + </Text> + {lang.t('explain.slippage.still_curious.fragment3')} </Text> - {lang.t('explain.slippage.still_curious.fragment3')} - </Text> - ), - text: lang.t('explain.slippage.text'), - title: lang.t('explain.slippage.title'), - }, - swap_refuel_add: { - logo: ( - <DashedWrapper - size={50} - childXPosition={10} - colors={[ - colors?.networkColors[params?.network], - getTokenMetadata(params?.nativeAsset?.mainnet_address)?.color ?? colors?.appleBlue, - ]} - > - <CoinIcon - mainnet_address={params?.nativeAsset?.mainnet_address} - address={params?.nativeAsset?.address} - symbol={params?.nativeAsset?.symbol} - type={params?.nativeAsset?.network} - size={30} - badgeSize="tiny" - badgeXPosition={-4} - badgeYPosition={1} - /> - </DashedWrapper> - ), - title: lang.t('explain.swap_refuel.title', { - networkName: params?.networkName, - gasToken: params?.gasToken, - }), - text: lang.t('explain.swap_refuel.text', { - networkName: params?.networkName, - gasToken: params?.gasToken, - }), - button: { - label: lang.t('button.no_thanks'), - textColor: 'blueGreyDark60', - bgColor: colors?.transparent, - onPress: params?.onContinue, + ), + text: lang.t('explain.slippage.text'), + title: lang.t('explain.slippage.title'), }, - secondaryButton: { - label: lang.t('explain.swap_refuel.button', { + swap_refuel_add: { + logo: ( + <DashedWrapper + size={50} + childXPosition={10} + colors={[ + colors?.networkColors[params?.network], + getTokenMetadata(params?.nativeAsset?.mainnet_address)?.color ?? colors?.appleBlue, + ]} + > + <RainbowCoinIcon + size={30} + icon={params?.nativeAsset?.icon} + symbol={params?.nativeAsset?.symbol} + network={params?.nativeAsset?.network} + colors={params?.nativeAssety?.colors} + theme={theme} + ignoreBadge + /> + </DashedWrapper> + ), + title: lang.t('explain.swap_refuel.title', { networkName: params?.networkName, gasToken: params?.gasToken, }), - textColor: colors?.networkColors[params?.network], - bgColor: colors?.networkColors[params?.network] && colors?.alpha(colors?.networkColors[params?.network], 0.05), - onPress: params?.onRefuel, - }, - }, - swap_refuel_deduct: { - logo: ( - <DashedWrapper - size={50} - childXPosition={10} - colors={[ - colors?.networkColors[params?.network], - getTokenMetadata(params?.nativeAsset?.mainnet_address)?.color ?? colors?.appleBlue, - ]} - > - <CoinIcon - address={params?.nativeAsset?.mainnet_address} - symbol={params?.nativeAsset?.symbol} - type={params?.nativeAsset?.network} - size={30} - badgeSize="tiny" - badgeXPosition={-4} - badgeYPosition={1} - /> - </DashedWrapper> - ), - title: lang.t('explain.swap_refuel_deduct.title', { - networkName: params?.networkName, - gasToken: params?.gasToken, - }), - text: lang.t('explain.swap_refuel_deduct.text', { - networkName: params?.networkName, - gasToken: params?.gasToken, - }), - button: { - label: lang.t('button.no_thanks'), - textColor: 'blueGreyDark60', - bgColor: colors?.transparent, - onPress: params?.onContinue, - }, - secondaryButton: { - label: lang.t('explain.swap_refuel_deduct.button', { + text: lang.t('explain.swap_refuel.text', { networkName: params?.networkName, gasToken: params?.gasToken, }), - textColor: colors?.networkColors[params?.network], - bgColor: colors?.networkColors[params?.network] && colors?.alpha(colors?.networkColors[params?.network], 0.05), - onPress: params?.onRefuel, + button: { + label: lang.t('button.no_thanks'), + textColor: 'blueGreyDark60', + bgColor: colors?.transparent, + onPress: params?.onContinue, + }, + secondaryButton: { + label: lang.t('explain.swap_refuel.button', { + networkName: params?.networkName, + gasToken: params?.gasToken, + }), + textColor: colors?.networkColors[params?.network], + bgColor: colors?.networkColors[params?.network] && colors?.alpha(colors?.networkColors[params?.network], 0.05), + onPress: params?.onRefuel, + }, }, - }, - swap_refuel_notice: { - extraHeight: 50, - logo: ( - <DashedWrapper - size={50} - childXPosition={10} - colors={[ - colors?.networkColors[params?.network], - getTokenMetadata(params?.nativeAsset?.mainnet_address)?.color ?? colors?.appleBlue, - ]} - > - <CoinIcon - address={params?.nativeAsset?.mainnet_address} - symbol={params?.nativeAsset?.symbol} - type={params?.nativeAsset?.network} - size={30} - badgeSize="tiny" - badgeXPosition={-4} - badgeYPosition={1} - /> - </DashedWrapper> - ), - title: lang.t('explain.swap_refuel_notice.title', { - networkName: params?.networkName, - gasToken: params?.gasToken, - }), - text: lang.t('explain.swap_refuel_notice.text', { - networkName: params?.networkName, - gasToken: params?.gasToken, - }), - button: { - label: lang.t('button.go_back'), - textColor: 'blueGreyDark60', - bgColor: colors?.transparent, - onPress: params?.onContinue, + swap_refuel_deduct: { + logo: ( + <DashedWrapper + size={50} + childXPosition={10} + colors={[ + colors?.networkColors[params?.network], + getTokenMetadata(params?.nativeAsset?.mainnet_address)?.color ?? colors?.appleBlue, + ]} + > + <RainbowCoinIcon + size={30} + icon={params?.nativeAsset?.icon} + symbol={params?.nativeAsset?.symbol} + network={params?.nativeAsset?.network} + colors={params?.nativeAsset?.colors} + theme={theme} + ignoreBadge + /> + </DashedWrapper> + ), + title: lang.t('explain.swap_refuel_deduct.title', { + networkName: params?.networkName, + gasToken: params?.gasToken, + }), + text: lang.t('explain.swap_refuel_deduct.text', { + networkName: params?.networkName, + gasToken: params?.gasToken, + }), + button: { + label: lang.t('button.no_thanks'), + textColor: 'blueGreyDark60', + bgColor: colors?.transparent, + onPress: params?.onContinue, + }, + secondaryButton: { + label: lang.t('explain.swap_refuel_deduct.button', { + networkName: params?.networkName, + gasToken: params?.gasToken, + }), + textColor: colors?.networkColors[params?.network], + bgColor: colors?.networkColors[params?.network] && colors?.alpha(colors?.networkColors[params?.network], 0.05), + onPress: params?.onRefuel, + }, }, - secondaryButton: { - label: lang.t('button.proceed_anyway'), - textColor: colors?.appleBlue, - bgColor: colors?.alpha(colors?.appleBlue, 0.05), - onPress: params?.onProceed, + swap_refuel_notice: { + extraHeight: 50, + logo: ( + <DashedWrapper + size={50} + childXPosition={10} + colors={[ + colors?.networkColors[params?.network], + getTokenMetadata(params?.nativeAsset?.mainnet_address)?.color ?? colors?.appleBlue, + ]} + > + <RainbowCoinIcon + size={30} + icon={params?.nativeAsset?.icon} + symbol={params?.nativeAsset?.symbol} + network={params?.nativeAsset?.network} + colors={params?.nativeAsset?.colors} + theme={theme} + /> + </DashedWrapper> + ), + title: lang.t('explain.swap_refuel_notice.title', { + networkName: params?.networkName, + gasToken: params?.gasToken, + }), + text: lang.t('explain.swap_refuel_notice.text', { + networkName: params?.networkName, + gasToken: params?.gasToken, + }), + button: { + label: lang.t('button.go_back'), + textColor: 'blueGreyDark60', + bgColor: colors?.transparent, + onPress: params?.onContinue, + }, + secondaryButton: { + label: lang.t('button.proceed_anyway'), + textColor: colors?.appleBlue, + bgColor: colors?.alpha(colors?.appleBlue, 0.05), + onPress: params?.onProceed, + }, }, - }, -}); + }; +}; const ExplainSheet = () => { const { height: deviceHeight } = useDimensions(); @@ -1266,7 +1307,7 @@ const ExplainSheet = () => { const { params } = useRoute(); const type = params.type; - const { colors } = useTheme(); + const theme = useTheme(); const { goBack, navigate } = useNavigation(); const renderBaseFeeIndicator = useMemo(() => { if (!type.includes('currentBaseFee')) return null; @@ -1281,8 +1322,8 @@ const ExplainSheet = () => { }, [params, type]); const explainSheetConfig = useMemo(() => { - return explainers(params, colors)[type]; - }, [colors, params, type]); + return explainers(params, theme)[type]; + }, [theme, params, type]); const handleClose = useCallback(() => { goBack(); params?.onClose?.(); @@ -1321,24 +1362,24 @@ const ExplainSheet = () => { const secondaryButton = (explainSheetConfig?.readMoreLink || explainSheetConfig?.secondaryButton?.label) && ( <Column height={60} style={android && reverseButtons && { marginTop: 16 }}> <SheetActionButton - color={explainSheetConfig?.secondaryButton?.bgColor ?? colors.blueGreyDarkLight} + color={explainSheetConfig?.secondaryButton?.bgColor ?? theme.colors.blueGreyDarkLight} isTransparent label={explainSheetConfig.secondaryButton?.label || lang.t('explain.read_more')} onPress={onSecondaryPress} size="big" - textColor={explainSheetConfig.secondaryButton?.textColor ?? colors.blueGreyDark80} + textColor={explainSheetConfig.secondaryButton?.textColor ?? theme.colors.blueGreyDark80} weight="heavy" /> </Column> ); const accentCta = ( <SheetActionButton - color={explainSheetConfig.button?.bgColor || colors.alpha(colors.appleBlue, 0.04)} + color={explainSheetConfig.button?.bgColor || theme.colors.alpha(theme.colors.appleBlue, 0.04)} isTransparent label={explainSheetConfig.button?.label || lang.t('button.got_it')} onPress={onPrimaryPress} size="big" - textColor={explainSheetConfig.button?.textColor ?? colors.appleBlue} + textColor={explainSheetConfig.button?.textColor ?? theme.colors.appleBlue} weight="heavy" testID={'explainer-sheet-accent'} /> @@ -1349,7 +1390,7 @@ const ExplainSheet = () => { } return buttonArray; }, [ - colors, + theme.colors, explainSheetConfig.button, explainSheetConfig.secondaryButton, explainSheetConfig?.readMoreLink, @@ -1393,7 +1434,7 @@ const ExplainSheet = () => { {/** base fee explainer */} {renderBaseFeeIndicator} - {explainSheetConfig.text && <Text {...getBodyTextPropsWithColor(colors)}>{explainSheetConfig.text}</Text>} + {explainSheetConfig.text && <Text {...getBodyTextPropsWithColor(theme.colors)}>{explainSheetConfig.text}</Text>} {explainSheetConfig?.stillCurious && explainSheetConfig.stillCurious} {buttons} diff --git a/src/screens/MintsSheet/card/Card.tsx b/src/screens/MintsSheet/card/Card.tsx index 5372e3b4ee6..7d438dff17c 100644 --- a/src/screens/MintsSheet/card/Card.tsx +++ b/src/screens/MintsSheet/card/Card.tsx @@ -7,14 +7,14 @@ import { getNetworkObj } from '@/networks'; import { getNetworkFromChainId } from '@/utils/ethereumUtils'; import { ButtonPressAnimation } from '@/components/animations'; import { Placeholder, RecentMintCell } from './RecentMintCell'; -import { Linking, View } from 'react-native'; +import { View } from 'react-native'; import { useTheme } from '@/theme'; import { analyticsV2 } from '@/analytics'; import * as i18n from '@/languages'; import ChainBadge from '@/components/coin-icon/ChainBadge'; -import { CoinIcon } from '@/components/coin-icon'; import { Network } from '@/helpers'; import { navigateToMintCollection } from '@/resources/reservoir/mints'; +import { EthCoinIcon } from '@/components/coin-icon/EthCoinIcon'; export const NUM_NFTS = 3; @@ -59,7 +59,7 @@ export function Card({ collection }: { collection: MintableCollection }) { {network !== Network.mainnet ? ( <ChainBadge network={network} position="relative" size="medium" /> ) : ( - <CoinIcon size={20} network={network} /> + <EthCoinIcon size={20} /> )} </Bleed> </Cover> diff --git a/src/screens/NFTOffersSheet/OfferRow.tsx b/src/screens/NFTOffersSheet/OfferRow.tsx index 6f0a2ae6382..9c29c3ac80b 100644 --- a/src/screens/NFTOffersSheet/OfferRow.tsx +++ b/src/screens/NFTOffersSheet/OfferRow.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { useNavigation } from '@/navigation'; import { Bleed, Box, Column, Columns, globalColors, Inline, Inset, Stack, Text, useBackgroundColor, useColorMode } from '@/design-system'; -import { CoinIcon } from '@/components/coin-icon'; import MaskedView from '@react-native-masked-view/masked-view'; import { NftOffer } from '@/graphql/__generated__/arc'; import { ImgixImage } from '@/components/images'; @@ -14,6 +13,10 @@ import { useTheme } from '@/theme'; import { CardSize } from '@/components/unique-token/CardSize'; import { View } from 'react-native'; import Svg, { Path } from 'react-native-svg'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; +import { Network } from '@/networks/types'; +import { useAccountSettings } from '@/hooks'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; const NFT_SIZE = 50; const MARKETPLACE_ORB_SIZE = 18; @@ -90,8 +93,15 @@ export const FakeOfferRow = () => { export const OfferRow = ({ offer }: { offer: NftOffer }) => { const { navigate } = useNavigation(); + const { nativeCurrency } = useAccountSettings(); const { colorMode } = useColorMode(); + const theme = useTheme(); const bgColor = useBackgroundColor('surfaceSecondaryElevated'); + const { data: externalAsset } = useExternalToken({ + address: offer.paymentToken.address, + network: offer.network as Network, + currency: nativeCurrency, + }); const isFloorDiffPercentagePositive = offer.floorDifferencePercentage >= 0; const dollarAmount = convertAmountToNativeDisplay( @@ -200,11 +210,13 @@ export const OfferRow = ({ offer }: { offer: NftOffer }) => { <View style={{ alignItems: 'flex-end' }}> <View style={{ flexDirection: 'row', paddingBottom: 10 }}> <View style={{ marginVertical: -2, paddingRight: 6 }}> - <CoinIcon - address={offer.paymentToken.address} + <RainbowCoinIcon size={COIN_ICON_SIZE} + icon={externalAsset?.icon_url} + network={offer?.network as Network} symbol={offer.paymentToken.symbol} - network={offer.network} + theme={theme} + colors={externalAsset?.colors} ignoreBadge /> </View> diff --git a/src/screens/NFTSingleOfferSheet/index.tsx b/src/screens/NFTSingleOfferSheet/index.tsx index 6fbf4e229bc..c477c00b08e 100644 --- a/src/screens/NFTSingleOfferSheet/index.tsx +++ b/src/screens/NFTSingleOfferSheet/index.tsx @@ -20,7 +20,6 @@ import { ImgixImage } from '@/components/images'; import { getFormattedTimeQuantity, convertAmountToNativeDisplay, handleSignificantDecimals } from '@/helpers/utilities'; import * as i18n from '@/languages'; import { NftOffer } from '@/graphql/__generated__/arc'; -import { CoinIcon } from '@/components/coin-icon'; import { ButtonPressAnimation } from '@/components/animations'; import { useNavigation } from '@/navigation'; import { IS_ANDROID } from '@/env'; @@ -48,6 +47,8 @@ import { CardSize } from '@/components/unique-token/CardSize'; import { queryClient } from '@/react-query'; import { nftOffersQueryKey } from '@/resources/reservoir/nftOffersQuery'; import { getRainbowFeeAddress } from '@/resources/reservoir/utils'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; const NFT_IMAGE_HEIGHT = 160; const TWO_HOURS_MS = 2 * 60 * 60 * 1000; @@ -80,9 +81,9 @@ function Row({ symbol, label, value }: { symbol: string; label: string; value: R export function NFTSingleOfferSheet() { const { params } = useRoute(); const { navigate, setParams } = useNavigation(); - const { accountAddress } = useAccountSettings(); + const { accountAddress, nativeCurrency } = useAccountSettings(); const { isReadOnlyWallet } = useWallets(); - const { isDarkMode } = useTheme(); + const theme = useTheme(); const { updateTxFee, startPollingGasFees, stopPollingGasFees, isSufficientGas, isValidGas } = useGas(); const dispatch = useDispatch(); const { @@ -91,6 +92,12 @@ export function NFTSingleOfferSheet() { const { offer } = params as { offer: NftOffer }; + const { data: externalAsset } = useExternalToken({ + address: offer.paymentToken.address, + network: offer.network as Network, + currency: nativeCurrency, + }); + const [height, setHeight] = useState(0); const didErrorRef = useRef<boolean>(false); const didCompleteRef = useRef<boolean>(false); @@ -447,8 +454,15 @@ export function NFTSingleOfferSheet() { </Column> <Column> <Inline space="4px" alignVertical="center" alignHorizontal="right"> - <CoinIcon address={offer.paymentToken.address} size={16} symbol={offer.paymentToken.symbol} network={offer.network} /> - + <RainbowCoinIcon + size={16} + icon={externalAsset?.icon_url} + network={offer?.network as Network} + symbol={offer.paymentToken.symbol} + theme={theme} + colors={externalAsset?.colors} + ignoreBadge + /> <Text color="label" align="right" size="17pt" weight="bold"> {listPrice} {offer.paymentToken.symbol} </Text> @@ -478,11 +492,14 @@ export function NFTSingleOfferSheet() { label={i18n.t(i18n.l.nft_offers.single_offer_sheet.floor_price)} value={ <Inline space="4px" alignVertical="center" alignHorizontal="right"> - <CoinIcon - address={offer.floorPrice.paymentToken.address} + <RainbowCoinIcon size={16} - symbol={offer.floorPrice.paymentToken.symbol} - network={offer.network} + icon={externalAsset?.icon_url} + network={offer?.network as Network} + symbol={offer.paymentToken.symbol} + theme={theme} + colors={externalAsset?.colors} + ignoreBadge /> <Text color="labelSecondary" align="right" size="17pt" weight="medium"> @@ -563,8 +580,15 @@ export function NFTSingleOfferSheet() { </Column> <Column> <Inline space="4px" alignVertical="center" alignHorizontal="right"> - <CoinIcon address={offer.paymentToken.address} size={16} symbol={offer.paymentToken.symbol} network={offer.network} /> - + <RainbowCoinIcon + size={16} + icon={externalAsset?.icon_url} + network={offer?.network as Network} + symbol={offer.paymentToken.symbol} + theme={theme} + colors={externalAsset?.colors} + ignoreBadge + /> <Text color="label" align="right" size="17pt" weight="bold"> {netCrypto} {offer.paymentToken.symbol} </Text> @@ -643,7 +667,7 @@ export function NFTSingleOfferSheet() { }} horizontalPadding={0} currentNetwork={offer.network} - theme={isDarkMode ? 'dark' : 'light'} + theme={theme.isDarkMode ? 'dark' : 'light'} /> </> )} diff --git a/src/screens/SendConfirmationSheet.tsx b/src/screens/SendConfirmationSheet.tsx index fcb585643d1..bf00ee0ceb1 100644 --- a/src/screens/SendConfirmationSheet.tsx +++ b/src/screens/SendConfirmationSheet.tsx @@ -14,7 +14,6 @@ import Pill from '../components/Pill'; import TouchableBackdrop from '../components/TouchableBackdrop'; import ButtonPressAnimation from '../components/animations/ButtonPressAnimation'; import Callout from '../components/callout/Callout'; -import { CoinIcon } from '../components/coin-icon'; import RequestVendorLogoIcon from '../components/coin-icon/RequestVendorLogoIcon'; import { ContactAvatar } from '../components/contacts'; import ImageAvatar from '../components/contacts/ImageAvatar'; @@ -60,6 +59,7 @@ import { useTheme } from '@/theme'; import { ethereumUtils, getUniqueTokenType, promiseUtils } from '@/utils'; import logger from '@/utils/logger'; import { getNetworkObj } from '@/networks'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; const Container = styled(Centered).attrs({ direction: 'column', @@ -179,7 +179,7 @@ const ChevronDown = () => { }; export const SendConfirmationSheet = () => { - const { colors, isDarkMode } = useTheme(); + const theme = useTheme(); const { accountAddress, nativeCurrency } = useAccountSettings(); const { goBack, navigate, setParams } = useNavigation(); const { height: deviceHeight, isSmallPhone, isTinyPhone, width: deviceWidth } = useDimensions(); @@ -353,7 +353,7 @@ export const SendConfirmationSheet = () => { let color = useColorForAsset(asset); if (isNft) { - color = colors.appleBlue; + color = theme.colors.appleBlue; } const shouldShowChecks = isL2 && !isSendingToUserAccount && alreadySentTransactionsCurrentNetwork < 3; @@ -463,7 +463,7 @@ export const SendConfirmationSheet = () => { <Row marginTop={12}> <Text color={{ - custom: isNft ? colors.alpha(colors.blueGreyDark, 0.6) : color, + custom: isNft ? theme.colors.alpha(theme.colors.blueGreyDark, 0.6) : color, }} size="16px / 22px (Deprecated)" weight={isNft ? 'bold' : 'heavy'} @@ -477,7 +477,7 @@ export const SendConfirmationSheet = () => { {isNft ? ( // @ts-expect-error JavaScript component <RequestVendorLogoIcon - backgroundColor={asset.background || colors.lightestGrey} + backgroundColor={asset.background || theme.colors.lightestGrey} badgeXPosition={-7} badgeYPosition={0} borderRadius={10} @@ -487,8 +487,14 @@ export const SendConfirmationSheet = () => { size={50} /> ) : ( - // eslint-disable-next-line react/jsx-props-no-spreading - <CoinIcon size={50} {...asset} /> + <RainbowCoinIcon + size={50} + icon={asset?.icon_url} + network={asset?.network} + symbol={asset?.symbol || ''} + theme={theme} + colors={asset?.colors} + /> )} </Row> </Column> @@ -499,7 +505,7 @@ export const SendConfirmationSheet = () => { <Pill borderRadius={15} height={30} minWidth={39} paddingHorizontal={10} paddingVertical={5.5}> <OldText align="center" - color={colors.blueGreyDark60} + color={theme.colors.blueGreyDark60} letterSpacing="roundedMedium" lineHeight={20} size="large" @@ -530,7 +536,7 @@ export const SendConfirmationSheet = () => { > <Text color={{ - custom: colors.alpha(colors.blueGreyDark, isDarkMode ? 0.5 : 0.6), + custom: theme.colors.alpha(theme.colors.blueGreyDark, theme.isDarkMode ? 0.5 : 0.6), }} size="20px / 24px (Deprecated)" weight="heavy" @@ -541,7 +547,11 @@ export const SendConfirmationSheet = () => { </Centered> </Row> <Row marginTop={12}> - <Text color={{ custom: colors.alpha(colors.blueGreyDark, 0.6) }} size="16px / 22px (Deprecated)" weight="bold"> + <Text + color={{ custom: theme.colors.alpha(theme.colors.blueGreyDark, 0.6) }} + size="16px / 22px (Deprecated)" + weight="bold" + > {getMessage()} </Text> </Row> @@ -555,7 +565,7 @@ export const SendConfirmationSheet = () => { </Column> </Row> {/* @ts-expect-error JavaScript component */} - <Divider color={colors.rowDividerExtraLight} inset={[0]} /> + <Divider color={theme.colors.rowDividerExtraLight} inset={[0]} /> </Column> {(isL2 || isENS || shouldShowChecks) && ( <Inset bottom="30px (Deprecated)" horizontal="19px (Deprecated)"> @@ -565,7 +575,7 @@ export const SendConfirmationSheet = () => { {/* @ts-expect-error JavaScript component */} <L2Disclaimer network={asset.network} - colors={colors} + colors={theme.colors} hideDivider marginBottom={0} marginHorizontal={0} diff --git a/src/screens/SettingsSheet/components/CurrencySection.android.tsx b/src/screens/SettingsSheet/components/CurrencySection.android.tsx index 4f9e31037c5..a3a4a761427 100644 --- a/src/screens/SettingsSheet/components/CurrencySection.android.tsx +++ b/src/screens/SettingsSheet/components/CurrencySection.android.tsx @@ -1,18 +1,19 @@ import React, { useCallback } from 'react'; -import { Platform } from 'react-native'; +import { Platform, View } from 'react-native'; import { reloadTimelines } from 'react-native-widgetkit'; -import { CoinIcon } from '../../../components/coin-icon'; import Menu from './Menu'; import MenuContainer from './MenuContainer'; import MenuItem from './MenuItem'; import { analytics } from '@/analytics'; import { useAccountSettings } from '@/hooks'; -import { emojis, supportedNativeCurrencies } from '@/references'; +import { ETH_ADDRESS, WBTC_ADDRESS, emojis, supportedNativeCurrencies } from '@/references'; import { BackgroundProvider, Box, Inline, Inset, Text } from '@/design-system'; -import { useNavigation } from '@/navigation'; import { SimpleSheet } from '@/components/sheet/SimpleSheet'; import * as i18n from '@/languages'; import { Network } from '@/networks/types'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; +import { useTheme } from '@/theme'; const emojiData = Object.entries(emojis).map(([emoji, { name }]) => [name, emoji]); @@ -25,7 +26,9 @@ const currencyListItems = Object.values(supportedNativeCurrencies).map(({ curren const CurrencySection = () => { const { nativeCurrency, settingsChangeNativeCurrency } = useAccountSettings(); - const { goBack } = useNavigation(); + const theme = useTheme(); + const { data: WBTC } = useExternalToken({ address: WBTC_ADDRESS, network: Network.mainnet, currency: nativeCurrency }); + const { data: ETH } = useExternalToken({ address: ETH_ADDRESS, network: Network.mainnet, currency: nativeCurrency }); const onSelectCurrency = useCallback( (currency: any) => { @@ -60,7 +63,15 @@ const CurrencySection = () => { emojiName ? ( <MenuItem.TextIcon icon={(emoji.get('flag_' + emojiName) as string) || ''} isEmoji /> ) : ( - <CoinIcon address={currency} size={23} style={{ marginLeft: 7 }} symbol={currency} network={Network.mainnet} /> + <View style={{ marginLeft: 7 }}> + <RainbowCoinIcon + icon={currency === ETH?.symbol ? ETH?.icon_url : WBTC?.icon_url} + size={23} + symbol={currency} + network={Network.mainnet} + theme={theme} + /> + </View> ) } onPress={() => onSelectCurrency(currency)} diff --git a/src/screens/SignTransactionSheet.tsx b/src/screens/SignTransactionSheet.tsx index 0430875a368..aaae931e088 100644 --- a/src/screens/SignTransactionSheet.tsx +++ b/src/screens/SignTransactionSheet.tsx @@ -23,7 +23,6 @@ import Animated, { import { Transaction } from '@ethersproject/transactions'; import { ButtonPressAnimation } from '@/components/animations'; -import { CoinIcon } from '@/components/coin-icon'; import { ChainImage } from '@/components/coin-icon/ChainImage'; import { SheetActionButton } from '@/components/sheet'; import { Bleed, Box, Columns, Inline, Inset, Stack, Text, globalColors, useBackgroundColor, useForegroundColor } from '@/design-system'; @@ -95,6 +94,8 @@ import { methodRegistryLookupAndParse } from '@/utils/methodRegistry'; import { sanitizeTypedData } from '@/utils/signingUtils'; import { hexToNumber, isHex } from 'viem'; import { getNextNonce } from '@/state/nonces'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; const COLLAPSED_CARD_HEIGHT = 56; const MAX_CARD_HEIGHT = 176; @@ -1549,7 +1550,13 @@ const SimulatedEventRow = ({ eventType: EventType; price?: number | undefined; }) => { - const { colors } = useTheme(); + const theme = useTheme(); + const { nativeCurrency } = useAccountSettings(); + const { data: externalAsset } = useExternalToken({ + address: asset?.assetCode || '', + network: (asset?.network as Network) || Network.mainnet, + currency: nativeCurrency, + }); const eventInfo: EventInfo = infoForEventType[eventType]; @@ -1604,13 +1611,14 @@ const SimulatedEventRow = ({ <Inline alignVertical="center" space={{ custom: 7 }} wrap={false}> <Bleed vertical="6px"> {asset?.type !== TransactionAssetType.Nft ? ( - <CoinIcon - address={assetCode} - symbol={asset?.symbol} + <RainbowCoinIcon size={16} - network={asset?.network || Network.mainnet} - forcedShadowColor={colors.transparent} - ignoreBadge={true} + icon={externalAsset?.icon_url} + network={(asset?.network as Network) || Network.mainnet} + symbol={externalAsset?.symbol || ''} + theme={theme} + colors={externalAsset?.colors} + ignoreBadge /> ) : ( <Image source={{ uri: url }} style={{ borderRadius: 4.5, height: 16, width: 16 }} /> diff --git a/src/screens/WalletConnectApprovalSheet.js b/src/screens/WalletConnectApprovalSheet.js index 91d2acb5bb8..0d3ddb470ee 100644 --- a/src/screens/WalletConnectApprovalSheet.js +++ b/src/screens/WalletConnectApprovalSheet.js @@ -31,6 +31,7 @@ import { IS_IOS } from '@/env'; import { useDappMetadata } from '@/resources/metadata/dapp'; import { DAppStatus } from '@/graphql/__generated__/metadata'; import { InfoAlert } from '@/components/info-alert/info-alert'; +import { EthCoinIcon } from '@/components/coin-icon/EthCoinIcon'; const LoadingSpinner = styled(android ? Spinner : ActivityIndicator).attrs(({ theme: { colors } }) => ({ color: colors.alpha(colors.blueGreyDark, 0.3), @@ -124,7 +125,7 @@ const NetworkPill = ({ chainIds }) => { {network !== Network.mainnet ? ( <ChainBadge network={network} position="relative" size="small" /> ) : ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} network={network} /> + <EthCoinIcon size={20} /> )} </Box> ); @@ -135,7 +136,7 @@ const NetworkPill = ({ chainIds }) => { {availableNetworks[0] !== Network.mainnet ? ( <ChainBadge network={availableNetworks[0]} position="relative" size="small" /> ) : ( - <CoinIcon address={ETH_ADDRESS} size={20} symbol={ETH_SYMBOL} type={availableNetworks[0]} /> + <EthCoinIcon size={20} /> )} <Box paddingLeft="6px"> diff --git a/src/screens/mints/MintSheet.tsx b/src/screens/mints/MintSheet.tsx index a43eddeedda..7c68268a50c 100644 --- a/src/screens/mints/MintSheet.tsx +++ b/src/screens/mints/MintSheet.tsx @@ -54,6 +54,7 @@ import { QuantityButton } from './components/QuantityButton'; import { estimateGas, getProviderForNetwork } from '@/handlers/web3'; import { getRainbowFeeAddress } from '@/resources/reservoir/utils'; import { IS_ANDROID, IS_IOS } from '@/env'; +import { EthCoinIcon } from '@/components/coin-icon/EthCoinIcon'; const NFT_IMAGE_HEIGHT = 250; // inset * 2 -> 28 *2 @@ -665,14 +666,7 @@ const MintSheet = () => { <Inset vertical={{ custom: -4 }}> <Inline space="4px" alignVertical="center" alignHorizontal="right"> {currentNetwork === Network.mainnet ? ( - <CoinIcon - address={ETH_ADDRESS} - size={16} - symbol={ETH_SYMBOL} - forceFallback={undefined} - shadowColor={undefined} - style={undefined} - /> + <EthCoinIcon size={16} /> ) : ( <ChainBadge network={currentNetwork} position="relative" size="small" forceDark={true} /> )} diff --git a/src/screens/positions/SubPositionListItem.tsx b/src/screens/positions/SubPositionListItem.tsx index 2f58e7364fb..8ab85b77a7c 100644 --- a/src/screens/positions/SubPositionListItem.tsx +++ b/src/screens/positions/SubPositionListItem.tsx @@ -1,14 +1,15 @@ import React from 'react'; import { Bleed, Box, Column, Columns, Inline, Stack, Text } from '@/design-system'; import { useTheme } from '@/theme'; -import { CoinIcon } from '@/components/coin-icon'; import { convertAmountToPercentageDisplay, convertAmountToPercentageDisplayWithThreshold, convertRawAmountToRoundedDecimal, } from '@/helpers/utilities'; import { NativeDisplay, PositionAsset } from '@/resources/defi/types'; -import ethereumUtils from '@/utils/ethereumUtils'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; +import { useAccountSettings } from '@/hooks'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; type Props = { asset: PositionAsset; @@ -19,14 +20,22 @@ type Props = { }; export const SubPositionListItem: React.FC<Props> = ({ asset, apy, quantity, native, positionColor }) => { - const { colors } = useTheme(); + const theme = useTheme(); + const { nativeCurrency } = useAccountSettings(); + const { data: externalAsset } = useExternalToken({ address: asset.asset_code, network: asset.network, currency: nativeCurrency }); - const priceChangeColor = (asset.price?.relative_change_24h || 0) < 0 ? colors.blueGreyDark60 : colors.green; + const priceChangeColor = (asset.price?.relative_change_24h || 0) < 0 ? theme.colors.blueGreyDark60 : theme.colors.green; return ( <Columns space={'10px'}> <Column width={'content'}> - <CoinIcon address={asset.asset_code} network={asset.network} symbol={asset.symbol} /> + <RainbowCoinIcon + icon={externalAsset?.icon_url} + network={asset.network} + symbol={asset.symbol} + theme={theme} + colors={externalAsset?.colors} + /> </Column> <Box justifyContent="center" style={{ height: 40 }}> <Stack space="10px"> @@ -57,7 +66,7 @@ export const SubPositionListItem: React.FC<Props> = ({ asset, apy, quantity, nat <Bleed vertical={{ custom: 3 }}> <Box style={{ - backgroundColor: colors.alpha(positionColor, 0.08), + backgroundColor: theme.colors.alpha(positionColor, 0.08), borderRadius: 7, height: 18, }} diff --git a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx index fadda13516c..a399ae42a89 100644 --- a/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx +++ b/src/screens/transaction-details/components/TransactionDetailsValueAndFeeSection.tsx @@ -2,17 +2,15 @@ import React from 'react'; import { DoubleLineTransactionDetailsRow } from '@/screens/transaction-details/components/DoubleLineTransactionDetailsRow'; import { TransactionDetailsSymbol } from '@/screens/transaction-details/components/TransactionDetailsSymbol'; import { RainbowTransaction, RainbowTransactionFee } from '@/entities/transactions/transaction'; -import { CoinIcon } from '@/components/coin-icon'; import { Box, Stack } from '@/design-system'; import { TransactionDetailsDivider } from '@/screens/transaction-details/components/TransactionDetailsDivider'; import * as i18n from '@/languages'; -import { TransactionType } from '@/entities'; -import { ethereumUtils } from '@/utils'; + import { Network } from '@/networks/types'; import { useUserAsset } from '@/resources/assets/useUserAsset'; import { getUniqueId } from '@/utils/ethereumUtils'; -import FastCoinIcon from '@/components/asset-list/RecyclerAssetList2/FastComponents/FastCoinIcon'; import { useTheme } from '@/theme'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; type Props = { transaction: RainbowTransaction; @@ -23,17 +21,10 @@ type Props = { export const TransactionDetailsValueAndFeeSection: React.FC<Props> = ({ transaction }) => { const theme = useTheme(); - const { network, symbol, type, fee } = transaction; + const { network, fee } = transaction; const assetUniqueId = getUniqueId(transaction?.address || '', transaction?.network || Network.mainnet); const { data: assetData } = useUserAsset(assetUniqueId); - const coinAddress = assetData?.address || transaction?.address || ''; - const mainnetCoinAddress = assetData?.mainnet_address; - const coinSymbol = - type === TransactionType.contract_interaction - ? ethereumUtils.getNetworkNativeAsset(network ?? Network.mainnet)?.symbol - : assetData?.symbol ?? symbol ?? undefined; - const value = transaction.balance?.display; const nativeCurrencyValue = transaction.native?.display; @@ -52,12 +43,13 @@ export const TransactionDetailsValueAndFeeSection: React.FC<Props> = ({ transact {value && ( <DoubleLineTransactionDetailsRow leftComponent={ - <FastCoinIcon - mainnetAddress={mainnetCoinAddress} - address={coinAddress} - symbol={coinSymbol || ''} - network={network || Network.mainnet} + <RainbowCoinIcon + size={40} + icon={assetData?.icon_url} + network={network || assetData?.network || Network.mainnet} + symbol={assetData?.symbol || ''} theme={theme} + colors={assetData?.colors} /> } title={i18n.t(i18n.l.transaction_details.value)} From f4a6dd06527340888b251ea670630e0b46877886 Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 23 Feb 2024 12:47:45 -0500 Subject: [PATCH 06/12] clean --- .../coin-row/FastTransactionCoinRow.tsx | 2 +- src/components/images/FastImgixImage.tsx | 96 ------------------- .../images/ImageWithCachedMetadata.js | 7 +- 3 files changed, 4 insertions(+), 101 deletions(-) delete mode 100644 src/components/images/FastImgixImage.tsx diff --git a/src/components/coin-row/FastTransactionCoinRow.tsx b/src/components/coin-row/FastTransactionCoinRow.tsx index 0b5fe53a69c..e9866f780d7 100644 --- a/src/components/coin-row/FastTransactionCoinRow.tsx +++ b/src/components/coin-row/FastTransactionCoinRow.tsx @@ -1,5 +1,5 @@ import React, { useCallback } from 'react'; -import { StyleSheet, View, View } from 'react-native'; +import { StyleSheet, View } from 'react-native'; import { ButtonPressAnimation } from '../animations'; import FastTransactionStatusBadge from './FastTransactionStatusBadge'; import { Bleed, Box, Inline, Text, globalColors, useForegroundColor } from '@/design-system'; diff --git a/src/components/images/FastImgixImage.tsx b/src/components/images/FastImgixImage.tsx deleted file mode 100644 index e44dcfaa47f..00000000000 --- a/src/components/images/FastImgixImage.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import * as React from 'react'; -import FastImage, { FastImageProps, Source } from 'react-native-fast-image'; - -import { maybeSignSource } from '../../handlers/imgix'; - -export type ImgixImageProps = FastImageProps & { - readonly Component?: React.ElementType; - readonly size: number; -}; - -// Here we're emulating the pattern used in react-native-fast-image: -// https://github.com/DylanVann/react-native-fast-image/blob/0439f7190f141e51a391c84890cdd8a7067c6ad3/src/index.tsx#L146 -type HiddenImgixImageProps = { - forwardedRef?: React.Ref<any>; - maxRetries?: number; - retryOnError?: boolean; - size: number; - fm?: string; -}; -type MergedImgixImageProps = ImgixImageProps & HiddenImgixImageProps; - -// ImgixImage must be a class Component to support Animated.createAnimatedComponent. -class ImgixImage extends React.PureComponent<MergedImgixImageProps, ImgixImageProps & { retryCount: number }> { - static getDerivedStateFromProps(props: MergedImgixImageProps) { - const { source, size, fm } = props; - const options = { - ...(fm && { fm: fm }), - ...(size && { - h: size, - w: size, - }), - }; - - return { - retryCount: 0, - source: !!source && typeof source === 'object' ? maybeSignSource(source, options) : source, - }; - } - - handleError = (err: any) => { - const { onError, retryOnError, maxRetries = 5 } = this.props; - const { retryCount } = this.state; - // We don't want to retry if there is a 404. - const isNotFound = err?.nativeEvent?.statusCode === 404 || err?.nativeEvent?.message?.includes('404'); - const shouldRetry = retryOnError && !isNotFound; - - if (shouldRetry && retryCount < maxRetries) { - this.setState(({ retryCount }) => ({ retryCount: retryCount + 1 })); - } else { - // @ts-expect-error - onError?.(err); - } - }; - - render() { - const { Component: maybeComponent, ...props } = this.props; - // Use the local state as the signing source, as opposed to the prop directly. - // (The source prop may point to an untrusted URL.) - const { retryCount, source } = this.state; - const Component = maybeComponent || FastImage; - return <Component {...props} key={`${JSON.stringify(source)}-${retryCount}`} onError={this.handleError} source={source} />; - } -} - -const preload = (sources: Source[], size?: number, fm?: string): void => { - if (sources.length) { - const options = { - ...(fm && { fm: fm }), - ...(size && { - h: size, - w: size, - }), - }; - return FastImage.preload(sources.map(source => maybeSignSource(source, options))); - } - return; -}; - -const getCachePath = (source: Source) => FastImage.getCachePath(maybeSignSource(source)); - -const ImgixImageWithForwardRef = React.forwardRef((props: ImgixImageProps, ref: React.Ref<any>) => ( - <ImgixImage forwardedRef={ref} {...props} /> -)); - -const { cacheControl, clearDiskCache, clearMemoryCache, contextTypes, priority, resizeMode } = FastImage; - -export default Object.assign(ImgixImageWithForwardRef, { - cacheControl, - clearDiskCache, - clearMemoryCache, - getCachePath, - contextTypes, - preload, - priority, - resizeMode, -}); diff --git a/src/components/images/ImageWithCachedMetadata.js b/src/components/images/ImageWithCachedMetadata.js index 6d7a215ecef..a3908718cb8 100644 --- a/src/components/images/ImageWithCachedMetadata.js +++ b/src/components/images/ImageWithCachedMetadata.js @@ -1,9 +1,8 @@ import React, { useCallback, useMemo } from 'react'; -import ImgixImage from './ImgixImage'; import { useImageMetadata } from '@/hooks'; -import FastImgixImage from './FastImgixImage'; +import FastImage from 'react-native-fast-image'; -const ImageWithCachedMetadata = ({ cache = ImgixImage.cacheControl.web, imageUrl, onLoad, ...props }, ref) => { +const ImageWithCachedMetadata = ({ cache = FastImage.cacheControl.web, imageUrl, onLoad, ...props }, ref) => { const { onCacheImageMetadata } = useImageMetadata(imageUrl); const source = useMemo(() => ({ cache, uri: imageUrl }), [cache, imageUrl]); @@ -18,7 +17,7 @@ const ImageWithCachedMetadata = ({ cache = ImgixImage.cacheControl.web, imageUrl [onCacheImageMetadata, onLoad] ); - return <FastImgixImage {...props} onLoad={handleLoad} ref={ref} source={source} />; + return <FastImage {...props} onLoad={handleLoad} ref={ref} source={source} />; }; export default React.forwardRef(ImageWithCachedMetadata); From 87b65f3226c733f8501babcc15c962165eec56f0 Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 23 Feb 2024 12:58:49 -0500 Subject: [PATCH 07/12] add rainbowcoinicon --- src/components/coin-icon/TwoCoinsIcon.tsx | 27 ++++++++++------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/components/coin-icon/TwoCoinsIcon.tsx b/src/components/coin-icon/TwoCoinsIcon.tsx index 7a46c126afd..4e561cc3e27 100644 --- a/src/components/coin-icon/TwoCoinsIcon.tsx +++ b/src/components/coin-icon/TwoCoinsIcon.tsx @@ -4,6 +4,7 @@ import { ParsedAddressAsset } from '@/entities'; import { useTheme } from '@/theme'; import { ImgixImage } from '@/components/images'; import ChainBadge from './ChainBadge'; +import RainbowCoinIcon from './RainbowCoinIcon'; export function TwoCoinsIcon({ size = 45, @@ -40,24 +41,20 @@ export function TwoCoinsIcon({ left: -0, }} > - <ImgixImage - source={{ uri: under?.icon_url }} - style={{ borderRadius: 100, width: underSize, height: underSize }} + <RainbowCoinIcon + icon={under?.icon_url} + theme={theme} size={underSize} + network={under.network} + symbol={under.symbol} + ignoreBadge /> </Box> - <Box borderRadius={100} style={{ zIndex: 10, position: 'absolute', top: 0, right: 0 }}> - <ImgixImage - source={{ uri: over?.icon_url }} - style={{ - borderRadius: 100, - width: overSize, - height: overSize, - borderWidth: 2, - borderColor: theme.colors.white, - }} - size={overSize} - /> + <Box + borderRadius={100} + style={{ zIndex: 10, position: 'absolute', top: 0, right: 0, borderRadius: 99, borderColor: theme.colors.white, borderWidth: 2 }} + > + <RainbowCoinIcon icon={over?.icon_url} theme={theme} size={overSize} network={over.network} symbol={over.symbol} ignoreBadge /> </Box> {badge && <ChainBadge network={over.network} badgeYPosition={9} badgeXPosition={-7.5} />} </Box> From 2df08ea6f3b5035088b5b0455fccda891d877f1c Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 23 Feb 2024 13:00:31 -0500 Subject: [PATCH 08/12] oops --- src/hooks/useAccountTransactions.ts | 1 - src/resources/transactions/transaction.ts | 1 - src/screens/ExchangeModal.tsx | 1 - src/screens/SpeedUpAndCancelSheet.js | 1 - 4 files changed, 4 deletions(-) diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index 5f45243fc83..e6f20251613 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -140,7 +140,6 @@ export default function useAccountTransactions() { const { sections } = buildTransactionsSections(accountState); const remainingItemsLabel = useMemo(() => { - console.log({ hasNextPage }); if (!hasNextPage) { return null; } diff --git a/src/resources/transactions/transaction.ts b/src/resources/transactions/transaction.ts index 13cbfb07d19..21c4e33b54a 100644 --- a/src/resources/transactions/transaction.ts +++ b/src/resources/transactions/transaction.ts @@ -106,7 +106,6 @@ export function useBackendTransaction({ hash, network }: BackendTransactionArgs) if (tx) { return tx; } - console.log('fuck'); return {}; } }, diff --git a/src/screens/ExchangeModal.tsx b/src/screens/ExchangeModal.tsx index 5a762b473e0..faecd452b7b 100644 --- a/src/screens/ExchangeModal.tsx +++ b/src/screens/ExchangeModal.tsx @@ -770,7 +770,6 @@ export default function ExchangeModal({ fromDiscover, ignoreInitialTypeCheck, te return navigateToSwapDetailsModal(); }, [loading, navigateToSwapDetailsModal]); - console.log({ outputCurrency }); return ( <Wrapper keyboardType={KeyboardType.numpad}> <Box height="full" width="full"> diff --git a/src/screens/SpeedUpAndCancelSheet.js b/src/screens/SpeedUpAndCancelSheet.js index 3f3bd9bcf3e..312db8e5652 100644 --- a/src/screens/SpeedUpAndCancelSheet.js +++ b/src/screens/SpeedUpAndCancelSheet.js @@ -172,7 +172,6 @@ export default function SpeedUpAndCancelSheet() { updatedTx.hash = res.result?.hash; updatedTx.status = 'pending'; updatedTx.type = 'cancel'; - console.log({ before: tx.nonce, after: updatedTx.nonce, hash: updatedTx.hash }); updateTransaction({ address: accountAddress, transaction: updatedTx, network: currentNetwork }); } catch (e) { logger.log('Error submitting cancel tx', e); From 79ab58828d7b20a661ca767d0d41226ca62cdbf7 Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 23 Feb 2024 13:06:45 -0500 Subject: [PATCH 09/12] rm some unused shiz from txs --- src/hooks/useAccountTransactions.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/hooks/useAccountTransactions.ts b/src/hooks/useAccountTransactions.ts index e6f20251613..1e7a3745c0a 100644 --- a/src/hooks/useAccountTransactions.ts +++ b/src/hooks/useAccountTransactions.ts @@ -5,8 +5,6 @@ import useContacts from './useContacts'; import useRequests from './useRequests'; import { useNavigation } from '@/navigation'; import { useTheme } from '@/theme'; -import { getCachedProviderForNetwork, isHardHat } from '@/handlers/web3'; -import { useUserAssets } from '@/resources/assets/UserAssetsQuery'; import { useConsolidatedTransactions } from '@/resources/transactions/consolidatedTransactions'; import { RainbowTransaction } from '@/entities'; import { pendingTransactionsStore, usePendingTransactionsStore } from '@/state/pendingTransactions'; @@ -17,15 +15,7 @@ import { nonceStore } from '@/state/nonces'; export const NOE_PAGE = 30; export default function useAccountTransactions() { - const { network: currentNetwork, accountAddress, nativeCurrency } = useAccountSettings(); - const provider = getCachedProviderForNetwork(currentNetwork); - const providerUrl = provider?.connection?.url; - const connectedToHardhat = isHardHat(providerUrl); - const { data: userAssets } = useUserAssets({ - address: accountAddress, - currency: nativeCurrency, - connectedToHardhat, - }); + const { accountAddress, nativeCurrency } = useAccountSettings(); const { pendingTransactions: storePendingTransactions } = usePendingTransactionsStore(); From b10699ad93614028f4c2ab97239a717fce137521 Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 23 Feb 2024 13:29:35 -0500 Subject: [PATCH 10/12] rm legacy transaction sheet things --- .../transaction/TransactionMessage.js | 58 - src/components/transaction/TransactionRow.js | 25 - .../transaction/TransactionSheet.js | 12 - src/components/transaction/index.js | 6 - src/screens/TransactionConfirmationScreen.js | 1008 ----------------- 5 files changed, 1109 deletions(-) delete mode 100644 src/components/transaction/TransactionMessage.js delete mode 100644 src/components/transaction/TransactionRow.js delete mode 100644 src/components/transaction/TransactionSheet.js delete mode 100644 src/components/transaction/index.js delete mode 100644 src/screens/TransactionConfirmationScreen.js diff --git a/src/components/transaction/TransactionMessage.js b/src/components/transaction/TransactionMessage.js deleted file mode 100644 index 7205ae22d68..00000000000 --- a/src/components/transaction/TransactionMessage.js +++ /dev/null @@ -1,58 +0,0 @@ -import { addHexPrefix } from '@walletconnect/legacy-utils'; -import React from 'react'; -import { ScrollView } from 'react-native-gesture-handler'; -import { isSignTypedData } from '../../utils/signingMethods'; -import { Row } from '../layout'; -import { Text } from '../text'; -import styled from '@/styled-thing'; -import { padding } from '@/styles'; -import { deviceUtils } from '@/utils'; -import { sanitizeTypedData } from '@/utils/signingUtils'; -import { RainbowError, logger } from '@/logger'; - -const deviceWidth = deviceUtils.dimensions.width; -const horizontalPadding = 24; - -const Container = styled(Row)({ - minHeight: ({ minHeight }) => minHeight, - overflow: 'visible', -}); - -const MessageWrapper = styled(ScrollView)({ - marginBottom: 14, -}); - -const TransactionMessage = ({ maxHeight = 150, message, method }) => { - const { colors } = useTheme(); - let msg = message; - let maximumHeight = maxHeight; - let minimumHeight = 150; - if (isSignTypedData(method)) { - maximumHeight = 200; - minimumHeight = 200; - try { - const parsedMessage = JSON.parse(message); - const sanitizedMessage = sanitizeTypedData(parsedMessage); - msg = sanitizedMessage; - // eslint-disable-next-line no-empty - } catch (e) { - logger.error( - new RainbowError('TransactionMessage: Error parsing message ', { - messageType: typeof message, - }) - ); - } - - msg = JSON.stringify(msg, null, 4); - } - - return ( - <Container maxHeight={maximumHeight} minHeight={minimumHeight}> - <Text color={colors.alpha(colors.blueGreyDark, 0.6)} size="lmedium" style={{ ...padding.object(12, 15) }}> - {msg} - </Text> - </Container> - ); -}; - -export default TransactionMessage; diff --git a/src/components/transaction/TransactionRow.js b/src/components/transaction/TransactionRow.js deleted file mode 100644 index 15c24e73b3b..00000000000 --- a/src/components/transaction/TransactionRow.js +++ /dev/null @@ -1,25 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import { ColumnWithMargins } from '../layout'; -import { Smallcaps } from '../text'; -import styled from '@/styled-thing'; -import { padding } from '@/styles'; - -const Container = styled(ColumnWithMargins).attrs({ - marginLeft: 5, - marginRight: 5, -})(padding.object(0, 19)); - -const TransactionRow = ({ children, title, ...props }) => ( - <Container {...props}> - {title && <Smallcaps>{title}</Smallcaps>} - {children} - </Container> -); - -TransactionRow.propTypes = { - children: PropTypes.node, - title: PropTypes.string.isRequired, -}; - -export default TransactionRow; diff --git a/src/components/transaction/TransactionSheet.js b/src/components/transaction/TransactionSheet.js deleted file mode 100644 index e22fd16609c..00000000000 --- a/src/components/transaction/TransactionSheet.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { Column } from '../layout'; - -const TransactionSheet = ({ children, ...props }) => { - return ( - <Column {...props} paddingHorizontal={30}> - {children} - </Column> - ); -}; - -export default TransactionSheet; diff --git a/src/components/transaction/index.js b/src/components/transaction/index.js deleted file mode 100644 index 2d3279305fa..00000000000 --- a/src/components/transaction/index.js +++ /dev/null @@ -1,6 +0,0 @@ -export { default as DefaultTransactionConfirmationSection } from './sections/DefaultTransactionConfirmationSection'; -export { default as MessageSigningSection } from './sections/MessageSigningSection'; -export { default as TransactionConfirmationSection } from './sections/TransactionConfirmationSection'; -export { default as TransactionMessage } from './TransactionMessage'; -export { default as TransactionRow } from './TransactionRow'; -export { default as TransactionSheet } from './TransactionSheet'; diff --git a/src/screens/TransactionConfirmationScreen.js b/src/screens/TransactionConfirmationScreen.js deleted file mode 100644 index fe231278044..00000000000 --- a/src/screens/TransactionConfirmationScreen.js +++ /dev/null @@ -1,1008 +0,0 @@ -import { useIsFocused, useRoute } from '@react-navigation/native'; -import BigNumber from 'bignumber.js'; -import lang from 'i18n-js'; -import * as i18n from '@/languages'; -import isEmpty from 'lodash/isEmpty'; -import isNil from 'lodash/isNil'; -import { IS_TESTING } from 'react-native-dotenv'; -import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { ActivityIndicator, InteractionManager } from 'react-native'; -import { isEmulatorSync } from 'react-native-device-info'; -import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; -import Animated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated'; -import { useDispatch, useSelector } from 'react-redux'; -import URL from 'url-parse'; -import Divider from '../components/Divider'; -import L2Disclaimer from '../components/L2Disclaimer'; -import Spinner from '../components/Spinner'; -import { RequestVendorLogoIcon } from '../components/coin-icon'; -import { ContactAvatar } from '../components/contacts'; -import ImageAvatar from '../components/contacts/ImageAvatar'; -import { GasSpeedButton } from '../components/gas'; -import { Centered, Column, Row, RowWithMargins } from '../components/layout'; -import { SheetActionButton, SheetActionButtonRow, SheetHandleFixedToTop, SheetKeyboardAnimation, SlackSheet } from '../components/sheet'; -import { DefaultTransactionConfirmationSection, MessageSigningSection, TransactionConfirmationSection } from '../components/transaction'; -import { FLASHBOTS_WC } from '../config/experimental'; -import useExperimentalFlag from '../config/experimentalHooks'; -import { lightModeThemeColors } from '../styles/colors'; -import { WrappedAlert as Alert } from '@/helpers/alert'; -import { analytics } from '@/analytics'; -import { Text } from '@/design-system'; -import { useRemoteConfig } from '@/model/remoteConfig'; -import { - estimateGas, - estimateGasWithPadding, - getFlashbotsProvider, - getProviderForNetwork, - isL2Network, - isTestnetNetwork, - toHex, -} from '@/handlers/web3'; -import { Network } from '@/helpers'; -import { getAccountProfileInfo } from '@/helpers/accountInfo'; -import { findWalletWithAccount } from '@/helpers/findWalletWithAccount'; -import { - useAccountSettings, - useCurrentNonce, - useDimensions, - useGas, - useKeyboardHeight, - useTransactionConfirmation, - useWalletBalances, - useWallets, -} from '@/hooks'; -import { loadWallet, sendTransaction, signPersonalMessage, signTransaction, signTypedDataMessage } from '@/model/wallet'; -import { useNavigation } from '@/navigation'; -import { parseGasParamsForTransaction } from '@/parsers'; -import { walletConnectRemovePendingRedirect } from '@/redux/walletconnect'; -import Routes from '@/navigation/routesNames'; -import styled from '@/styled-thing'; -import { padding } from '@/styles'; -import { - convertAmountToNativeDisplay, - convertHexToString, - delay, - fromWei, - greaterThan, - greaterThanOrEqualTo, - multiply, - omitFlatten, -} from '@/helpers/utilities'; -import { ethereumUtils, safeAreaInsetValues } from '@/utils'; -import { useNativeAssetForNetwork } from '@/utils/ethereumUtils'; -import { methodRegistryLookupAndParse } from '@/utils/methodRegistry'; -import { - isMessageDisplayType, - isSignTypedData, - isTransactionDisplayType, - PERSONAL_SIGN, - SEND_TRANSACTION, - SIGN, - SIGN_TYPED_DATA, - SIGN_TYPED_DATA_V4, -} from '@/utils/signingMethods'; -import { handleSessionRequestResponse } from '@/walletConnect'; -import { isAddress } from '@ethersproject/address'; -import { logger, RainbowError } from '@/logger'; -import { getNetworkObj } from '@/networks'; -import { getNextNonce } from '@/state/nonces'; - -const springConfig = { - damping: 500, - mass: 3, - stiffness: 1000, -}; - -const LoadingSpinner = styled(android ? Spinner : ActivityIndicator).attrs(({ theme: { colors } }) => ({ - color: colors.alpha(colors.blueGreyDark, 0.3), -}))({}); - -const DappLogo = styled(RequestVendorLogoIcon).attrs(({ theme: { colors } }) => ({ - backgroundColor: colors.transparent, - borderRadius: 16, - showLargeShadow: true, - size: 50, -}))({ - marginBottom: 14, -}); - -const Container = styled(Column)({ - flex: 1, -}); - -const AnimatedContainer = Animated.createAnimatedComponent(Container); -const AnimatedSheet = Animated.createAnimatedComponent(Centered); - -const SwitchText = ({ children, ...props }) => { - return ( - <Text color="secondary40 (Deprecated)" size="14px / 19px (Deprecated)" weight="semibold" {...props}> - {children} - </Text> - ); -}; - -const WalletText = ({ balanceTooLow, children }) => { - return ( - <Text - color={balanceTooLow ? { custom: lightModeThemeColors.avatarColor[7] } : 'secondary80 (Deprecated)'} - numberOfLines={1} - size="18px / 27px (Deprecated)" - weight={balanceTooLow ? 'bold' : 'semibold'} - > - {children} - </Text> - ); -}; - -const messageRequestContainerStyle = padding.object(24, 0); - -const rowStyle = padding.object(6, 24, 30); - -const NOOP = () => undefined; - -const Wrapper = ios ? SlackSheet : ({ children }) => children; - -export default function TransactionConfirmationScreen() { - const { colors } = useTheme(); - const [provider, setProvider] = useState(); - const [currentNetwork, setCurrentNetwork] = useState(); - const [isAuthorizing, setIsAuthorizing] = useState(false); - const [methodName, setMethodName] = useState(null); - const calculatingGasLimit = useRef(false); - const [isBalanceEnough, setIsBalanceEnough] = useState(true); - const [isSufficientGasChecked, setIsSufficientGasChecked] = useState(false); - const [nativeAsset, setNativeAsset] = useState(null); - const { height: deviceHeight } = useDimensions(); - const { wallets, walletNames, switchToWalletWithAddress } = useWallets(); - const balances = useWalletBalances(wallets); - const { accountAddress, nativeCurrency } = useAccountSettings(); - const keyboardHeight = useKeyboardHeight(); - const dispatch = useDispatch(); - const { params: routeParams } = useRoute(); - const { goBack, navigate } = useNavigation(); - const isFocused = useIsFocused(); - const { flashbots_enabled } = useRemoteConfig(); - - const pendingRedirect = useSelector(({ walletconnect }) => walletconnect.pendingRedirect); - - const walletConnectors = useSelector(({ walletconnect }) => walletconnect.walletConnectors); - - const { dataAddNewTransaction, removeRequest, walletConnectSendStatus } = useTransactionConfirmation(); - - const { - callback, - transactionDetails: { - dappName, - dappScheme, - dappUrl, - displayDetails, - imageUrl, - payload: { method, params }, - peerId, - requestId, - walletConnectV2RequestValues, - }, - } = routeParams; - const isMessageRequest = isMessageDisplayType(method); - const [ready, setReady] = useState(isMessageRequest); - const genericNativeAsset = useNativeAssetForNetwork(currentNetwork); - const walletConnector = walletConnectors[peerId]; - - const accountInfo = useMemo(() => { - // TODO where do we get address for sign/send transaction? - const address = walletConnectV2RequestValues?.address || walletConnector?._accounts?.[0]; - const selectedWallet = findWalletWithAccount(wallets, address); - const profileInfo = getAccountProfileInfo(selectedWallet, walletNames, address); - return { - ...profileInfo, - address, - isHardwareWallet: !!selectedWallet?.deviceId, - }; - }, [walletConnector?._accounts, walletNames, wallets, walletConnectV2RequestValues]); - - const isTestnet = isTestnetNetwork(currentNetwork); - const isL2 = isL2Network(currentNetwork); - const disableFlashbotsPostMerge = !flashbots_enabled; - const flashbotsEnabled = useExperimentalFlag(FLASHBOTS_WC) && !disableFlashbotsPostMerge; - - useEffect(() => { - setCurrentNetwork(ethereumUtils.getNetworkFromChainId(Number(walletConnectV2RequestValues?.chainId || walletConnector?._chainId))); - }, [walletConnectV2RequestValues?.chainId, walletConnector?._chainId]); - - useEffect(() => { - const initProvider = async () => { - let p; - if (currentNetwork === Network.mainnet && flashbotsEnabled) { - p = await getFlashbotsProvider(currentNetwork); - } else { - p = await getProviderForNetwork(currentNetwork); - } - - setProvider(p); - }; - currentNetwork && initProvider(); - }, [currentNetwork, flashbotsEnabled, setProvider]); - - useEffect(() => { - const getNativeAsset = async () => { - const asset = await ethereumUtils.getNativeAssetForNetwork(currentNetwork, accountInfo.address); - provider && setNativeAsset(asset); - }; - currentNetwork && getNativeAsset(); - }, [accountInfo.address, currentNetwork, provider]); - - const { - gasLimit, - isValidGas, - isSufficientGas, - startPollingGasFees, - stopPollingGasFees, - updateGasFeeOption, - updateTxFee, - selectedGasFee, - selectedGasFeeOption, - gasFeeParamsBySpeed, - } = useGas({ nativeAsset }); - - useEffect(() => { - if (isEmpty(selectedGasFee?.gasFee) || isEmpty(gasFeeParamsBySpeed) || !nativeAsset || !currentNetwork || isSufficientGasChecked) - return; - updateGasFeeOption(selectedGasFeeOption); - setIsSufficientGasChecked(true); - }, [ - isSufficientGas, - isSufficientGasChecked, - nativeAsset, - currentNetwork, - selectedGasFee, - selectedGasFeeOption, - updateGasFeeOption, - gasFeeParamsBySpeed, - ]); - - const request = useMemo(() => { - return isMessageRequest ? { message: displayDetails.request } : { ...displayDetails.request, nativeAsset: nativeAsset }; - }, [displayDetails.request, nativeAsset, isMessageRequest]); - - const openAutomatically = routeParams?.openAutomatically; - - const formattedDappUrl = useMemo(() => { - const { hostname } = new URL(dappUrl); - return hostname; - }, [dappUrl]); - - const handleL2DisclaimerPress = useCallback(() => { - if (isTestnet) return; - navigate(Routes.EXPLAIN_SHEET, { - type: currentNetwork, - }); - }, [isTestnet, navigate, currentNetwork]); - - const fetchMethodName = useCallback( - async data => { - if (!data) return; - const methodSignaturePrefix = data.substr(0, 10); - let fallbackHandler; - try { - fallbackHandler = setTimeout(() => { - setMethodName(lang.t('wallet.transaction.request')); - }, 5000); - const { name } = await methodRegistryLookupAndParse(methodSignaturePrefix, getNetworkObj(currentNetwork).id); - if (name) { - setMethodName(name); - clearTimeout(fallbackHandler); - } - } catch (e) { - setMethodName(lang.t('wallet.transaction.request')); - clearTimeout(fallbackHandler); - } - }, - [setMethodName, currentNetwork] - ); - - useEffect(() => { - if (openAutomatically && !isEmulatorSync()) { - ReactNativeHapticFeedback.trigger('notificationSuccess'); - } - InteractionManager.runAfterInteractions(() => { - if (currentNetwork) { - if (!isMessageRequest) { - startPollingGasFees(currentNetwork); - fetchMethodName(params[0].data); - } else { - setMethodName(lang.t('wallet.message_signing.request')); - } - analytics.track('Shown Walletconnect signing request'); - } - }); - }, [dappUrl, fetchMethodName, isMessageRequest, method, currentNetwork, openAutomatically, params, startPollingGasFees]); - - const closeScreen = useCallback( - canceled => { - // we need to close the hw navigator too - if (accountInfo.isHardwareWallet) { - delay(300); - goBack(); - } - goBack(); - if (!isMessageRequest) { - stopPollingGasFees(); - } - - let type = method === SEND_TRANSACTION ? 'transaction' : 'sign'; - if (canceled) { - type = `${type}-canceled`; - } - - if (pendingRedirect) { - InteractionManager.runAfterInteractions(() => { - dispatch(walletConnectRemovePendingRedirect(type, dappScheme)); - }); - } - - if (walletConnectV2RequestValues?.onComplete) { - InteractionManager.runAfterInteractions(() => { - walletConnectV2RequestValues.onComplete(type); - }); - } - }, - [ - accountInfo.isHardwareWallet, - goBack, - isMessageRequest, - pendingRedirect, - walletConnectV2RequestValues, - stopPollingGasFees, - method, - dispatch, - dappScheme, - ] - ); - - const onCancel = useCallback( - async error => { - try { - if (callback) { - callback({ error: error || 'User cancelled the request' }); - } - setTimeout(async () => { - if (requestId) { - if (walletConnectV2RequestValues) { - await handleSessionRequestResponse(walletConnectV2RequestValues, { - error: error || 'User cancelled the request', - }); - } else { - await dispatch( - walletConnectSendStatus(peerId, requestId, { - error: error || 'User cancelled the request', - }) - ); - } - dispatch(removeRequest(requestId)); - } - const rejectionType = method === SEND_TRANSACTION ? 'transaction' : 'signature'; - analytics.track(`Rejected WalletConnect ${rejectionType} request`, { - isHardwareWallet: accountInfo.isHardwareWallet, - }); - - closeScreen(true); - }, 300); - } catch (error) { - logger.error(new RainbowError('WC: error while handling cancel request'), { error }); - closeScreen(true); - } - }, - [ - accountInfo.isHardwareWallet, - callback, - closeScreen, - dispatch, - method, - peerId, - removeRequest, - requestId, - walletConnectSendStatus, - walletConnectV2RequestValues, - ] - ); - - const onPressCancel = useCallback(() => onCancel(), [onCancel]); - - useEffect(() => { - if (isFocused && (!peerId || (!walletConnector && !walletConnectV2RequestValues)) && (ios || IS_TESTING !== 'true')) { - Alert.alert(lang.t('wallet.transaction.alert.connection_expired'), lang.t('wallet.transaction.alert.please_go_back_and_reconnect'), [ - { - onPress: () => onCancel(), - }, - ]); - } - }, [isFocused, goBack, onCancel, peerId, walletConnector, walletConnectV2RequestValues]); - - const calculateGasLimit = useCallback(async () => { - calculatingGasLimit.current = true; - const txPayload = params?.[0]; - // use the default - let gas = txPayload.gasLimit || txPayload.gas; - - // sometimes provider is undefined, this is hack to ensure its defined - const localCurrentNetwork = ethereumUtils.getNetworkFromChainId( - Number(walletConnectV2RequestValues?.chainId || walletConnector?._chainId) - ); - const provider = await getProviderForNetwork(localCurrentNetwork); - try { - // attempt to re-run estimation - logger.debug('WC: Estimating gas limit', { gas }, logger.DebugContext.walletconnect); - - // safety precaution: we want to ensure these properties are not used for gas estimation - const cleanTxPayload = omitFlatten(txPayload, ['gas', 'gasLimit', 'gasPrice', 'maxFeePerGas', 'maxPriorityFeePerGas']); - const rawGasLimit = await estimateGas(cleanTxPayload, provider); - logger.debug('WC: Estimated gas limit', { rawGasLimit }, logger.DebugContext.walletconnect); - if (rawGasLimit) { - gas = toHex(rawGasLimit); - } - } catch (error) { - logger.error(new RainbowError('WC: error estimating gas'), { error }); - } finally { - logger.debug('WC: Setting gas limit to', { gas: convertHexToString(gas) }, logger.DebugContext.walletconnect); - - if (getNetworkObj(currentNetwork).gas.OptimismTxFee) { - const l1GasFeeOptimism = await ethereumUtils.calculateL1FeeOptimism(txPayload, provider); - updateTxFee(gas, null, l1GasFeeOptimism); - } else { - updateTxFee(gas, null); - } - } - }, [currentNetwork, params, updateTxFee, walletConnectV2RequestValues?.chainId, walletConnector?._chainId]); - - useEffect(() => { - if (!isEmpty(gasFeeParamsBySpeed) && !calculatingGasLimit.current && !isMessageRequest && provider) { - InteractionManager.runAfterInteractions(() => { - calculateGasLimit(); - }); - } - }, [calculateGasLimit, gasLimit, gasFeeParamsBySpeed, isMessageRequest, method, params, provider, updateTxFee]); - - const walletBalance = useMemo(() => { - if (isL2 || isTestnet) { - return { - amount: nativeAsset?.balance?.amount || 0, - display: nativeAsset?.balance?.display || `0 ${nativeAsset?.symbol}`, - symbol: nativeAsset?.symbol || 'ETH', - }; - } else { - return { - amount: balances[accountInfo.address] || 0, - display: `${balances[accountInfo.address] || 0} ETH`, - symbol: 'ETH', - }; - } - }, [isL2, isTestnet, nativeAsset?.balance?.amount, nativeAsset?.balance?.display, nativeAsset?.symbol, balances, accountInfo.address]); - - useEffect(() => { - if (isMessageRequest) { - setIsBalanceEnough(true); - return; - } - - if (!isSufficientGas) { - setIsBalanceEnough(false); - return; - } - - const { gasFee } = selectedGasFee; - if (!gasFee?.estimatedFee) { - setIsBalanceEnough(false); - return; - } - // Get the TX fee Amount - const txFeeAmount = fromWei(gasFee?.maxFee?.value?.amount ?? 0); - - // Get the ETH balance - const balanceAmount = walletBalance.amount ?? 0; - - // Get the TX value - const txPayload = params?.[0]; - const value = txPayload?.value ?? 0; - - // Check that there's enough ETH to pay for everything! - const totalAmount = BigNumber(fromWei(value)).plus(txFeeAmount); - const isEnough = greaterThanOrEqualTo(balanceAmount, totalAmount); - - setIsBalanceEnough(isEnough); - }, [isBalanceEnough, isMessageRequest, isSufficientGas, method, currentNetwork, params, selectedGasFee, walletBalance.amount]); - - const handleConfirmTransaction = useCallback(async () => { - const sendInsteadOfSign = method === SEND_TRANSACTION; - const txPayload = params?.[0]; - let { gas, gasLimit: gasLimitFromPayload } = txPayload; - - try { - logger.debug( - 'WC: gas suggested by dapp', - { - gas: convertHexToString(gas), - gasLimitFromPayload: convertHexToString(gasLimitFromPayload), - }, - logger.DebugContext.walletconnect - ); - - // Estimate the tx with gas limit padding before sending - const rawGasLimit = await estimateGasWithPadding(txPayload, null, null, provider); - - // If the estimation with padding is higher or gas limit was missing, - // let's use the higher value - if ( - (isNil(gas) && isNil(gasLimitFromPayload)) || - (!isNil(gas) && greaterThan(rawGasLimit, convertHexToString(gas))) || - (!isNil(gasLimitFromPayload) && greaterThan(rawGasLimit, convertHexToString(gasLimitFromPayload))) - ) { - logger.debug('WC: using padded estimation!', { gas: rawGasLimit.toString() }, logger.DebugContext.walletconnect); - gas = toHex(rawGasLimit); - } - } catch (error) { - logger.error(new RainbowError('WC: error estimating gas'), { error }); - } - // clean gas prices / fees sent from the dapp - const cleanTxPayload = omitFlatten(txPayload, ['gasPrice', 'maxFeePerGas', 'maxPriorityFeePerGas']); - const gasParams = parseGasParamsForTransaction(selectedGasFee); - const calculatedGasLimit = gas || gasLimitFromPayload || gasLimit; - const nonce = await getNextNonce({ address: accountInfo.address, network: currentNetwork }); - let txPayloadUpdated = { - ...cleanTxPayload, - ...gasParams, - nonce, - }; - if (calculatedGasLimit) { - txPayloadUpdated.gasLimit = calculatedGasLimit; - } - txPayloadUpdated = omitFlatten(txPayloadUpdated, ['from', 'gas', 'chainId']); - - logger.debug(`WC: ${method} payload`, { txPayload, txPayloadUpdated }); - - let response = null; - try { - const existingWallet = await loadWallet(accountInfo.address, true, provider); - if (sendInsteadOfSign) { - response = await sendTransaction({ - existingWallet, - provider, - transaction: txPayloadUpdated, - }); - } else { - response = await signTransaction({ - existingWallet, - provider, - transaction: txPayloadUpdated, - }); - } - } catch (e) { - logger.error(new RainbowError(`WC: Error while ${sendInsteadOfSign ? 'sending' : 'signing'} transaction`)); - } - - const { result, error } = response; - if (result) { - if (callback) { - callback({ result: result.hash }); - } - let txSavedInCurrentWallet = false; - let txDetails = null; - if (sendInsteadOfSign) { - txDetails = { - amount: displayDetails?.request?.value ?? 0, - asset: nativeAsset || displayDetails?.request?.asset, - dappName, - data: result.data, - from: displayDetails?.request?.from, - gasLimit, - hash: result.hash, - network: currentNetwork, - nonce: result.nonce, - to: displayDetails?.request?.to, - value: result.value.toString(), - ...gasParams, - }; - if (accountAddress?.toLowerCase() === txDetails.from?.toLowerCase()) { - dispatch(dataAddNewTransaction(txDetails, null, false, provider)); - txSavedInCurrentWallet = true; - } - } - analytics.track('Approved WalletConnect transaction request', { - dappName, - dappUrl, - isHardwareWallet: accountInfo.isHardwareWallet, - network: currentNetwork, - }); - if (isFocused && requestId) { - if (walletConnectV2RequestValues) { - await handleSessionRequestResponse(walletConnectV2RequestValues, { - result: result.hash, - }); - } else { - await dispatch(walletConnectSendStatus(peerId, requestId, { result: result.hash })); - } - dispatch(removeRequest(requestId)); - } - - closeScreen(false); - // When the tx is sent from a different wallet, - // we need to switch to that wallet before saving the tx - if (!txSavedInCurrentWallet) { - InteractionManager.runAfterInteractions(async () => { - await switchToWalletWithAddress(txDetails.from); - dispatch(dataAddNewTransaction(txDetails, null, false, provider)); - }); - } - } else { - logger.error(new RainbowError(`WC: Tx failure - ${formattedDappUrl}`), { - dappName, - dappScheme, - dappUrl, - formattedDappUrl, - rpcMethod: method, - network: currentNetwork, - }); - - // If the user is using a hardware wallet, we don't want to close the sheet on an error - if (!accountInfo.isHardwareWallet) { - await onCancel(error); - } - } - }, [ - method, - params, - selectedGasFee, - gasLimit, - provider, - accountInfo.address, - accountInfo.isHardwareWallet, - callback, - dappName, - dappUrl, - currentNetwork, - isFocused, - requestId, - closeScreen, - displayDetails?.request?.value, - displayDetails?.request?.asset, - displayDetails?.request?.from, - displayDetails?.request?.to, - nativeAsset, - accountAddress, - dispatch, - dataAddNewTransaction, - walletConnectV2RequestValues, - removeRequest, - walletConnectSendStatus, - peerId, - switchToWalletWithAddress, - formattedDappUrl, - dappScheme, - onCancel, - ]); - - const handleSignMessage = useCallback(async () => { - const message = params.find(p => !isAddress(p)); - let response = null; - const existingWallet = await loadWallet(accountInfo.address, true, provider); - switch (method) { - case SIGN: - break; - case PERSONAL_SIGN: - response = await signPersonalMessage(message, existingWallet); - break; - case SIGN_TYPED_DATA_V4: - case SIGN_TYPED_DATA: - response = await signTypedDataMessage(message, existingWallet); - break; - default: - break; - } - const { result, error } = response; - if (result) { - analytics.track('Approved WalletConnect signature request', { - dappName, - dappUrl, - isHardwareWallet: accountInfo.isHardwareWallet, - network: currentNetwork, - }); - if (requestId) { - if (walletConnectV2RequestValues) { - await handleSessionRequestResponse(walletConnectV2RequestValues, { - result, - }); - } else { - await dispatch(walletConnectSendStatus(peerId, requestId, response)); - } - dispatch(removeRequest(requestId)); - } - if (callback) { - callback({ sig: result }); - } - closeScreen(false); - } else { - await onCancel(error); - } - }, [ - params, - accountInfo.address, - accountInfo.isHardwareWallet, - provider, - method, - dappName, - dappUrl, - currentNetwork, - requestId, - callback, - closeScreen, - walletConnectV2RequestValues, - dispatch, - removeRequest, - walletConnectSendStatus, - peerId, - onCancel, - ]); - - const onConfirm = useCallback(async () => { - if (isMessageRequest) { - return handleSignMessage(); - } - if (!isBalanceEnough || !isValidGas) return; - return handleConfirmTransaction(); - }, [handleConfirmTransaction, handleSignMessage, isBalanceEnough, isMessageRequest, isValidGas]); - - const onPressSend = useCallback(async () => { - if (isAuthorizing) return; - setIsAuthorizing(true); - try { - await onConfirm(); - setIsAuthorizing(false); - } catch (error) { - setIsAuthorizing(false); - } - }, [isAuthorizing, onConfirm]); - - const submitFn = useCallback(async () => { - if (accountInfo.isHardwareWallet) { - navigate(Routes.HARDWARE_WALLET_TX_NAVIGATOR, { submit: onPressSend }); - } else { - await onPressSend(); - } - }, [accountInfo.isHardwareWallet, navigate, onPressSend]); - - const renderTransactionButtons = useCallback(() => { - let ready = true; - const isMessage = isMessageRequest; - // If we don't know about gas prices yet - // set the button state to "loading" - if (!isMessage && !isBalanceEnough && isSufficientGas === null) { - ready = false; - } - return !isMessage && (isBalanceEnough === false || !isValidGas) && isSufficientGas !== null ? ( - <Column marginBottom={24} marginTop={19}> - <SheetActionButton - color={colors.transparent} - disabled - label={ - !isValidGas - ? lang.t('button.confirm_exchange.invalid_fee_lowercase') - : lang.t('button.confirm_exchange.symbol_balance_too_low', { - symbol: nativeAsset?.symbol, - }) - } - onPress={onCancel} - size="big" - textColor={colors.avatarColor[7]} - weight="bold" - /> - </Column> - ) : ( - <SheetActionButtonRow ignorePaddingTop> - <SheetActionButton - color={colors.white} - label={lang.t('button.cancel')} - onPress={onPressCancel} - size="big" - textColor={colors.alpha(colors.blueGreyDark, 0.8)} - weight="bold" - /> - <SheetActionButton - color={colors.appleBlue} - label={` ${lang.t('button.confirm')}`} - onPress={ready ? submitFn : NOOP} - size="big" - testID="wc-confirm" - weight="heavy" - /> - </SheetActionButtonRow> - ); - }, [isMessageRequest, isBalanceEnough, isSufficientGas, isValidGas, colors, nativeAsset?.symbol, onCancel, onPressCancel, submitFn]); - - const renderTransactionSection = useCallback(() => { - if (isMessageRequest) { - return ( - <RowWithMargins style={messageRequestContainerStyle}> - <MessageSigningSection message={request.message} method={method} /> - </RowWithMargins> - ); - } - - if (isTransactionDisplayType(method) && request?.asset) { - const amount = request?.value ?? '0.00'; - const nativeAssetPrice = request?.asset?.price?.value || genericNativeAsset?.price?.value || nativeAsset?.price?.value; - const nativeAmount = multiply(nativeAssetPrice, amount); - const nativeAmountDisplay = convertAmountToNativeDisplay(nativeAmount, nativeCurrency); - if (!amount) return; - return ( - <TransactionConfirmationSection - address={ - request?.asset?.mainnet_address || - request?.asset?.address || - request?.nativeAsset?.mainnet_address || - request?.nativeAsset?.address - } - amount={amount} - method={method} - name={request?.asset?.name || request?.nativeAsset?.name} - nativeAmountDisplay={!nativeAssetPrice ? null : nativeAmountDisplay} - symbol={request?.asset?.symbol || request?.nativeAsset?.symbol} - /> - ); - } - return <DefaultTransactionConfirmationSection address={request?.to} data={request?.data} method={method} value={request?.value} />; - }, [ - isMessageRequest, - method, - request?.asset, - request?.to, - request?.data, - request?.value, - request.message, - nativeAsset, - genericNativeAsset?.price?.value, - nativeCurrency, - ]); - - const offset = useSharedValue(0); - const sheetOpacity = useSharedValue(1); - const animatedSheetStyles = useAnimatedStyle(() => ({ - opacity: sheetOpacity.value, - })); - - useEffect(() => { - offset.value = withSpring(0, springConfig); - sheetOpacity.value = withSpring(1, springConfig); - }, [keyboardHeight, offset, sheetOpacity]); - - const amount = request?.value ?? '0.00'; - - const isAndroidApprovalRequest = useMemo( - () => android && isTransactionDisplayType(method) && !!request?.asset && amount === 0 && isBalanceEnough, - [amount, isBalanceEnough, method, request] - ); - - const ShortSheetHeight = 486 + safeAreaInsetValues.bottom; - const TallSheetHeight = 656 + safeAreaInsetValues.bottom; - const MessageSheetHeight = (isSignTypedData(method) ? 630 : android ? 595 : 580) + safeAreaInsetValues.bottom; - - const balanceTooLow = isBalanceEnough === false && isSufficientGas !== null; - - let sheetHeight = - (isMessageRequest ? MessageSheetHeight : (amount && amount !== '0.00') || !isBalanceEnough ? TallSheetHeight : ShortSheetHeight) * - (android ? 1.5 : 1); - - let marginTop = android ? deviceHeight - sheetHeight + 275 : null; - - if (isTransactionDisplayType(method) && !request?.asset) { - marginTop += 50; - } - - if (isAndroidApprovalRequest) { - sheetHeight += 140; - } - - if (isTransactionDisplayType(method) && !isL2 && !isTestnet) { - sheetHeight -= 70; - } - - useEffect(() => { - if (request?.asset && walletBalance && currentNetwork && provider && nativeAsset && !isEmpty(selectedGasFee)) { - setReady(true); - } - }, [nativeAsset, currentNetwork, provider, ready, request?.asset, selectedGasFee, walletBalance]); - - const spinnerHeight = sheetHeight - 227 + (isTransactionDisplayType(method) ? (isL2 ? 84 : 72) : 0); - - return ( - <SheetKeyboardAnimation as={AnimatedContainer} isKeyboardVisible={false} translateY={offset}> - <Wrapper backgroundColor={colors.transparent} borderRadius={0} height={sheetHeight} hideHandle scrollEnabled={false}> - <Column testID="wc-request-sheet"> - <AnimatedSheet - backgroundColor={colors.white} - borderRadius={39} - direction="column" - marginTop={marginTop} - paddingBottom={isMessageRequest ? safeAreaInsetValues.bottom + (android ? 20 : 0) : 0} - paddingTop={24} - style={[animatedSheetStyles, android && isMessageRequest ? { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 } : null]} - > - {!ready ? ( - <Centered height={spinnerHeight}> - <LoadingSpinner size={android ? 40 : 'large'} /> - </Centered> - ) : ( - <Fragment> - <SheetHandleFixedToTop showBlur={false} /> - <Column marginBottom={17} /> - <DappLogo dappName={dappName || ''} imageUrl={imageUrl || ''} network={currentNetwork} /> - <Row marginBottom={android ? -6 : 5}> - <Row marginBottom={android ? 16 : 8} marginHorizontal={32}> - <Text align="center" color="secondary80 (Deprecated)" numberOfLines={1} size="18px / 27px (Deprecated)" weight="bold"> - {formattedDappUrl} - </Text> - </Row> - </Row> - <Centered marginBottom={android ? 10 : 24} paddingHorizontal={24}> - <Text - align="center" - color={methodName ? 'primary (Deprecated)' : { custom: 'transparent' }} - size="18px / 27px (Deprecated)" - weight="heavy" - > - {methodName || lang.t('wallet.transaction.placeholder_title')} - </Text> - </Centered> - {ios && <Divider color={colors.rowDividerLight} inset={[0, 143.5]} />} - {renderTransactionSection()} - {(isL2 || isTestnet) && !isMessageRequest && ( - <Column margin={android ? 24 : 0} width="100%"> - <Row height={android ? 0 : 19} /> - <L2Disclaimer - network={currentNetwork} - colors={colors} - hideDivider - onPress={handleL2DisclaimerPress} - prominent - customText={i18n.t(i18n.l.expanded_state.asset.l2_disclaimer_dapp, { - network: getNetworkObj(currentNetwork).name, - })} - /> - </Column> - )} - {renderTransactionButtons()} - <RowWithMargins margin={15} style={rowStyle}> - <Column flex={1}> - <Row marginBottom={8}> - <SwitchText>{lang.t('wallet.wallet_title')}</SwitchText> - </Row> - <RowWithMargins margin={5} style={{ alignItems: 'center' }}> - {accountInfo.accountImage ? ( - <ImageAvatar image={accountInfo.accountImage} size="smaller" /> - ) : ( - <ContactAvatar - color={isNaN(accountInfo.accountColor) ? colors.skeleton : accountInfo.accountColor} - size="smaller" - value={accountInfo.accountSymbol} - /> - )} - <WalletText>{accountInfo.accountName}</WalletText> - </RowWithMargins> - </Column> - <Column marginLeft={16}> - <Row justify="end" marginBottom={12}> - <SwitchText align="right">{lang.t('wallet.balance_title')}</SwitchText> - </Row> - <WalletText align="right" balanceTooLow={balanceTooLow}> - {isBalanceEnough === false && isSufficientGas !== null && ' '} - {walletBalance?.display} - </WalletText> - </Column> - </RowWithMargins> - </Fragment> - )} - </AnimatedSheet> - {!isMessageRequest && <GasSpeedButton currentNetwork={currentNetwork} theme="dark" />} - </Column> - </Wrapper> - </SheetKeyboardAnimation> - ); -} From b074537bf9a763911df760a552d835f335fb70f1 Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 23 Feb 2024 14:11:42 -0500 Subject: [PATCH 11/12] more clean --- src/navigation/Routes.android.tsx | 1 - src/navigation/Routes.ios.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/navigation/Routes.android.tsx b/src/navigation/Routes.android.tsx index f11ae450aab..e35f7b4de17 100644 --- a/src/navigation/Routes.android.tsx +++ b/src/navigation/Routes.android.tsx @@ -24,7 +24,6 @@ import SendSheet from '../screens/SendSheet'; import ShowcaseSheet from '../screens/ShowcaseSheet'; import SpeedUpAndCancelSheet from '../screens/SpeedUpAndCancelSheet'; import NotificationsPromoSheet from '../screens/NotificationsPromoSheet'; -import TransactionConfirmationScreen from '../screens/TransactionConfirmationScreen'; import WalletConnectApprovalSheet from '../screens/WalletConnectApprovalSheet'; import WalletConnectRedirectSheet from '../screens/WalletConnectRedirectSheet'; import { WalletDiagnosticsSheet } from '../screens/Diagnostics'; diff --git a/src/navigation/Routes.ios.tsx b/src/navigation/Routes.ios.tsx index 469a65149b1..164f4a9aed7 100644 --- a/src/navigation/Routes.ios.tsx +++ b/src/navigation/Routes.ios.tsx @@ -24,7 +24,6 @@ import ShowcaseScreen from '../screens/ShowcaseSheet'; import { SignTransactionSheet } from '../screens/SignTransactionSheet'; import SpeedUpAndCancelSheet from '../screens/SpeedUpAndCancelSheet'; import NotificationsPromoSheet from '../screens/NotificationsPromoSheet'; -import TransactionConfirmationScreen from '../screens/TransactionConfirmationScreen'; import WalletConnectApprovalSheet from '../screens/WalletConnectApprovalSheet'; import WalletConnectRedirectSheet from '../screens/WalletConnectRedirectSheet'; import { WalletDiagnosticsSheet } from '../screens/Diagnostics'; From a03a42a4622768ec22211ce6fb5868aeab80f27d Mon Sep 17 00:00:00 2001 From: skylarbarrera <skylar.barrera@gmail.com> Date: Fri, 23 Feb 2024 16:01:35 -0500 Subject: [PATCH 12/12] clean --- src/components/coin-icon/CoinIcon.tsx | 85 ------------------- src/components/coin-icon/index.js | 2 +- src/components/coin-row/CoinRow.js | 5 +- .../expanded-state/AvailableNetworks.js | 2 +- src/components/gas/GasSpeedButton.js | 4 +- src/components/positions/PositionsCard.tsx | 3 +- .../WalletConnectV2ListItem.tsx | 6 +- src/screens/ExplainSheet.js | 2 +- .../components/CurrencySection.tsx | 77 ++++++++++++----- src/screens/WalletConnectApprovalSheet.js | 4 +- src/screens/mints/MintSheet.tsx | 2 +- src/utils/CoinIcons/CoinIcon.js | 77 ----------------- src/utils/index.ts | 1 - 13 files changed, 67 insertions(+), 203 deletions(-) delete mode 100644 src/utils/CoinIcons/CoinIcon.js diff --git a/src/components/coin-icon/CoinIcon.tsx b/src/components/coin-icon/CoinIcon.tsx index 9ad65239ffc..25c1a46c13d 100644 --- a/src/components/coin-icon/CoinIcon.tsx +++ b/src/components/coin-icon/CoinIcon.tsx @@ -1,86 +1 @@ -import React, { useMemo } from 'react'; -import { View, ViewProps } from 'react-native'; -import ContractInteraction from '../../assets/contractInteraction.png'; -import { useTheme } from '../../theme/ThemeContext'; -import ChainBadge from './ChainBadge'; -import { CoinIconFallback } from './CoinIconFallback'; -import { Network } from '@/networks/types'; -import { useColorForAsset } from '@/hooks'; -import { ImgixImage } from '@/components/images'; -import styled from '@/styled-thing'; -import { ethereumUtils, isETH, magicMemo, CoinIcon as ReactCoinIcon } from '@/utils'; -import { ChainBadgeType } from '@/components/coin-icon/ChainBadgeSizeConfigs'; - export const CoinIconSize = 40; - -const ContractInteractionIcon = styled(ImgixImage)(({ size }: { size: number }) => ({ - height: size, - width: size, -})); - -const StyledCoinIcon = styled(ReactCoinIcon)({ - opacity: ({ isHidden }: { isHidden?: boolean }) => (isHidden ? 0.4 : 1), -}); - -type Props = { - address?: string; - badgeXPosition?: number; - badgeYPosition?: number; - badgeSize?: ChainBadgeType; - ignoreBadge?: boolean; - forcedShadowColor?: string; - size?: number; - symbol?: string; - network: string; - mainnet_address?: string; - shadowOpacity?: number; -} & Pick<ViewProps, 'testID' | 'style'>; - -const CoinIcon: React.FC<Props> = ({ - address = 'eth', - badgeXPosition, - badgeYPosition, - badgeSize, - ignoreBadge = false, - forcedShadowColor, - size = CoinIconSize, - symbol = '', - network, - mainnet_address, - ...props -}) => { - const color = useColorForAsset({ - address: mainnet_address || address, - }); - const { colors, isDarkMode } = useTheme(); - const forceFallback = !isETH(mainnet_address || address); - const isNotContractInteraction = useMemo(() => symbol !== 'contract', [symbol]); - - const theme = useTheme(); - - return ( - <View> - {isNotContractInteraction ? ( - <StyledCoinIcon - {...props} - address={mainnet_address || address} - color={color} - fallbackRenderer={CoinIconFallback} - forceFallback={true} - // force update on change symbol due to ImageCache strategy - key={symbol} - shadowColor={forcedShadowColor || (isDarkMode ? colors.shadow : color)} - size={size} - symbol={symbol} - network={mainnet_address ? Network.mainnet : network} - theme={theme} - /> - ) : ( - <ContractInteractionIcon size={size} source={ContractInteraction} /> - )} - {!ignoreBadge && <ChainBadge network={network} badgeXPosition={badgeXPosition} badgeYPosition={badgeYPosition} size={badgeSize} />} - </View> - ); -}; - -export default magicMemo(CoinIcon, ['address', 'isHidden', 'isPinned', 'size', 'network', 'symbol', 'shadowColor']); diff --git a/src/components/coin-icon/index.js b/src/components/coin-icon/index.js index 962de1fe0b4..da7654b2cd4 100644 --- a/src/components/coin-icon/index.js +++ b/src/components/coin-icon/index.js @@ -1,5 +1,5 @@ export { default as ChainBadge } from './ChainBadge'; -export { default as CoinIcon, CoinIconSize } from './CoinIcon'; +export { CoinIconSize } from './CoinIcon'; export { default as CoinIconFallback } from './CoinIconFallback'; export { default as CoinIconIndicator } from './CoinIconIndicator'; export { default as RequestCoinIcon } from './RequestCoinIcon'; diff --git a/src/components/coin-row/CoinRow.js b/src/components/coin-row/CoinRow.js index ccaae419140..08f04fa850f 100644 --- a/src/components/coin-row/CoinRow.js +++ b/src/components/coin-row/CoinRow.js @@ -1,9 +1,10 @@ import React, { createElement } from 'react'; -import { CoinIcon, CoinIconSize } from '../coin-icon'; +import { CoinIconSize } from '../coin-icon'; import { Column, Row } from '../layout'; import { useAccountSettings } from '@/hooks'; import styled from '@/styled-thing'; import { padding } from '@/styles'; +import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; const CoinRowPaddingTop = 9; const CoinRowPaddingBottom = 10; @@ -31,7 +32,7 @@ export default function CoinRow({ badgeYPosition, bottomRowRender, children, - coinIconRender = CoinIcon, + coinIconRender = RainbowCoinIcon, containerStyles, contentStyles, isFirstCoinRow, diff --git a/src/components/expanded-state/AvailableNetworks.js b/src/components/expanded-state/AvailableNetworks.js index 4377749ef1a..b54bf9d66b7 100644 --- a/src/components/expanded-state/AvailableNetworks.js +++ b/src/components/expanded-state/AvailableNetworks.js @@ -11,7 +11,7 @@ import { ethereumUtils } from '@/utils'; import { useTheme } from '@/theme'; import { ButtonPressAnimation } from '../animations'; import { Column, Row } from '../layout'; -import { ChainBadge, CoinIcon } from '../coin-icon'; +import { ChainBadge } from '../coin-icon'; import Divider from '../Divider'; import { Text } from '../text'; import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; diff --git a/src/components/gas/GasSpeedButton.js b/src/components/gas/GasSpeedButton.js index a065d0c30e3..e2470b77fa2 100644 --- a/src/components/gas/GasSpeedButton.js +++ b/src/components/gas/GasSpeedButton.js @@ -2,7 +2,7 @@ /* eslint-disable no-undef */ import AnimateNumber from '@bankify/react-native-animate-number'; import lang from 'i18n-js'; -import { isEmpty, isNaN, isNil, upperFirst } from 'lodash'; +import { isEmpty, isNaN, isNil } from 'lodash'; import makeColorMoreChill from 'make-color-more-chill'; import { AnimatePresence, MotiView } from 'moti'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; @@ -10,7 +10,7 @@ import { InteractionManager, Keyboard } from 'react-native'; import { Easing } from 'react-native-reanimated'; import { darkModeThemeColors } from '../../styles/colors'; import { ButtonPressAnimation } from '../animations'; -import { ChainBadge, CoinIcon } from '../coin-icon'; +import { ChainBadge } from '../coin-icon'; import { Centered, Column, Row } from '../layout'; import { Text } from '../text'; import { GasSpeedLabelPager } from '.'; diff --git a/src/components/positions/PositionsCard.tsx b/src/components/positions/PositionsCard.tsx index b0f3f2df34a..4eaa4dda1fb 100644 --- a/src/components/positions/PositionsCard.tsx +++ b/src/components/positions/PositionsCard.tsx @@ -4,7 +4,7 @@ import { useTheme } from '@/theme'; import { GenericCard } from '../cards/GenericCard'; import startCase from 'lodash/startCase'; -import { CoinIcon, RequestVendorLogoIcon } from '../coin-icon'; +import { RequestVendorLogoIcon } from '../coin-icon'; import { EthereumAddress } from '@/entities'; import { useNavigation } from '@/navigation'; import Routes from '@/navigation/routesNames'; @@ -13,7 +13,6 @@ import { event } from '@/analytics/event'; import { IS_ANDROID } from '@/env'; import { capitalize, uniqBy } from 'lodash'; import { RainbowDeposit, RainbowPosition } from '@/resources/defi/types'; -import { ethereumUtils } from '@/utils'; import { Network } from '@/networks/types'; import RainbowCoinIcon from '../coin-icon/RainbowCoinIcon'; import { useAccountSettings } from '@/hooks'; diff --git a/src/components/walletconnect-list/WalletConnectV2ListItem.tsx b/src/components/walletconnect-list/WalletConnectV2ListItem.tsx index 5e7abcd6d6a..eab8284a5d4 100644 --- a/src/components/walletconnect-list/WalletConnectV2ListItem.tsx +++ b/src/components/walletconnect-list/WalletConnectV2ListItem.tsx @@ -2,12 +2,12 @@ import React, { useCallback, useMemo } from 'react'; import { SessionTypes } from '@walletconnect/types'; import RadialGradient from 'react-native-radial-gradient'; -import { RequestVendorLogoIcon, CoinIcon } from '../coin-icon'; +import { RequestVendorLogoIcon } from '../coin-icon'; import { ContactAvatar } from '../contacts'; import ImageAvatar from '../contacts/ImageAvatar'; import { ContextMenuButton } from '../context-menu'; import { Centered, ColumnWithMargins, Row } from '../layout'; -import { Text, TruncatedText } from '../text'; +import { TruncatedText } from '../text'; import { analytics } from '@/analytics'; import { getAccountProfileInfo } from '@/helpers/accountInfo'; import { findWalletWithAccount } from '@/helpers/findWalletWithAccount'; @@ -24,8 +24,6 @@ import { logger, RainbowError } from '@/logger'; import { changeAccount, disconnectSession, isSupportedChain } from '@/walletConnect'; import { Box, Inline } from '@/design-system'; import ChainBadge from '@/components/coin-icon/ChainBadge'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; - import { Network } from '@/helpers'; import { EthCoinIcon } from '../coin-icon/EthCoinIcon'; diff --git a/src/screens/ExplainSheet.js b/src/screens/ExplainSheet.js index 10a24340660..10862fa1422 100644 --- a/src/screens/ExplainSheet.js +++ b/src/screens/ExplainSheet.js @@ -3,7 +3,7 @@ import lang from 'i18n-js'; import React, { useCallback, useMemo } from 'react'; import { Linking, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { ChainBadge, CoinIcon, DashedWrapper } from '../components/coin-icon'; +import { ChainBadge, DashedWrapper } from '../components/coin-icon'; import { Centered, Column, ColumnWithMargins, Row, RowWithMargins } from '../components/layout'; import Routes from '@/navigation/routesNames'; import { SheetActionButton, SheetTitle, SlackSheet } from '../components/sheet'; diff --git a/src/screens/SettingsSheet/components/CurrencySection.tsx b/src/screens/SettingsSheet/components/CurrencySection.tsx index 7d421d4c3ab..a3a4a761427 100644 --- a/src/screens/SettingsSheet/components/CurrencySection.tsx +++ b/src/screens/SettingsSheet/components/CurrencySection.tsx @@ -1,14 +1,19 @@ import React, { useCallback } from 'react'; -import { Platform } from 'react-native'; +import { Platform, View } from 'react-native'; import { reloadTimelines } from 'react-native-widgetkit'; -import { CoinIcon } from '../../../components/coin-icon'; import Menu from './Menu'; import MenuContainer from './MenuContainer'; import MenuItem from './MenuItem'; import { analytics } from '@/analytics'; import { useAccountSettings } from '@/hooks'; -import { emojis, supportedNativeCurrencies } from '@/references'; +import { ETH_ADDRESS, WBTC_ADDRESS, emojis, supportedNativeCurrencies } from '@/references'; +import { BackgroundProvider, Box, Inline, Inset, Text } from '@/design-system'; +import { SimpleSheet } from '@/components/sheet/SimpleSheet'; +import * as i18n from '@/languages'; import { Network } from '@/networks/types'; +import { useExternalToken } from '@/resources/assets/externalAssetsQuery'; +import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon'; +import { useTheme } from '@/theme'; const emojiData = Object.entries(emojis).map(([emoji, { name }]) => [name, emoji]); @@ -21,6 +26,9 @@ const currencyListItems = Object.values(supportedNativeCurrencies).map(({ curren const CurrencySection = () => { const { nativeCurrency, settingsChangeNativeCurrency } = useAccountSettings(); + const theme = useTheme(); + const { data: WBTC } = useExternalToken({ address: WBTC_ADDRESS, network: Network.mainnet, currency: nativeCurrency }); + const { data: ETH } = useExternalToken({ address: ETH_ADDRESS, network: Network.mainnet, currency: nativeCurrency }); const onSelectCurrency = useCallback( (currency: any) => { @@ -35,26 +43,49 @@ const CurrencySection = () => { ); return ( - <MenuContainer> - <Menu> - {currencyListItems.map(({ label, emojiName, currency }: any) => ( - <MenuItem - key={currency} - leftComponent={ - emojiName ? ( - <MenuItem.TextIcon icon={(emoji.get('flag_' + emojiName) as string) || ''} isEmoji /> - ) : ( - <CoinIcon address={currency} size={23} style={{ marginLeft: 7 }} symbol={currency} network={Network.mainnet} /> - ) - } - onPress={() => onSelectCurrency(currency)} - rightComponent={currency === nativeCurrency && <MenuItem.StatusIcon status="selected" />} - size={52} - titleComponent={<MenuItem.Title text={label} />} - /> - ))} - </Menu> - </MenuContainer> + <BackgroundProvider color="surfaceSecondary"> + {({ backgroundColor }) => ( + <SimpleSheet backgroundColor={backgroundColor as string}> + <Inset top="20px" horizontal="20px" bottom="60px"> + <Inline alignHorizontal="center" alignVertical="center"> + <Box paddingBottom="12px"> + <Text size="22pt" weight="heavy" color="label"> + {i18n.t(i18n.l.settings.currency)} + </Text> + </Box> + </Inline> + <MenuContainer> + <Menu> + {currencyListItems.map(({ label, emojiName, currency }: any) => ( + <MenuItem + key={currency} + leftComponent={ + emojiName ? ( + <MenuItem.TextIcon icon={(emoji.get('flag_' + emojiName) as string) || ''} isEmoji /> + ) : ( + <View style={{ marginLeft: 7 }}> + <RainbowCoinIcon + icon={currency === ETH?.symbol ? ETH?.icon_url : WBTC?.icon_url} + size={23} + symbol={currency} + network={Network.mainnet} + theme={theme} + /> + </View> + ) + } + onPress={() => onSelectCurrency(currency)} + rightComponent={currency === nativeCurrency && <MenuItem.StatusIcon status="selected" />} + size={52} + titleComponent={<MenuItem.Title text={label} />} + /> + ))} + </Menu> + </MenuContainer> + </Inset> + </SimpleSheet> + )} + </BackgroundProvider> ); }; diff --git a/src/screens/WalletConnectApprovalSheet.js b/src/screens/WalletConnectApprovalSheet.js index 0d3ddb470ee..eeb5d4b8bd8 100644 --- a/src/screens/WalletConnectApprovalSheet.js +++ b/src/screens/WalletConnectApprovalSheet.js @@ -6,7 +6,7 @@ import ChainLogo from '../components/ChainLogo'; import Divider from '../components/Divider'; import Spinner from '../components/Spinner'; import ButtonPressAnimation from '../components/animations/ButtonPressAnimation'; -import { RequestVendorLogoIcon, CoinIcon } from '../components/coin-icon'; +import { RequestVendorLogoIcon } from '../components/coin-icon'; import { ContactAvatar } from '../components/contacts'; import ImageAvatar from '../components/contacts/ImageAvatar'; import { Centered, Column, Flex, Row } from '../components/layout'; @@ -25,9 +25,7 @@ import { Network } from '@/helpers'; import { Box, Columns, Column as RDSColumn, Inline, Text } from '@/design-system'; import ChainBadge from '@/components/coin-icon/ChainBadge'; import * as lang from '@/languages'; -import { ETH_ADDRESS, ETH_SYMBOL } from '@/references'; import { RainbowNetworks, getNetworkObj } from '@/networks'; -import { IS_IOS } from '@/env'; import { useDappMetadata } from '@/resources/metadata/dapp'; import { DAppStatus } from '@/graphql/__generated__/metadata'; import { InfoAlert } from '@/components/info-alert/info-alert'; diff --git a/src/screens/mints/MintSheet.tsx b/src/screens/mints/MintSheet.tsx index fab9b9fa41e..c671d7e235c 100644 --- a/src/screens/mints/MintSheet.tsx +++ b/src/screens/mints/MintSheet.tsx @@ -19,7 +19,7 @@ import { useNavigation } from '@/navigation'; import styled from '@/styled-thing'; import { position } from '@/styles'; import { useTheme } from '@/theme'; -import { CoinIcon, abbreviations, ethereumUtils, watchingAlert } from '@/utils'; +import { abbreviations, ethereumUtils, watchingAlert } from '@/utils'; import { usePersistentDominantColorFromImage } from '@/hooks/usePersistentDominantColorFromImage'; import { maybeSignUri } from '@/handlers/imgix'; import { ButtonPressAnimation } from '@/components/animations'; diff --git a/src/utils/CoinIcons/CoinIcon.js b/src/utils/CoinIcons/CoinIcon.js deleted file mode 100644 index 8f2b7801fff..00000000000 --- a/src/utils/CoinIcons/CoinIcon.js +++ /dev/null @@ -1,77 +0,0 @@ -/* eslint-disable import/namespace */ -import React, { useMemo } from 'react'; -import * as CoinIconsImages from 'react-coin-icon/lib/pngs'; -import { Image } from 'react-native'; -import { StyleSheet, View } from 'react-primitives'; -import FallbackIcon from './FallbackIcon'; - -const sx = StyleSheet.create({ - container: { - alignItems: 'center', - justifyContent: 'center', - }, - image: { - height: '100%', - width: '100%', - }, -}); - -function formatSymbol(symbol) { - return symbol ? symbol.charAt(0).toUpperCase() + symbol.slice(1).toLowerCase() : ''; -} - -const CoinIcon = ({ - color = '#3A3D51', - fallbackRenderer: Fallback = FallbackIcon, - forceFallback, - shadowColor, - size = 32, - style, - symbol, - ...props -}) => { - const formattedSymbol = useMemo(() => formatSymbol(symbol), [symbol]); - - const circleProps = useMemo( - () => ({ - borderRadius: size / 2, - height: size, - width: size, - }), - [size] - ); - - const shadowProps = useMemo(() => { - const isSmall = size < 30; - - return { - elevation: isSmall ? 4.5 : 6, - shadowColor: shadowColor || color, - shadowOffset: { - height: isSmall ? 3 : 4, - width: 0, - }, - shadowOpacity: isSmall ? 0.2 : 0.3, - shadowRadius: isSmall ? 4.5 : 6, - }; - }, [color, shadowColor, size]); - - if (!forceFallback && CoinIconsImages[formattedSymbol]) { - return ( - <View {...circleProps} {...shadowProps} style={[sx.container, style]}> - <Image resizeMode="contain" source={CoinIconsImages[formattedSymbol]} style={sx.image} /> - </View> - ); - } - - return ( - <View {...circleProps} style={[sx.container, style]}> - <Fallback {...circleProps} {...shadowProps} color={color} symbol={formattedSymbol} size={size} {...props} /> - </View> - ); -}; - -const arePropsEqual = (prev, next) => - prev.color === next.color && prev.shadowColor === next.shadowColor && prev.size === next.size && prev.symbol === next.symbol; - -export default React.memo(CoinIcon, arePropsEqual); diff --git a/src/utils/index.ts b/src/utils/index.ts index a827e38d6c1..0ebd4ada6b7 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -35,7 +35,6 @@ export { filterList } from './search'; export { getFirstGrapheme, initials, removeLeadingZeros, sanitizeSeedPhrase } from './formatters'; export { default as watchingAlert } from './watchingAlert'; export { default as withSpeed } from './withSpeed'; -export { default as CoinIcon } from './CoinIcons/CoinIcon'; export { default as FallbackIcon } from './CoinIcons/FallbackIcon'; export { default as getExchangeIconUrl } from './getExchangeIconUrl'; export { resolveFirstRejectLast } from './resolveFirstRejectLast';