Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

CP-9946 & CP-9947: Add Action Buttons to Watchlist #2336

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/core-mobile/app/consts/coingecko.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const AVAX_COINGECKO_ID = 'avalanche-2'

export const BITCOIN_COINGECKO_ID = 'bitcoin'

export const ETHEREUM_COINGECKO_ID = 'ethereum'
2 changes: 2 additions & 0 deletions packages/core-mobile/app/consts/swap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const AVAX_TOKEN_ID = 'AvalancheAVAX'
export const USDC_TOKEN_ID = '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E'
43 changes: 43 additions & 0 deletions packages/core-mobile/app/hooks/earn/useHasEnoughAvaxToStake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useCChainBalance } from 'hooks/earn/useCChainBalance'
import useStakingParams from 'hooks/earn/useStakingParams'
import { useEffect, useState } from 'react'
import { useGetClaimableBalance } from 'hooks/earn/useGetClaimableBalance'
import { TokenUnit } from '@avalabs/core-utils-sdk'
import useCChainNetwork from 'hooks/earn/useCChainNetwork'
import { useGetStuckBalance } from 'hooks/earn/useGetStuckBalance'

export const useHasEnoughAvaxToStake = (): {
hasEnoughAvax: boolean | undefined
} => {
const { minStakeAmount } = useStakingParams()
const cChainBalance = useCChainBalance()
const claimableBalance = useGetClaimableBalance()
const cChainNetwork = useCChainNetwork()
const stuckBalance = useGetStuckBalance()
const cChainNetworkToken = cChainNetwork?.networkToken
const [hasEnoughAvax, setHasEnoughAvax] = useState<boolean | undefined>(
undefined
)

useEffect(() => {
if (cChainBalance.data?.balance !== undefined && cChainNetworkToken) {
const availableAvax = new TokenUnit(
cChainBalance.data.balance,
cChainNetworkToken.decimals,
cChainNetworkToken.symbol
)
.add(claimableBalance ?? 0)
.add(stuckBalance ?? 0)

setHasEnoughAvax(availableAvax.gt(minStakeAmount))
}
}, [
cChainBalance?.data?.balance,
minStakeAmount,
stuckBalance,
claimableBalance,
cChainNetworkToken
])

return { hasEnoughAvax }
}
11 changes: 8 additions & 3 deletions packages/core-mobile/app/hooks/useCoinGeckoId.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { useTokenInfoContext } from '@avalabs/core-bridge-sdk'
import {
AVAX_COINGECKO_ID,
BITCOIN_COINGECKO_ID,
ETHEREUM_COINGECKO_ID
} from 'consts/coingecko'

const KNOWN_IDS: { [key: string]: string } = {
BTC: 'bitcoin',
AVAX: 'avalanche-2',
ETH: 'ethereum'
BTC: BITCOIN_COINGECKO_ID,
AVAX: AVAX_COINGECKO_ID,
ETH: ETHEREUM_COINGECKO_ID
}

export const useCoinGeckoId = (tokenSymbol?: string): string | undefined => {
Expand Down
6 changes: 3 additions & 3 deletions packages/core-mobile/app/hooks/useIsUIDisabled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ const enabledUIs: Partial<Record<UI, number[]>> = {
ChainId.ETHEREUM_TEST_RINKEBY,
ChainId.ETHEREUM_TEST_SEPOLIA
],
[UI.Swap]: [ChainId.AVALANCHE_MAINNET_ID],
[UI.Buy]: [ChainId.AVALANCHE_MAINNET_ID, ChainId.AVALANCHE_TESTNET_ID]
[UI.Swap]: [ChainId.AVALANCHE_MAINNET_ID]
}

// The list of features we want to disable on certain networks (blacklist)
Expand All @@ -40,7 +39,8 @@ const disabledUIs: Partial<Record<UI, number[]>> = {
ChainId.SWIMMER,
ChainId.SWIMMER_TESTNET
],
[UI.WalletConnect]: [] // empty array means this feature shouldn't be disabled on any network
[UI.WalletConnect]: [], // empty array means this feature shouldn't be disabled on any network
[UI.Buy]: []
}

export const useIsUIDisabled = (ui: UI): boolean => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { UseQueryResult, useQuery } from '@tanstack/react-query'
import { ReactQueryKeys } from 'consts/reactQueryKeys'
import { useExchangeRates } from 'hooks/defi/useExchangeRates'
import { useSelector } from 'react-redux'
import { TrendingToken } from 'services/token/types'
import WatchlistService from 'services/watchlist/WatchlistService'
import { selectSelectedCurrency } from 'store/settings/currency'

