diff --git a/packages/desktop/public/index.html b/packages/desktop/public/index.html index bd31dd853c..aed3a5e923 100644 --- a/packages/desktop/public/index.html +++ b/packages/desktop/public/index.html @@ -8,7 +8,7 @@ content=" default-src 'self'; connect-src 'self' https://* wss://relay.walletconnect.com; - img-src 'self' https://tideprotocol.infura-ipfs.io data:; + img-src 'self' data: https:; base-uri 'self'; form-action 'self'; frame-src 'self' https://verify.walletconnect.org https://verify.walletconnect.com; diff --git a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AssetPillsForActivity.svelte b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AssetPillsForActivity.svelte index be93a4ba57..702f90167c 100644 --- a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AssetPillsForActivity.svelte +++ b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AssetPillsForActivity.svelte @@ -10,6 +10,7 @@ import { EvmActivityType } from '@core/activity/enums/evm' import { NftStandard } from '@core/nfts/enums' import { convertCamelCaseToPhrase } from '@core/utils/string' + import { ConfirmationPill } from '@ui' export let activity: Activity @@ -17,13 +18,13 @@ let standardPill = '' $: activity, setPills() - function setPills() { + function setPills(): void { if (activity.namespace === NetworkNamespace.Stardust) { if (activity.type === StardustActivityType.Basic) { if (activity.tokenTransfer && activity.tokenTransfer?.tokenId !== BASE_TOKEN_ID) { const token = getTokenFromActivity(activity) typePill = 'token' - standardPill = token.standard + standardPill = token?.standard ?? '' } else { typePill = 'baseCoin' standardPill = '' @@ -80,5 +81,8 @@ {standardPill} {/if} + {#if activity.namespace === NetworkNamespace.Evm} + + {/if} {/if} diff --git a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/row-sections/ActivityAssetSection.svelte b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/row-sections/ActivityAssetSection.svelte index a42081e963..33ff5e9df4 100644 --- a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/row-sections/ActivityAssetSection.svelte +++ b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/row-sections/ActivityAssetSection.svelte @@ -59,7 +59,7 @@ {:else if token} - {:else if showNft} + {:else if showNft && nft} {:else if activity.type === EvmActivityType.ContractCall} {/if} {#if selectedTab.key === PopupTab.Transaction} - + {:else if selectedTab.key === PopupTab.NftMetadata && nft} {:else if selectedTab.key === PopupTab.SmartContract && (activity.type === EvmActivityType.ContractCall || activity.type === EvmActivityType.TokenTransfer || activity.type === EvmActivityType.TokenMinting)} diff --git a/packages/shared/src/components/activities/evm/info/EvmGenericInformation.svelte b/packages/shared/src/components/activities/evm/info/EvmGenericInformation.svelte index 7e576cda3b..3640eea546 100644 --- a/packages/shared/src/components/activities/evm/info/EvmGenericInformation.svelte +++ b/packages/shared/src/components/activities/evm/info/EvmGenericInformation.svelte @@ -1,23 +1,20 @@ @@ -28,7 +25,7 @@ slot: { component: NetworkLabel, props: { - networkId: destinationNetworkId, + networkId: activity.destinationNetworkId, }, }, }, @@ -44,5 +41,12 @@ key: localize('general.transactionFee'), value: formattedTransactionFee, }, + { + key: localize('general.status'), + value: + activity.inclusionState === InclusionState.Confirmed + ? localize('general.confirmed') + : localize('general.pending'), + }, ]} /> diff --git a/packages/shared/src/components/pills/ConfirmationPill.svelte b/packages/shared/src/components/pills/ConfirmationPill.svelte new file mode 100644 index 0000000000..7b8e7ee9bc --- /dev/null +++ b/packages/shared/src/components/pills/ConfirmationPill.svelte @@ -0,0 +1,31 @@ + + +{#if activity.inclusionState === InclusionState.Pending} +
+ + {localize('general.pending')} + +
+{/if} diff --git a/packages/shared/src/components/pills/index.ts b/packages/shared/src/components/pills/index.ts index 09044fb0ea..407eac1e67 100644 --- a/packages/shared/src/components/pills/index.ts +++ b/packages/shared/src/components/pills/index.ts @@ -7,3 +7,4 @@ export { default as AsyncStatusPill } from './AsyncStatusPill.svelte' export { default as NetworkStatusPill } from './NetworkStatusPill.svelte' export { default as NetworkTypePill } from './NetworkTypePill.svelte' export { default as NftStandardPill } from './NftStandardPill.svelte' +export { default as ConfirmationPill } from './ConfirmationPill.svelte' diff --git a/packages/shared/src/lib/core/activity/enums/activity-status.enum.ts b/packages/shared/src/lib/core/activity/enums/activity-status.enum.ts deleted file mode 100644 index 704d2cac8c..0000000000 --- a/packages/shared/src/lib/core/activity/enums/activity-status.enum.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum ActivityStatus { - InProgress = 'inProgress', - Pending = 'pending', - Confirmed = 'confirmed', - Conflict = 'conflict', - Failed = 'failed', -} diff --git a/packages/shared/src/lib/core/activity/enums/index.ts b/packages/shared/src/lib/core/activity/enums/index.ts index 9f77ddf2d4..d63757569f 100644 --- a/packages/shared/src/lib/core/activity/enums/index.ts +++ b/packages/shared/src/lib/core/activity/enums/index.ts @@ -1,6 +1,5 @@ export * from './activity-action.enum' export * from './activity-direction.enum' -export * from './activity-status.enum' export * from './activity-type-filter-option.enum' export * from './inclusion-state.enum' diff --git a/packages/shared/src/lib/core/activity/stores/all-account-activities.store.ts b/packages/shared/src/lib/core/activity/stores/all-account-activities.store.ts index 91f6462134..b1b3c733dc 100644 --- a/packages/shared/src/lib/core/activity/stores/all-account-activities.store.ts +++ b/packages/shared/src/lib/core/activity/stores/all-account-activities.store.ts @@ -1,5 +1,5 @@ import { get, writable } from 'svelte/store' -import { AsyncData, BaseStardustActivity, Activity } from '../types' +import { AsyncData, BaseStardustActivity, Activity, EvmActivity, BaseEvmActivity } from '../types' import { NetworkNamespace } from '@core/network' export const allAccountActivities = writable<{ [accountIndex: number]: Activity[] }>({}) @@ -35,7 +35,13 @@ export function setAccountActivities(accountIndex: number, accountActivities: Ac }) } -export function getActivityByTransactionId(accountIndex: number, transactionId: string): Activity | undefined { +export function getActivityByTransactionId( + accountIndex: number, + transactionId: string | undefined +): Activity | undefined { + if (!transactionId) { + return + } return get(allAccountActivities)?.[accountIndex]?.find((_activity) => _activity?.transactionId === transactionId) } @@ -97,6 +103,25 @@ export function updateAsyncDataByTransactionId( }) } +export function updateEvmActivity( + accountIndex: number, + transactionHash: string, + partialActivity: Partial +): void { + allAccountActivities.update((state) => { + const activity = state[accountIndex]?.find( + (_activity) => _activity.namespace === NetworkNamespace.Evm && _activity?.transactionId === transactionHash + ) as EvmActivity + + if (!activity) { + return state + } + + Object.assign(activity, partialActivity) + return state + }) +} + export function clearAccountActivities(): void { allAccountActivities.set({}) } diff --git a/packages/shared/src/lib/core/activity/utils/evm/generateBaseEvmActivity.ts b/packages/shared/src/lib/core/activity/utils/evm/generateBaseEvmActivity.ts index d3e69eae49..9e518136fc 100644 --- a/packages/shared/src/lib/core/activity/utils/evm/generateBaseEvmActivity.ts +++ b/packages/shared/src/lib/core/activity/utils/evm/generateBaseEvmActivity.ts @@ -5,19 +5,10 @@ import { MILLISECONDS_PER_SECOND } from '@core/utils/constants' import { getSubjectFromAddress, isSubjectInternal } from '@core/wallet' import { ActivityAction, ActivityDirection, InclusionState } from '../../enums' import { BaseEvmActivity } from '../../types' -import type { BigIntLike } from '@ethereumjs/util' +import { LocalEvmTransaction } from '@core/transactions' export async function generateBaseEvmActivity( - transaction: { - transactionHash: string - from: string - recipient: string - gasUsed: number - blockNumber: number - estimatedGas?: bigint - gasPrice?: BigIntLike - timestamp?: number - }, + transaction: LocalEvmTransaction, evmNetwork: IEvmNetwork, account: IAccountState ): Promise { @@ -28,7 +19,7 @@ export async function generateBaseEvmActivity( : ActivityDirection.Outgoing const sender = getSubjectFromAddress(transaction.from, networkId) - const recipient = getSubjectFromAddress(transaction.recipient, networkId) + const recipient = getSubjectFromAddress(transaction.recipient ?? transaction.to, networkId) const subject = direction === ActivityDirection.Outgoing ? recipient : sender const isInternal = isSubjectInternal(recipient) @@ -38,6 +29,10 @@ export async function generateBaseEvmActivity( // https://discord.com/channels/397872799483428865/930642258427019354/1168854453005332490 const gasUsed = transaction.gasUsed || transaction.estimatedGas const transactionFee = transaction.gasPrice ? calculateGasFee(gasUsed, transaction.gasPrice) : undefined + const inclusionState = + Number(transaction.confirmations) >= evmNetwork.blocksUntilConfirmed + ? InclusionState.Confirmed + : InclusionState.Pending return { namespace: NetworkNamespace.Evm, @@ -50,7 +45,7 @@ export async function generateBaseEvmActivity( // transaction information transactionId: transaction.transactionHash, time: new Date(timestamp), - inclusionState: InclusionState.Confirmed, + inclusionState, // sender / recipient information sourceNetworkId: networkId, diff --git a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivitiesFromEvmChains.ts b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivitiesFromEvmChains.ts index e4a1831fd7..91a1cfb192 100644 --- a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivitiesFromEvmChains.ts +++ b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivitiesFromEvmChains.ts @@ -1,8 +1,10 @@ import { IAccountState } from '@core/account' -import { getEvmNetworks } from '@core/network' +import { FAILED_CONFIRMATION, getEvmNetworks, IEvmNetwork } from '@core/network' import { getPersistedTransactionsForChain } from '@core/transactions/stores' import { EvmActivity } from '../../types' import { generateEvmActivityFromPersistedTransaction } from './generateEvmActivityFromPersistedTransaction' +import { LocalEvmTransaction } from '@core/transactions' +import { startEvmConfirmationPoll } from '@core/wallet' export async function generateEvmActivitiesFromEvmChains( profileId: string, @@ -13,6 +15,11 @@ export async function generateEvmActivitiesFromEvmChains( for (const evmNetwork of getEvmNetworks()) { const persistedTransactions = getPersistedTransactionsForChain(profileId, account.index, evmNetwork) for (const persistedTransaction of persistedTransactions) { + const { local } = persistedTransaction + if (local) { + updateConfirmationsForEvmTransactions(evmNetwork, local, account.index, profileId) + } + try { const activity = await generateEvmActivityFromPersistedTransaction( persistedTransaction, @@ -30,3 +37,22 @@ export async function generateEvmActivitiesFromEvmChains( return activities } + +function updateConfirmationsForEvmTransactions( + evmNetwork: IEvmNetwork, + transaction: LocalEvmTransaction, + accountIndex: number, + profileId: string +): void { + if (transaction.confirmations === FAILED_CONFIRMATION) { + return + } + + if (!transaction?.confirmations || transaction.confirmations < evmNetwork.blocksUntilConfirmed) { + try { + startEvmConfirmationPoll(transaction, evmNetwork, accountIndex, profileId) + } catch (error) { + console.error(error) + } + } +} diff --git a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromBlockscoutTransaction.ts b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromBlockscoutTransaction.ts index b3abe6e15e..e28227e819 100644 --- a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromBlockscoutTransaction.ts +++ b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromBlockscoutTransaction.ts @@ -127,20 +127,20 @@ async function generateBaseEvmActivityFromBlockscoutTransaction( evmNetwork: IEvmNetwork, account: IAccountState ): Promise { - const baseActivity = await generateBaseEvmActivity( - { - recipient: blockscoutTransaction.to.hash.toLowerCase(), - from: blockscoutTransaction.from.hash.toLowerCase(), - gasUsed: Number(blockscoutTransaction.gas_used), - estimatedGas: localTransaction?.estimatedGas ? BigInt(localTransaction.estimatedGas) : undefined, - gasPrice: blockscoutTransaction.gas_price, - transactionHash: blockscoutTransaction.hash, - timestamp: new Date(blockscoutTransaction.timestamp).getTime(), - blockNumber: blockscoutTransaction.block, - }, - evmNetwork, - account - ) + const newLocalTransaction: LocalEvmTransaction = { + recipient: blockscoutTransaction.to.hash.toLowerCase(), + from: blockscoutTransaction.from.hash.toLowerCase(), + gasUsed: Number(blockscoutTransaction.gas_used), + gasPrice: blockscoutTransaction.gas_price, + transactionHash: blockscoutTransaction.hash, + timestamp: new Date(blockscoutTransaction.timestamp).getTime(), + blockNumber: blockscoutTransaction.block, + confirmations: blockscoutTransaction.confirmations, + status: localTransaction?.status ?? false, + transactionIndex: localTransaction?.transactionIndex ?? 0, + to: localTransaction?.to ?? blockscoutTransaction.to.hash.toLowerCase(), + } + const baseActivity = await generateBaseEvmActivity(newLocalTransaction, evmNetwork, account) if (blockscoutTransaction.to.is_contract) { baseActivity.recipient = { diff --git a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromLocalEvmTransaction.ts b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromLocalEvmTransaction.ts index a07fb558d9..096cede94f 100644 --- a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromLocalEvmTransaction.ts +++ b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromLocalEvmTransaction.ts @@ -22,22 +22,8 @@ export async function generateEvmActivityFromLocalEvmTransaction( account: IAccountState ): Promise { if (!transaction.data) { - const { to, from, gasUsed, estimatedGas, gasPrice, transactionHash, timestamp, blockNumber } = transaction // i.e must be a coin transfer - const baseActivity = await generateBaseEvmActivity( - { - recipient: to?.toString().toLowerCase(), - from: from?.toString().toLowerCase(), - gasUsed: Number(gasUsed), - estimatedGas: estimatedGas ? BigInt(estimatedGas) : undefined, - gasPrice: gasPrice ?? undefined, - transactionHash, - timestamp, - blockNumber, - }, - evmNetwork, - account - ) + const baseActivity = await generateBaseEvmActivity(transaction, evmNetwork, account) return { ...baseActivity, @@ -57,21 +43,8 @@ export async function generateEvmActivityFromLocalEvmTransaction( return } - const { to, from, gasUsed, estimatedGas, gasPrice, transactionHash, timestamp, blockNumber } = transaction - let baseActivity = await generateBaseEvmActivity( - { - recipient: parsedData.recipientAddress ?? to?.toString().toLowerCase(), - from: from?.toString().toLowerCase(), - gasUsed: Number(gasUsed), - estimatedGas: estimatedGas ? BigInt(estimatedGas) : undefined, - gasPrice: gasPrice ?? undefined, - transactionHash, - timestamp, - blockNumber, - }, - evmNetwork, - account - ) + transaction.recipient = parsedData.recipientAddress ?? transaction.to?.toString().toLowerCase() + let baseActivity = await generateBaseEvmActivity(transaction, evmNetwork, account) baseActivity = { ...baseActivity, @@ -81,7 +54,7 @@ export async function generateEvmActivityFromLocalEvmTransaction( rawData: String(transaction.data ?? ''), contract: { type: SubjectType.SmartContract, - address: to?.toString().toLowerCase(), + address: transaction.to?.toString().toLowerCase(), name: '', verified: false, }, diff --git a/packages/shared/src/lib/core/network/classes/evm-network.class.ts b/packages/shared/src/lib/core/network/classes/evm-network.class.ts index ff9ebfbc59..71fd387c80 100644 --- a/packages/shared/src/lib/core/network/classes/evm-network.class.ts +++ b/packages/shared/src/lib/core/network/classes/evm-network.class.ts @@ -1,6 +1,10 @@ import { getAddressFromAccountForNetwork, IAccountState } from '@core/account' import { IError } from '@core/error/interfaces' -import { NETWORK_STATUS_POLL_INTERVAL } from '@core/network/constants' +import { + AVERAGE_BLOCK_TIME_IN_SECONDS, + ETHEREUM_CONFIRMATION_THRESHOLD, + NETWORK_STATUS_POLL_INTERVAL, +} from '@core/network/constants' import { getPersistedErc721NftsForNetwork, updateErc721NftsOwnership } from '@core/nfts/actions' import { Nft } from '@core/nfts/interfaces' import { buildNftFromPersistedErc721Nft } from '@core/nfts/utils' @@ -33,6 +37,8 @@ export class EvmNetwork implements IEvmNetwork { public readonly explorerUrl: string | undefined public readonly rpcEndpoint: string public readonly type: EvmNetworkType = NetworkType.Evm + public readonly averageBlockTimeInSeconds: number = AVERAGE_BLOCK_TIME_IN_SECONDS + public readonly blocksUntilConfirmed: number = ETHEREUM_CONFIRMATION_THRESHOLD public health: Writable = writable(NetworkHealth.Operational) public statusPoll: number | undefined diff --git a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts index 55e171e808..6033116299 100644 --- a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts +++ b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts @@ -15,6 +15,7 @@ import { Converter } from '@core/utils' import { BigIntLike } from '@ethereumjs/util' import { IIscChain, IIscChainConfiguration, IIscChainMetadata } from '../interfaces' import { NftStandard } from '@core/nfts/enums' +import { ISC_CONFIRMATION_THRESHOLD } from '@core/network/constants' export class IscChain extends EvmNetwork implements IIscChain { private readonly _chainApi: string @@ -25,6 +26,7 @@ export class IscChain extends EvmNetwork implements IIscChain { public readonly apiEndpoint: string public readonly aliasAddress: string public readonly type = NetworkType.Isc + public readonly blocksUntilConfirmed = ISC_CONFIRMATION_THRESHOLD constructor(chainConfiguration: IIscChainConfiguration) { const { rpcEndpoint, aliasAddress, apiEndpoint } = chainConfiguration diff --git a/packages/shared/src/lib/core/network/constants/average-block-time-in-seconds.constant.ts b/packages/shared/src/lib/core/network/constants/average-block-time-in-seconds.constant.ts new file mode 100644 index 0000000000..5ca9412334 --- /dev/null +++ b/packages/shared/src/lib/core/network/constants/average-block-time-in-seconds.constant.ts @@ -0,0 +1 @@ +export const AVERAGE_BLOCK_TIME_IN_SECONDS = 12 diff --git a/packages/shared/src/lib/core/network/constants/confirmation-threshold.constant.ts b/packages/shared/src/lib/core/network/constants/confirmation-threshold.constant.ts new file mode 100644 index 0000000000..08fb97dca2 --- /dev/null +++ b/packages/shared/src/lib/core/network/constants/confirmation-threshold.constant.ts @@ -0,0 +1,4 @@ +export const ETHEREUM_CONFIRMATION_THRESHOLD = 6 +export const ISC_CONFIRMATION_THRESHOLD = 0 + +export const FAILED_CONFIRMATION = -1 diff --git a/packages/shared/src/lib/core/network/constants/index.ts b/packages/shared/src/lib/core/network/constants/index.ts index 68e176a217..054acfa23b 100644 --- a/packages/shared/src/lib/core/network/constants/index.ts +++ b/packages/shared/src/lib/core/network/constants/index.ts @@ -2,6 +2,8 @@ * CAUTION: If this file is exported in alphabetical order, it will * break the dependency flow. It MUST be exported first! */ +export * from './average-block-time-in-seconds.constant' +export * from './confirmation-threshold.constant' export * from './default-coin-type.constant' export * from './default-bech32-hrp.constant' export * from './default-base-token.constant' diff --git a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts index f3f915390b..b5075f0ca0 100644 --- a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts @@ -31,6 +31,9 @@ export interface IEvmNetwork extends IBaseNetwork, IBaseNetworkMetadata { provider: Web3Provider + averageBlockTimeInSeconds: number + blocksUntilConfirmed: number + getRequiredGasPrice(): Promise getGasPrices(): Promise getBalance(account: IAccountState): Promise diff --git a/packages/shared/src/lib/core/transactions/stores/transactions.store.ts b/packages/shared/src/lib/core/transactions/stores/transactions.store.ts index 24c45c7150..03ef82fc60 100644 --- a/packages/shared/src/lib/core/transactions/stores/transactions.store.ts +++ b/packages/shared/src/lib/core/transactions/stores/transactions.store.ts @@ -27,6 +27,18 @@ export function getPersistedTransactionsForChain( return Object.values(get(persistedTransactions)?.[profileId]?.[accountIndex]?.[networkId] ?? {}) ?? [] } +export function getPersistedTransaction(transactionId: string | undefined): PersistedTransaction | undefined { + if (!transactionId) { + return undefined + } + const allTransactions = Object.values(get(persistedTransactions)).flatMap((profile) => + Object.values(profile).flatMap((account) => + Object.values(account).flatMap((network) => Object.values(network ?? {})) + ) + ) + return allTransactions.find((transaction) => transaction.local?.transactionHash === transactionId) +} + export function addLocalTransactionToPersistedTransaction( profileId: string, accountIndex: number, diff --git a/packages/shared/src/lib/core/transactions/types/local-evm-transaction.interface.ts b/packages/shared/src/lib/core/transactions/types/local-evm-transaction.interface.ts index 3b94ae2fa3..8a53fb5491 100644 --- a/packages/shared/src/lib/core/transactions/types/local-evm-transaction.interface.ts +++ b/packages/shared/src/lib/core/transactions/types/local-evm-transaction.interface.ts @@ -12,4 +12,6 @@ export type LocalEvmTransaction = Omit { + const currentBlockNumber = await evmNetwork.provider.eth.getBlockNumber() + let confirmations = Number(BigInt(currentBlockNumber) - BigInt(blockNumber)) + + let inclusionState = InclusionState.Pending + if (confirmations >= evmNetwork.blocksUntilConfirmed) { + try { + await evmNetwork.provider.eth.getTransactionReceipt(transactionHash) + inclusionState = InclusionState.Confirmed + } catch (error) { + inclusionState = InclusionState.Conflicting + confirmations = FAILED_CONFIRMATION + } finally { + addLocalTransactionToPersistedTransaction(profileId, accountIndex, evmNetwork.id, [ + { ...transaction, confirmations }, + ]) + updateEvmActivity(accountIndex, transactionHash, { inclusionState }) + clearInterval(interval) + } + } else { + updateEvmActivity(accountIndex, transactionHash, { inclusionState }) + } + } + + const interval = setInterval(() => void poll(), pollInterval) +} diff --git a/packages/shared/src/locales/en.json b/packages/shared/src/locales/en.json index a475917af7..b087b9f3c7 100644 --- a/packages/shared/src/locales/en.json +++ b/packages/shared/src/locales/en.json @@ -1736,7 +1736,8 @@ "slow": "Slow", "average": "Average", "fast": "Fast", - "spender": "Spender" + "spender": "Spender", + "status": "Status" }, "filters":{ "title": "Filters",