diff --git a/apps/wallet-mobile/src/assets/img/chart-placeholder.png b/apps/wallet-mobile/src/assets/img/chart-placeholder.png deleted file mode 100644 index 383d949c9f..0000000000 Binary files a/apps/wallet-mobile/src/assets/img/chart-placeholder.png and /dev/null differ diff --git a/apps/wallet-mobile/src/assets/img/chart-placeholder@2x.png b/apps/wallet-mobile/src/assets/img/chart-placeholder@2x.png deleted file mode 100644 index 35590292b7..0000000000 Binary files a/apps/wallet-mobile/src/assets/img/chart-placeholder@2x.png and /dev/null differ diff --git a/apps/wallet-mobile/src/assets/img/chart-placeholder@3x.png b/apps/wallet-mobile/src/assets/img/chart-placeholder@3x.png deleted file mode 100644 index 83bbf8a4cf..0000000000 Binary files a/apps/wallet-mobile/src/assets/img/chart-placeholder@3x.png and /dev/null differ diff --git a/apps/wallet-mobile/src/components/PairedBalance/PairedBalance.tsx b/apps/wallet-mobile/src/components/PairedBalance/PairedBalance.tsx index 56c91435c5..e5a450f392 100644 --- a/apps/wallet-mobile/src/components/PairedBalance/PairedBalance.tsx +++ b/apps/wallet-mobile/src/components/PairedBalance/PairedBalance.tsx @@ -64,7 +64,7 @@ const Price = ({amount, textStyle, ignorePrivacy, hidePrimaryPair}: Props) => { if (isPrivacyActive && !ignorePrivacy) return `${privacyPlaceholder} ${currency}` - if (!isPrimaryToken(amount.info) && tokenPrice == null) return `—— ${currency}` + if (!isPrimaryToken(amount.info) && tokenPrice == null) return `— ${currency}` if (hidePrimaryPair && isPrimaryToken(amount.info) && isPrimaryTokenActive) return '' diff --git a/apps/wallet-mobile/src/features/Portfolio/common/hooks/useGetPortfolioTokenChart.ts b/apps/wallet-mobile/src/features/Portfolio/common/hooks/useGetPortfolioTokenChart.ts index 0ef0471d1c..431878febf 100644 --- a/apps/wallet-mobile/src/features/Portfolio/common/hooks/useGetPortfolioTokenChart.ts +++ b/apps/wallet-mobile/src/features/Portfolio/common/hooks/useGetPortfolioTokenChart.ts @@ -1,12 +1,14 @@ import {isRight} from '@yoroi/common' import {isPrimaryToken} from '@yoroi/portfolio' -import {Chain} from '@yoroi/types' +import {Chain, Portfolio} from '@yoroi/types' import {useQuery, UseQueryOptions} from 'react-query' import {supportedCurrencies, time} from '../../../../kernel/constants' import {useLanguage} from '../../../../kernel/i18n' +import {logger} from '../../../../kernel/logger/logger' import {fetchPtPriceActivity} from '../../../../yoroi-wallets/cardano/usePrimaryTokenActivity' import {useCurrencyPairing} from '../../../Settings/Currency/CurrencyContext' +import {useSelectedNetwork} from '../../../WalletManager/common/hooks/useSelectedNetwork' import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet' import {networkConfigs} from '../../../WalletManager/network-manager/network-manager' import {priceChange} from '../helpers/priceChange' @@ -30,60 +32,6 @@ type TokenChartData = { changeValue: number } -function generateMockChartData(timeInterval: TokenChartInterval = TOKEN_CHART_INTERVAL.DAY): TokenChartData[] { - const dataPoints = 50 - const startValue = 100 - const volatility = 50 - - const startDate = new Date('2024-02-02T15:09:00') - - function getTimeIncrement(interval: TokenChartInterval): number { - switch (interval) { - case TOKEN_CHART_INTERVAL.DAY: - return 60 * 60 * 1000 // 1 hour - case TOKEN_CHART_INTERVAL.WEEK: - return 24 * 60 * 60 * 1000 // 1 day - case TOKEN_CHART_INTERVAL.MONTH: - return 30 * 24 * 60 * 60 * 1000 // 1 month (approximated as 30 days) - case TOKEN_CHART_INTERVAL.SIX_MONTHS: - return 6 * 30 * 24 * 60 * 60 * 1000 // 6 months - case TOKEN_CHART_INTERVAL.YEAR: - return 12 * 30 * 24 * 60 * 60 * 1000 // 1 year (approximated as 360 days) - default: - return 60 * 1000 // Default to 1 minute - } - } - - const increment = getTimeIncrement(timeInterval) - const chartData: TokenChartData[] = [] - - let previousValue = startValue - - for (let i = 0; i < dataPoints; i++) { - const date = new Date(startDate.getTime() + i * increment) - const label = `${date.getDate().toString().padStart(2, '0')}/${(date.getMonth() + 1) - .toString() - .padStart(2, '0')}/${date.getFullYear().toString().substr(-2)} ${date.getHours()}:${date - .getMinutes() - .toString() - .padStart(2, '0')}` - const value = i === 0 ? startValue : previousValue + (Math.random() - 0.5) * volatility - const changeValue = i === 0 ? 0 : value - previousValue - const changePercent = i === 0 ? 0 : (changeValue / previousValue) * 100 - - chartData.push({ - label, - value, - changePercent, - changeValue, - }) - - previousValue = value // Update previousValue for the next iteration - } - - return chartData -} - const getTimestamps = (timeInterval: TokenChartInterval) => { const now = Date.now() const [from, resolution] = { @@ -104,9 +52,9 @@ const ptTicker = networkConfigs[Chain.Network.Mainnet].primaryTokenInfo.ticker export const useGetPortfolioTokenChart = ( timeInterval = TOKEN_CHART_INTERVAL.DAY as TokenChartInterval, options: UseQueryOptions< - TokenChartData[], + TokenChartData[] | null, Error, - TokenChartData[], + TokenChartData[] | null, ['useGetPortfolioTokenChart', string, TokenChartInterval, ReturnType['currency']?] > = {}, ) => { @@ -114,6 +62,9 @@ export const useGetPortfolioTokenChart = ( const { wallet: {balances}, } = useSelectedWallet() + const { + networkManager: {tokenManager}, + } = useSelectedNetwork() const tokenInfo = balances.records.get(tokenId) const {currency} = useCurrencyPairing() const {languageCode} = useLanguage() @@ -135,6 +86,8 @@ export const useGetPortfolioTokenChart = ( if (response.value.data.error) throw new Error(response.value.data.error) const tickers = response.value.data.tickers + if (tickers.length === 0) return null + const validCurrency = currency === ptTicker ? supportedCurrencies.USD : currency ?? supportedCurrencies.USD const initialPrice = tickers[0].prices[validCurrency] @@ -153,7 +106,8 @@ export const useGetPortfolioTokenChart = ( return records } - throw new Error('Failed to fetch token chart data') + logger.error('Failed to fetch token chart data for PT') + return null }, }) @@ -164,10 +118,42 @@ export const useGetPortfolioTokenChart = ( ...options, queryKey: ['useGetPortfolioTokenChart', tokenInfo?.info.id ?? '', timeInterval], queryFn: async () => { - await new Promise((resolve) => setTimeout(resolve, 1)) - return generateMockChartData(timeInterval) + const response = await tokenManager.api.tokenHistory(tokenId, chartIntervalToHistoryPeriod(timeInterval)) + if (isRight(response)) { + const prices = response.value.data.prices + + if (prices.length === 0) return null + + const initialPrice = prices[0].open.toNumber() + const records = prices + .map((price) => { + const value = price.close.toNumber() + if (value === undefined) return undefined + const {changePercent, changeValue} = priceChange(initialPrice, value) + const label = new Date(price.ts).toLocaleString(languageCode, { + dateStyle: 'short', + timeStyle: 'short', + }) + return {label, value, changePercent, changeValue} + }) + .filter(Boolean) as TokenChartData[] + + return records + } + logger.error(`Failed to fetch token chart data for ${tokenId}`) + return null }, }) return tokenInfo && isPrimaryToken(tokenInfo.info) ? ptQuery : otherQuery } + +const chartIntervalToHistoryPeriod = (i: TokenChartInterval): Portfolio.Token.HistoryPeriod => + ({ + [TOKEN_CHART_INTERVAL.DAY]: Portfolio.Token.HistoryPeriod.OneDay, + [TOKEN_CHART_INTERVAL.WEEK]: Portfolio.Token.HistoryPeriod.OneWeek, + [TOKEN_CHART_INTERVAL.MONTH]: Portfolio.Token.HistoryPeriod.OneMonth, + [TOKEN_CHART_INTERVAL.SIX_MONTHS]: Portfolio.Token.HistoryPeriod.SixMonth, + [TOKEN_CHART_INTERVAL.YEAR]: Portfolio.Token.HistoryPeriod.OneYear, + [TOKEN_CHART_INTERVAL.ALL]: Portfolio.Token.HistoryPeriod.All, + }[i] ?? Portfolio.Token.HistoryPeriod.OneDay) diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioDashboard/DashboardTokensList/DashboardTokenItem.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioDashboard/DashboardTokensList/DashboardTokenItem.tsx index 35e5f00441..db49a33b5f 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioDashboard/DashboardTokensList/DashboardTokenItem.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioDashboard/DashboardTokensList/DashboardTokenItem.tsx @@ -48,7 +48,7 @@ export const DashboardTokenItem = ({tokenInfo}: Props) => { - {isMissingPrices ? '—— ' : formatPriceChange(changePercent)}% + {isMissingPrices ? '— ' : formatPriceChange(changePercent)}% diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/ChartPlaceholder.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/ChartPlaceholder.tsx new file mode 100644 index 0000000000..d9ac221f88 --- /dev/null +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/ChartPlaceholder.tsx @@ -0,0 +1,19 @@ +import {useTheme} from '@yoroi/theme' +import React from 'react' +import {useWindowDimensions} from 'react-native' +import Svg, {Path} from 'react-native-svg' + +export const ChartPlaceholder = () => { + const {width} = useWindowDimensions() + const {color} = useTheme() + + return ( + + + + ) +} diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChart.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChart.tsx index 1f7d11afd6..3bb1067dfb 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChart.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChart.tsx @@ -7,6 +7,7 @@ import { TOKEN_CHART_INTERVAL, useGetPortfolioTokenChart, } from '../../../common/hooks/useGetPortfolioTokenChart' +import {ChartPlaceholder} from './ChartPlaceholder' import {PortfolioTokenChartSkeleton} from './PortfolioTokenChartSkeleton' import {TokenChart} from './TokenChart' import {TokenChartToolbar} from './TokenChartToolBar' @@ -29,16 +30,16 @@ export const PortfolioTokenChart = () => { return ( - {isFetching || !data ? ( + {isFetching ? ( ) : ( <> - + {!data ? : } )} @@ -49,6 +50,7 @@ export const PortfolioTokenChart = () => { const useStyles = () => { const {atoms} = useTheme() + const styles = StyleSheet.create({ root: { ...atoms.flex_1, diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChartSkeleton.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChartSkeleton.tsx index 138b6c69f6..c452a0f45c 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChartSkeleton.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/PortfolioTokenChartSkeleton.tsx @@ -1,10 +1,9 @@ import {useTheme} from '@yoroi/theme' import * as React from 'react' -import {Image, StyleSheet, View} from 'react-native' +import {StyleSheet, View} from 'react-native' import SkeletonPlaceholder from 'react-native-skeleton-placeholder' -import ChartPlaceholder from '../../../../../assets/img/chart-placeholder.png' -import {Icon} from '../../../../../components/Icon' +import {ChartPlaceholder} from './ChartPlaceholder' export const PortfolioTokenChartSkeleton = () => { const {color, styles} = useStyles() @@ -19,8 +18,6 @@ export const PortfolioTokenChartSkeleton = () => { - - @@ -28,7 +25,7 @@ export const PortfolioTokenChartSkeleton = () => { - + ) } @@ -51,12 +48,6 @@ const useStyles = () => { ...atoms.align_center, ...atoms.gap_2xs, }, - chartPlaceholder: { - height: 112, - width: '100%', - marginVertical: 16, - resizeMode: 'stretch', - }, }) return {styles, color} as const } diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenPerformance.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenPerformance.tsx index bbe0c21850..b14eaef25b 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenPerformance.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenChart/TokenPerformance.tsx @@ -3,7 +3,6 @@ import {useTheme} from '@yoroi/theme' import * as React from 'react' import {StyleSheet, View} from 'react-native' -import {Icon} from '../../../../../components/Icon' import {Text} from '../../../../../components/Text' import {Tooltip} from '../../../../../components/Tooltip/Tooltip' import {useCurrencyPairing} from '../../../../Settings/Currency/CurrencyContext' @@ -13,7 +12,7 @@ import {useStrings} from '../../../common/hooks/useStrings' import {PnlTag} from '../../../common/PnlTag/PnlTag' type Props = { - tokenPerformance: { + tokenPerformance?: { changePercent: number changeValue: number value: number @@ -27,11 +26,12 @@ export const TokenPerformance = ({tokenPerformance, timeInterval}: Props) => { const {currency, config} = useCurrencyPairing() const variant = React.useMemo(() => { + if (!tokenPerformance) return 'neutral' if (Number(tokenPerformance.changePercent) > 0) return 'success' if (Number(tokenPerformance.changePercent) < 0) return 'danger' return 'neutral' - }, [tokenPerformance.changePercent]) + }, [tokenPerformance]) const intervalLabel = React.useMemo(() => { switch (timeInterval) { @@ -54,25 +54,31 @@ export const TokenPerformance = ({tokenPerformance, timeInterval}: Props) => { return ( - - - {formatPriceChange(tokenPerformance.changePercent)}% - + + + + {!tokenPerformance ? '—' : formatPriceChange(tokenPerformance.changePercent)}% + - {`${formatPriceChange( - tokenPerformance.changeValue, - config.decimals, - )} ${currency}`} - - - - - + {`${ + !tokenPerformance ? '—' : formatPriceChange(tokenPerformance.changeValue, config.decimals) + } ${currency}`} + + - {formatPriceChange(tokenPerformance.value, config.decimals)} + {!tokenPerformance ? ( + + ) : ( + <> + {formatPriceChange(tokenPerformance.value, config.decimals)} - {currency} + {currency} + + )} ) diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenDetailsScreen.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenDetailsScreen.tsx index 43263f40f6..f0c284a3af 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenDetailsScreen.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokenDetails/PortfolioTokenDetailsScreen.tsx @@ -1,4 +1,3 @@ -import {isPrimaryTokenInfo} from '@yoroi/portfolio' import {useTheme} from '@yoroi/theme' import {App} from '@yoroi/types' import * as React from 'react' @@ -30,6 +29,9 @@ const tabs: Record = { overview: 'Overview', transactions: 'Transactions', } + +const HEADER_HEIGHT = 304 + export const PortfolioTokenDetailsScreen = () => { const strings = useStrings() const {activeTab, setActiveTab} = usePortfolioTokenDetailContext() @@ -38,8 +40,6 @@ export const PortfolioTokenDetailsScreen = () => { const {id: tokenId} = usePortfolioTokenDetailParams() const {wallet} = useSelectedWallet() const tokenInfo = wallet.balances.records.get(tokenId)?.info - const isPrimaryToken = isPrimaryTokenInfo(tokenInfo) - const HEADER_HEIGHT = isPrimaryToken ? 304 : 85 // Graph only in PT const {styles} = useStyles(HEADER_HEIGHT) if (!tokenInfo) throwLoggedError(new App.Errors.InvalidState('Token info not found, invalid state')) @@ -100,13 +100,9 @@ export const PortfolioTokenDetailsScreen = () => { - {isPrimaryToken && ( - <> - + - - - )} + {renderTabs} diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokensList/PortfolioWalletTokenList/TokenBalanceItem.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokensList/PortfolioWalletTokenList/TokenBalanceItem.tsx index 923e0f5516..43ae21f7d8 100644 --- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokensList/PortfolioWalletTokenList/TokenBalanceItem.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokensList/PortfolioWalletTokenList/TokenBalanceItem.tsx @@ -53,7 +53,7 @@ export const TokenBalanceItem = ({amount}: Props) => { - {isMissingPrices ? '—— ' : formatPriceChange(changePercent)}% + {isMissingPrices ? '— ' : formatPriceChange(changePercent)}% diff --git a/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/date-to-epoch-info.test.ts b/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/date-to-epoch-info.test.ts index 032bddaf2e..1d313b544e 100644 --- a/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/date-to-epoch-info.test.ts +++ b/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/date-to-epoch-info.test.ts @@ -18,6 +18,7 @@ describe('dateToEpochInfo', () => { start: new Date('2024-05-09T21:44:51.000Z'), end: new Date('2024-05-14T21:44:51.000Z'), era: shelleyEraConfig, + eras: networkManagers[Chain.Network.Mainnet].eras, } const result = convertDateToEpoch(inputDate) @@ -42,6 +43,7 @@ describe('dateToEpochInfo', () => { start: new Date('2017-09-23T21:44:51.000Z'), end: new Date('2017-09-28T21:44:51.000Z'), era: byronEraConfig, + eras: networkManagers[Chain.Network.Mainnet].eras, } const result = convertDateToEpoch(inputDate) @@ -58,6 +60,7 @@ describe('dateToEpochInfo', () => { start: new Date('2020-07-24T21:44:51.000Z'), end: new Date('2020-07-29T21:44:51.000Z'), era: byronEraConfig, + eras: networkManagers[Chain.Network.Mainnet].eras, } const result = convertDateToEpoch(inputDate) @@ -75,6 +78,7 @@ describe('dateToEpochInfo', () => { start: new Date('2020-07-29T21:44:51.000Z'), end: new Date('2020-08-03T21:44:51.000Z'), era: shelleyEraConfig, + eras: networkManagers[Chain.Network.Mainnet].eras, } const result = convertDateToEpoch(inputDate) @@ -91,6 +95,7 @@ describe('dateToEpochInfo', () => { start: new Date('2024-05-11T01:00:00.000Z'), end: new Date('2024-05-16T01:00:00.000Z'), era: shelleyPreprodEraConfig, + eras: networkManagers['preprod'].eras, } const result = convertDateToEpoch(inputDate) diff --git a/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/date-to-epoch-info.ts b/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/date-to-epoch-info.ts index f7031a1102..d4d5fc77ee 100644 --- a/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/date-to-epoch-info.ts +++ b/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/date-to-epoch-info.ts @@ -17,6 +17,7 @@ export function dateToEpochInfo(eras: Network.Manager['eras']) { start: epochStart, end: epochEnd, era: era, + eras: eras, }) } diff --git a/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/epoch-progress.test.ts b/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/epoch-progress.test.ts index 37b686c9e7..c5ace04ceb 100644 --- a/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/epoch-progress.test.ts +++ b/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/epoch-progress.test.ts @@ -15,6 +15,7 @@ describe('epochProgress', () => { expect(result).toEqual({ progress: 100, currentSlot: 431999, + absoluteSlot: 124156799, timeRemaining: {days: 0, hours: 0, minutes: 0, seconds: 1}, }) }) @@ -24,6 +25,7 @@ describe('epochProgress', () => { const result = epochProgress(dateToEpochInfo(networkManagers['mainnet'].eras)(currentDate))(currentDate) expect(result).toEqual({ + absoluteSlot: 123724800, progress: 0, currentSlot: 0, timeRemaining: {days: 5, hours: 0, minutes: 0, seconds: 0}, @@ -35,6 +37,7 @@ describe('epochProgress', () => { const result = epochProgress(dateToEpochInfo(networkManagers['mainnet'].eras)(currentDate))(currentDate) expect(result).toEqual({ + absoluteSlot: 123940800, progress: 50, currentSlot: 216000, timeRemaining: {days: 2, hours: 12, minutes: 0, seconds: 0}, @@ -47,6 +50,7 @@ describe('epochProgress', () => { start: new Date('2024-05-09T21:44:51.000Z'), end: new Date('2024-05-14T21:44:51.000Z'), era: shelleyEraConfig, + eras: networkManagers['mainnet'].eras, } const currentDate = new Date('2022-01-02T00:00:01Z') @@ -56,6 +60,7 @@ describe('epochProgress', () => { expect(result).toEqual({ progress: 100, currentSlot: 432000, + absoluteSlot: 49515310, timeRemaining: {days: 0, hours: 0, minutes: 0, seconds: 0}, }) }) @@ -68,6 +73,7 @@ describe('epochProgress', () => { const result = progressFn(currentDate) expect(result).toEqual({ + absoluteSlot: 61718400, progress: 86.67, currentSlot: 374400, timeRemaining: {days: 0, hours: 16, minutes: 0, seconds: 0}, diff --git a/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/epoch-progress.ts b/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/epoch-progress.ts index d412bce685..a6ef809775 100644 --- a/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/epoch-progress.ts +++ b/apps/wallet-mobile/src/features/WalletManager/network-manager/helpers/epoch-progress.ts @@ -6,11 +6,24 @@ export function epochProgress(epochInfo: Network.EpochInfo) { const epochStart = epochInfo.start const epochEnd = epochInfo.end - if (date > epochEnd || date < epochStart) + let absoluteSlot = 0 + + for (const era of epochInfo.eras) { + if (date >= era.start && (era.end === undefined || date < era.end)) { + absoluteSlot += Math.floor((date.getTime() - era.start.getTime()) / 1e3 / era.slotInSeconds) + break + } + absoluteSlot += Math.floor( + ((era.end?.getTime() ?? date.getTime()) - era.start.getTime()) / 1e3 / era.slotInSeconds, + ) + } + + if (date > epochEnd || date < epochStart) { return freeze( { progress: 100, currentSlot: epochInfo.era.slotsPerEpoch, + absoluteSlot, timeRemaining: { days: 0, hours: 0, @@ -20,6 +33,7 @@ export function epochProgress(epochInfo: Network.EpochInfo) { }, true, ) + } const progress = Math.round( @@ -36,13 +50,14 @@ export function epochProgress(epochInfo: Network.EpochInfo) { return freeze( { - progress: progress, - currentSlot: currentSlot, + progress, + currentSlot, + absoluteSlot, timeRemaining: { - days: days, - hours: hours, - minutes: minutes, - seconds: seconds, + days, + hours, + minutes, + seconds, }, }, true, diff --git a/apps/wallet-mobile/src/yoroi-wallets/cardano/cardano-wallet.ts b/apps/wallet-mobile/src/yoroi-wallets/cardano/cardano-wallet.ts index dae44280f1..52df12db52 100644 --- a/apps/wallet-mobile/src/yoroi-wallets/cardano/cardano-wallet.ts +++ b/apps/wallet-mobile/src/yoroi-wallets/cardano/cardano-wallet.ts @@ -371,12 +371,9 @@ export const makeCardanoWallet = (networkManager: Network.Manager, implementatio addressMode: Wallet.AddressMode }) { if (implementationConfig.features.staking) { - const time = await this.checkServerStatus() - .then(({serverTime}) => serverTime || Date.now()) - .catch(() => Date.now()) const primaryTokenId = this.portfolioPrimaryTokenInfo.id - const absSlotNumber = new BigNumber(this.networkManager.epoch.progress(new Date(time)).currentSlot) + const absSlotNumber = await this.getAbsoluteSlotNumber() const changeAddr = this.getAddressedChangeAddress(addressMode) const addressedUtxos = await this.getAddressedUtxos() const registrationStatus = this.getDelegationStatus().isRegistered @@ -437,11 +434,7 @@ export const makeCardanoWallet = (networkManager: Network.Manager, implementatio const primaryTokenId = this.portfolioPrimaryTokenInfo.id try { - const time = await this.checkServerStatus() - .then(({serverTime}) => serverTime || Date.now()) - .catch(() => Date.now()) - - const absSlotNumber = new BigNumber(this.networkManager.epoch.progress(new Date(time)).currentSlot) + const absSlotNumber = await this.getAbsoluteSlotNumber() const votingPublicKey = await Promise.resolve(Buffer.from(catalystKeyHex, 'hex')) .then((bytes) => CardanoMobile.PrivateKey.fromExtendedBytes(bytes)) .then((key) => key.toPublic()) @@ -528,12 +521,9 @@ export const makeCardanoWallet = (networkManager: Network.Manager, implementatio addressMode: Wallet.AddressMode }): Promise { if (implementationConfig.features.staking) { - const time = await this.checkServerStatus() - .then(({serverTime}) => serverTime || Date.now()) - .catch(() => Date.now()) const primaryTokenId = this.portfolioPrimaryTokenInfo.id - const absSlotNumber = new BigNumber(this.networkManager.epoch.progress(new Date(time)).currentSlot) + const absSlotNumber = await this.getAbsoluteSlotNumber() const changeAddr = this.getAddressedChangeAddress(addressMode) const addressedUtxos = await this.getAddressedUtxos() const accountState = await legacyApi.getAccountState( @@ -589,11 +579,8 @@ export const makeCardanoWallet = (networkManager: Network.Manager, implementatio votingCertificates: CardanoTypes.Certificate[] addressMode: Wallet.AddressMode }) { - const time = await this.checkServerStatus() - .then(({serverTime}) => serverTime || Date.now()) - .catch(() => Date.now()) const primaryTokenId = this.portfolioPrimaryTokenInfo.id - const absSlotNumber = new BigNumber(this.networkManager.epoch.progress(new Date(time)).currentSlot) + const absSlotNumber = await this.getAbsoluteSlotNumber() const changeAddr = this.getAddressedChangeAddress(addressMode) const addressedUtxos = await this.getAddressedUtxos() @@ -758,6 +745,13 @@ export const makeCardanoWallet = (networkManager: Network.Manager, implementatio return Promise.resolve(addressedUtxos) } + private async getAbsoluteSlotNumber() { + const time = await this.checkServerStatus() + .then(({serverTime}) => serverTime || Date.now()) + .catch(() => Date.now()) + return new BigNumber(this.networkManager.epoch.progress(new Date(time)).absoluteSlot) + } + async createUnsignedTx({ entries, addressMode, @@ -767,11 +761,9 @@ export const makeCardanoWallet = (networkManager: Network.Manager, implementatio addressMode: Wallet.AddressMode metadata?: Array }) { - const time = await this.checkServerStatus() - .then(({serverTime}) => serverTime || Date.now()) - .catch(() => Date.now()) const primaryTokenId = this.portfolioPrimaryTokenInfo.id - const absSlotNumber = new BigNumber(this.networkManager.epoch.progress(new Date(time)).currentSlot) + const absSlotNumber = await this.getAbsoluteSlotNumber() + const changeAddr = this.getAddressedChangeAddress(addressMode) const addressedUtxos = await this.getAddressedUtxos() diff --git a/apps/wallet-mobile/translations/messages/src/components/PairedBalance/PairedBalance.json b/apps/wallet-mobile/translations/messages/src/components/PairedBalance/PairedBalance.json index cc74c5db5c..33ff0e463c 100644 --- a/apps/wallet-mobile/translations/messages/src/components/PairedBalance/PairedBalance.json +++ b/apps/wallet-mobile/translations/messages/src/components/PairedBalance/PairedBalance.json @@ -6,12 +6,12 @@ "start": { "line": 107, "column": 22, - "index": 3610 + "index": 3609 }, "end": { "line": 110, "column": 3, - "index": 3742 + "index": 3741 } } ] \ No newline at end of file diff --git a/packages/types/src/network/manager.ts b/packages/types/src/network/manager.ts index fa1807fa04..705cec63c1 100644 --- a/packages/types/src/network/manager.ts +++ b/packages/types/src/network/manager.ts @@ -53,11 +53,13 @@ export type NetworkEpochInfo = { start: Date end: Date era: NetworkEraConfig + eras: ReadonlyArray } export type NetworkEpochProgress = { progress: number currentSlot: number + absoluteSlot: number timeRemaining: { days: number hours: number