export const useGetTrendingTokens = <TData = TrendingToken[]>(
select?: (data: TrendingToken[]) => TData
): UseQueryResult<TData, Error> => {
const selectedCurrency = useSelector(selectSelectedCurrency)
const { data } = useExchangeRates()
const exchangeRate = data?.usd?.[selectedCurrency.toLowerCase()]

return useQuery({
queryKey: [ReactQueryKeys.WATCHLIST_TRENDING_TOKENS_AND_CHARTS],
queryFn: async () => WatchlistService.getTrendingTokens(),
queryKey: [
ReactQueryKeys.WATCHLIST_TRENDING_TOKENS_AND_CHARTS,
exchangeRate
],
queryFn: async () => WatchlistService.getTrendingTokens(exchangeRate),
refetchInterval: 120000, // 2 mins
select
})
Expand Down
3 changes: 2 additions & 1 deletion packages/core-mobile/app/navigation/AppNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ enum WalletScreens {
Earn = 'WalletScreens.Earn',
Notifications = 'WalletScreens.Notifications',
DeFiProtocolDetails = 'WalletScreens.DeFiProtocolDetails',
SendFeedback = 'WalletScreens.SendFeedback'
SendFeedback = 'WalletScreens.SendFeedback',
Halliday = 'WalletScreens.Halliday'
}

enum ReceiveTokensScreens {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import TestnetBanner from 'components/TestnetBanner'
import { selectIsDeveloperMode } from 'store/settings/advanced'
import { NFTMetadataProvider } from 'contexts/NFTItemsContext'
import { BridgeProvider } from 'contexts/BridgeContext'
import { HallidayWebView } from 'screens/bridge/components/HallidayWebView'
import { BridgeStackParamList } from '../wallet/BridgeScreenStack'
import {
AddEthereumChainV2Params,
Expand Down Expand Up @@ -119,6 +120,7 @@ export type WalletScreenStackParams = {
[AppNavigation.Wallet.Buy]:
| NavigatorScreenParams<BuyStackParamList>
| undefined
[AppNavigation.Wallet.Halliday]: undefined
[AppNavigation.Wallet.Bridge]:
| NavigatorScreenParams<BridgeStackParamList>
| undefined
Expand Down Expand Up @@ -305,6 +307,13 @@ function WalletScreenStack(props: Props): JSX.Element {
name={AppNavigation.Wallet.Swap}
component={SwapScreenStack}
/>
<WalletScreenS.Screen
options={{
...MainHeaderOptions({ title: 'Halliday' })
}}
name={AppNavigation.Wallet.Halliday}
component={HallidayWebView}
/>
<WalletScreenS.Screen
options={{
headerShown: false
Expand Down
2 changes: 1 addition & 1 deletion packages/core-mobile/app/navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export type UpdateContactV2Params = {
}

export type BuyCarefullyParams = {
tokenType: string
provider: string
}

export type ApprovalPopupParams = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { useSelector } from 'react-redux'
import { selectIsBridgeBlocked } from 'store/posthog'
import AnalyticsService from 'services/analytics/AnalyticsService'
import Bridge from 'screens/bridge/Bridge'
import { HallidayWebView } from 'screens/bridge/components/HallidayWebView'

export type BridgeStackParamList = {
[AppNavigation.Bridge.Bridge]: { initialTokenSymbol: string } | undefined
Expand All @@ -27,7 +26,6 @@ export type BridgeStackParamList = {
bridgeTokenList: AssetBalance[] | undefined
}
[AppNavigation.Bridge.HideWarning]: undefined
[AppNavigation.Bridge.Halliday]: undefined
}

const BridgeStack = createStackNavigator<BridgeStackParamList>()
Expand Down Expand Up @@ -68,13 +66,6 @@ function BridgeScreenStack(): JSX.Element {
name={AppNavigation.Bridge.HideWarning}
component={HideTransactionWarningModal}
/>
<BridgeStack.Screen
options={{
...SubHeaderOptions('Halliday')
}}
name={AppNavigation.Bridge.Halliday}
component={HallidayWebView}
/>
</BridgeStack.Group>
</BridgeStack.Navigator>
{isBridgeBlocked && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { SwapContextProvider } from 'contexts/SwapContext/SwapContext'
import { useNavigation } from '@react-navigation/native'
import FeatureBlocked from 'screens/posthog/FeatureBlocked'
import * as Navigation from 'utils/Navigation'
import { AVAX_TOKEN_ID, USDC_TOKEN_ID } from 'consts/swap'

export type SwapStackParamList = {
[AppNavigation.Swap.Swap]:
Expand Down Expand Up @@ -51,8 +52,8 @@ function SwapScreenStack(): JSX.Element {
name={AppNavigation.Swap.Swap}
component={SwapView}
initialParams={{
initialTokenIdFrom: 'AvalancheAVAX', //AVAX
initialTokenIdTo: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E' //USDC
initialTokenIdFrom: AVAX_TOKEN_ID,
initialTokenIdTo: USDC_TOKEN_ID
}}
/>
</SwapStack.Navigator>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import AppNavigation from 'navigation/AppNavigation'
import { BridgeScreenProps } from 'navigation/types'
import React from 'react'
import { useDispatch } from 'react-redux'
import AnalyticsService from 'services/analytics/AnalyticsService'
import { setViewOnce, ViewOnceKey } from 'store/viewOnce'

type NavigationProps = BridgeScreenProps<typeof AppNavigation.Bridge.Bridge>
Expand All @@ -16,7 +17,8 @@ export const HallidayBanner = (): React.JSX.Element => {
const { navigate } = useNavigation<NavigationProps['navigation']>()

const openHalliday = async (): Promise<void> => {
navigate(AppNavigation.Bridge.Halliday)
AnalyticsService.capture('HallidayBuyClicked')
navigate(AppNavigation.Wallet.Halliday)
}

const dismissHallidayBanner = (): void => {
Expand Down
41 changes: 8 additions & 33 deletions packages/core-mobile/app/screens/earn/SmartStakeAmount.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { useNavigation } from '@react-navigation/native'
import { useCChainBalance } from 'hooks/earn/useCChainBalance'
import useStakingParams from 'hooks/earn/useStakingParams'
import AppNavigation from 'navigation/AppNavigation'
import { StakeSetupScreenProps } from 'navigation/types'
import React, { useEffect, useState } from 'react'
import { StyleSheet, View } from 'react-native'
import Spinner from 'components/animation/Spinner'
import { useGetClaimableBalance } from 'hooks/earn/useGetClaimableBalance'
import { TokenUnit } from '@avalabs/core-utils-sdk'
import useCChainNetwork from 'hooks/earn/useCChainNetwork'
import { useGetStuckBalance } from 'hooks/earn/useGetStuckBalance'
import { useHasEnoughAvaxToStake } from 'hooks/earn/useHasEnoughAvaxToStake'
import NotEnoughAvax from './NotEnoughAvax'
import StakingAmount from './StakingAmount'

Expand All @@ -25,38 +20,18 @@ enum BalanceStates {

const SmartStakeAmount = (): React.JSX.Element => {
const { navigate } = useNavigation<ScreenProps['navigation']>()
const { minStakeAmount } = useStakingParams()
const cChainBalance = useCChainBalance()
const { hasEnoughAvax } = useHasEnoughAvaxToStake()
const [balanceState, setBalanceState] = useState(BalanceStates.UNKNOWN)
const claimableBalance = useGetClaimableBalance()
const cChainNetwork = useCChainNetwork()
const stuckBalance = useGetStuckBalance()
const cChainNetworkToken = cChainNetwork?.networkToken

useEffect(() => {
if (cChainBalance.data?.balance !== undefined && cChainNetworkToken) {
const availableAvax = new TokenUnit(
cChainBalance.data.balance,
cChainNetworkToken.decimals,
cChainNetworkToken.symbol
)
.add(claimableBalance ?? 0)
.add(stuckBalance ?? 0)
const notEnoughAvax = availableAvax.lt(minStakeAmount)
if (hasEnoughAvax === undefined) return

if (notEnoughAvax) {
setBalanceState(BalanceStates.INSUFFICIENT)
} else {
setBalanceState(BalanceStates.SUFFICIENT)
}
if (hasEnoughAvax) {
setBalanceState(BalanceStates.SUFFICIENT)
} else {
setBalanceState(BalanceStates.INSUFFICIENT)
}
}, [
cChainBalance?.data?.balance,
minStakeAmount,
stuckBalance,
claimableBalance,
cChainNetworkToken
])
}, [hasEnoughAvax])

const renderNotEnoughAvax = (): React.JSX.Element => {
const navToBuy = (): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,31 @@ import AvaButton from 'components/AvaButton'
import TagSVG from 'components/svg/TagSVG'
import QRSVG from 'components/svg/QRSVG'
import { UI, useIsUIDisabled } from 'hooks/useIsUIDisabled'
import useInAppBrowser from 'hooks/useInAppBrowser'

type NavigationProp = PortfolioScreenProps<
typeof AppNavigation.Portfolio.Portfolio
>['navigation']

const ZeroState = () => {
const ZeroState = (): JSX.Element => {
const buyDisabled = useIsUIDisabled(UI.Buy)
const { openMoonPay } = useInAppBrowser()
const { navigate } = useNavigation<NavigationProp>()

const navigateToReceiveTokens = () => {
const navigateToReceiveTokens = (): void => {
navigate(AppNavigation.Wallet.ReceiveTokens)
}

const navigateToBuy = (): void => {
navigate(AppNavigation.Wallet.Buy)
}

let buttons

if (!buyDisabled) {
buttons = (
<>
<AvaButton.SecondaryMedium
icon={<TagSVG />}
onPress={openMoonPay}
onPress={navigateToBuy}
style={{
flex: 0.5
}}>
Expand Down
Loading
Loading