diff --git a/.changelog/1265.feature.md b/.changelog/1265.feature.md new file mode 100644 index 0000000000..35ef457a20 --- /dev/null +++ b/.changelog/1265.feature.md @@ -0,0 +1 @@ +Add support for using different tokens on ParaTimes diff --git a/src/app/pages/RuntimeTransactionDetailPage/index.tsx b/src/app/pages/RuntimeTransactionDetailPage/index.tsx index 29e820fd67..5687cd23c6 100644 --- a/src/app/pages/RuntimeTransactionDetailPage/index.tsx +++ b/src/app/pages/RuntimeTransactionDetailPage/index.tsx @@ -26,7 +26,8 @@ import { TransactionLink } from '../../components/Transactions/TransactionLink' import { TransactionEvents } from '../../components/Transactions/TransactionEvents' import { useRequiredScopeParam } from '../../hooks/useScopeParam' import { DashboardLink } from '../ParatimeDashboardPage/DashboardLink' -import { getNameForTicker, getTickerForNetwork, Ticker } from '../../../types/ticker' +import { getNameForTicker, Ticker } from '../../../types/ticker' +import { getTickerForScope } from '../../../config' import { TokenPriceInfo, useTokenPrice } from '../../../coin-gecko/api' import { CurrentFiatValue } from './CurrentFiatValue' import { AddressSwitch, AddressSwitchOption } from '../../components/AddressSwitch' @@ -102,7 +103,7 @@ export const RuntimeTransactionDetailPage: FC = () => { data?.data, ) - const tokenPriceInfo = useTokenPrice(getTickerForNetwork(scope.network)) + const tokenPriceInfo = useTokenPrice(getTickerForScope(scope)) if (!transaction && !isLoading) { throw AppErrors.NotFoundTxHash diff --git a/src/app/pages/RuntimeTransactionsPage/index.tsx b/src/app/pages/RuntimeTransactionsPage/index.tsx index 4419d2f352..6b9ab1666b 100644 --- a/src/app/pages/RuntimeTransactionsPage/index.tsx +++ b/src/app/pages/RuntimeTransactionsPage/index.tsx @@ -15,7 +15,7 @@ import { TableLayout, TableLayoutButton } from '../../components/TableLayoutButt import { RuntimeTransactionDetailView } from '../RuntimeTransactionDetailPage' import { useRequiredScopeParam } from '../../hooks/useScopeParam' import { useTokenPrice } from '../../../coin-gecko/api' -import { getTickerForNetwork } from '../../../types/ticker' +import { getTickerForScope } from '../../../config' import { VerticalList } from '../../components/VerticalList' const limit = NUMBER_OF_ITEMS_ON_SEPARATE_PAGE @@ -35,7 +35,7 @@ export const RuntimeTransactionsPage: FC = () => { // we should call useGetConsensusTransactions() } - const tokenPriceInfo = useTokenPrice(getTickerForNetwork(scope.network)) + const tokenPriceInfo = useTokenPrice(getTickerForScope(scope)) useEffect(() => { if (!isMobile) { diff --git a/src/app/pages/SearchResultsPage/SearchResultsList.tsx b/src/app/pages/SearchResultsPage/SearchResultsList.tsx index 4eb4945fd3..2da0f092b5 100644 --- a/src/app/pages/SearchResultsPage/SearchResultsList.tsx +++ b/src/app/pages/SearchResultsPage/SearchResultsList.tsx @@ -21,6 +21,7 @@ import { AllTokenPrices } from '../../../coin-gecko/api' import { ResultListFrame } from './ResultListFrame' import { TokenDetails } from '../../components/Tokens/TokenDetails' import { ProposalDetailView } from '../ProposalDetailsPage' +import { getTickerForScope } from '../../../config' /** * Component for displaying a list of search results @@ -70,7 +71,7 @@ export const SearchResultsList: FC<{ )} @@ -86,7 +87,7 @@ export const SearchResultsList: FC<{ isLoading={false} isError={false} account={item} - tokenPriceInfo={tokenPrices[item.network]} + tokenPriceInfo={tokenPrices[getTickerForScope(item)]} showLayer={true} /> )} @@ -102,7 +103,7 @@ export const SearchResultsList: FC<{ isLoading={false} isError={false} account={item} - tokenPriceInfo={tokenPrices[item.network]} + tokenPriceInfo={tokenPrices[getTickerForScope(item)]} showLayer={true} /> )} diff --git a/src/app/pages/SearchResultsPage/__tests__/SearchResultsList.test.tsx b/src/app/pages/SearchResultsPage/__tests__/SearchResultsList.test.tsx index e726877c43..cf9ef0771f 100644 --- a/src/app/pages/SearchResultsPage/__tests__/SearchResultsList.test.tsx +++ b/src/app/pages/SearchResultsPage/__tests__/SearchResultsList.test.tsx @@ -8,6 +8,7 @@ import { } from '../../../utils/test-fixtures' import { Network } from '../../../../types/network' import { SearchResultsList } from '../SearchResultsList' +import { Ticker } from '../../../../types/ticker' describe('SearchResultsView', () => { beforeEach(() => { @@ -24,13 +25,13 @@ describe('SearchResultsView', () => { { title="test search" networkForTheme={Network.mainnet} tokenPrices={{ - [Network.mainnet]: { + [Ticker.ROSE]: { isLoading: false, isFree: false, price: 1, hasUsedCoinGecko: true, }, - [Network.testnet]: { + [Ticker.TEST]: { isLoading: false, isFree: true, hasUsedCoinGecko: false, diff --git a/src/coin-gecko/api.ts b/src/coin-gecko/api.ts index 7e160aad64..9e6afb431f 100644 --- a/src/coin-gecko/api.ts +++ b/src/coin-gecko/api.ts @@ -1,8 +1,8 @@ import axios from 'axios' import type { AxiosResponse, AxiosError } from 'axios' import { useQuery } from '@tanstack/react-query' -import { getTickerForNetwork, NativeTicker, Ticker } from '../types/ticker' -import { Network } from '../types/network' +import { NativeTicker, Ticker } from '../types/ticker' +import { getTickerForScope } from '../config' import { RouteUtils } from '../app/utils/route-utils' import { exhaustedTypeWarning } from '../types/errors' @@ -78,12 +78,15 @@ export const useTokenPrice = (ticker: NativeTicker): TokenPriceInfo => { } } -export type AllTokenPrices = Record +export type AllTokenPrices = Record export const useAllTokenPrices = (): AllTokenPrices => { const results = {} as any - // The list of networks will never change on the run, so we can do this - // eslint-disable-next-line react-hooks/rules-of-hooks - RouteUtils.getEnabledNetworks().forEach(net => (results[net] = useTokenPrice(getTickerForNetwork(net)))) + RouteUtils.getEnabledScopes().forEach(scope => { + const ticker = getTickerForScope(scope) + // The list of networks will never change on the run, so we can do this + // eslint-disable-next-line react-hooks/rules-of-hooks + results[ticker] = useTokenPrice(ticker) + }) return results } diff --git a/src/config.ts b/src/config.ts index fa6ce54c40..751d3356a1 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,5 +1,7 @@ // eslint-disable-next-line no-restricted-imports -import { Layer } from './oasis-nexus/generated/api' // We get this from the generated code to avoid circular imports +import { Layer } from './oasis-nexus/generated/api' +import { getTickerForNetwork, NativeTicker, Ticker } from './types/ticker' +import { SearchScope } from './types/searchScope' // We get this from the generated code to avoid circular imports export const consensusDecimals = 9 @@ -8,6 +10,13 @@ type LayerNetwork = { address: string | undefined blockGasLimit: number | undefined runtimeId: string | undefined + + /** + * What do we call the native ticker on this layer? + * + * (If not given, the network's default token will be used.) + */ + ticker?: NativeTicker } type LayerConfig = { @@ -164,3 +173,12 @@ const stableDeploys = [...deploys.production, deploys.staging] export const isStableDeploy = stableDeploys.some(url => window.location.origin === url) export const getAppTitle = () => process.env.REACT_APP_META_TITLE + +export const getTickerForScope = ({ network, layer }: SearchScope): NativeTicker => { + const networkDefault = getTickerForNetwork(network) + + if (layer !== Layer.consensus) { + return paraTimesConfig[layer][network].ticker ?? networkDefault + } + return networkDefault +} diff --git a/src/oasis-nexus/api.ts b/src/oasis-nexus/api.ts index 68595930f8..feef24e4a0 100644 --- a/src/oasis-nexus/api.ts +++ b/src/oasis-nexus/api.ts @@ -1,7 +1,7 @@ /** @file Wrappers around generated API */ import axios, { AxiosResponse } from 'axios' -import { consensusDecimals, paraTimesConfig } from '../config' +import { consensusDecimals, getTickerForScope, paraTimesConfig } from '../config' import * as generated from './generated/api' import { QueryKey, UseQueryOptions, UseQueryResult } from '@tanstack/react-query' import { @@ -176,7 +176,7 @@ export const useGetRuntimeTransactions: typeof generated.useGetRuntimeTransactio params?, options?, ) => { - const ticker = getTickerForNetwork(network) + const ticker = getTickerForScope({ network, layer: runtime }) return generated.useGetRuntimeTransactions(network, runtime, params, { ...options, request: { @@ -248,7 +248,7 @@ export const useGetRuntimeTransactionsTxHash: typeof generated.useGetRuntimeTran ) => { // Sometimes we will call this with an undefined txHash, so we must be careful here. const actualHash = txHash?.startsWith('0x') ? txHash.substring(2) : txHash - const ticker = getTickerForNetwork(network) + const ticker = getTickerForScope({ network, layer: runtime }) return generated.useGetRuntimeTransactionsTxHash(network, runtime, actualHash, { ...options, request: { @@ -317,7 +317,7 @@ export const useGetRuntimeAccountsAddress: typeof generated.useGetRuntimeAccount const oasisAddress = useTransformToOasisAddress(address) - const ticker = getTickerForNetwork(network) + const ticker = getTickerForScope({ network, layer: runtime }) const query = generated.useGetRuntimeAccountsAddress(network, runtime, oasisAddress!, { ...options, query: { @@ -752,7 +752,7 @@ export const useGetRuntimeEvents: typeof generated.useGetRuntimeEvents = ( event.body.amount.Amount, paraTimesConfig[runtime].decimals, ), - Denomination: getTickerForNetwork(network), + Denomination: getTickerForScope({ network, layer: runtime }), } : event.body.amount, },