diff --git a/mocks/txs/tx.ts b/mocks/txs/tx.ts index 803eb0b9e0..d6abe3c80d 100644 --- a/mocks/txs/tx.ts +++ b/mocks/txs/tx.ts @@ -270,6 +270,47 @@ export const l2tx: Transaction = { l1_fee: '1584574188135760', }; +export const stabilityTx: Transaction = { + ...base, + stability_fee: { + dapp_address: { + hash: '0xDc2B93f3291030F3F7a6D9363ac37757f7AD5C43', + implementation_name: null, + is_contract: false, + is_verified: null, + name: null, + private_tags: [], + public_tags: [], + watchlist_names: [], + }, + dapp_fee: '34381250000000', + token: { + address: '0xDc2B93f3291030F3F7a6D9363ac37757f7AD5C43', + circulating_market_cap: null, + decimals: '18', + exchange_rate: '123.567', + holders: '92', + icon_url: null, + name: 'Stability Gas', + symbol: 'GAS', + total_supply: '10000000000000000000000000', + type: 'ERC-20', + }, + total_fee: '68762500000000', + validator_address: { + hash: '0x1432997a4058acbBe562F3c1E79738c142039044', + implementation_name: null, + is_contract: false, + is_verified: null, + name: null, + private_tags: [], + public_tags: [], + watchlist_names: [], + }, + validator_fee: '34381250000000', + }, +}; + export const base2 = { ...base, hash: '0x02d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3193', diff --git a/playwright/utils/configs.ts b/playwright/utils/configs.ts index a2dd7943d8..387a1de562 100644 --- a/playwright/utils/configs.ts +++ b/playwright/utils/configs.ts @@ -38,3 +38,9 @@ export const viewsEnvs = { ], }, }; + +export const stabilityEnvs = [ + { name: 'NEXT_PUBLIC_VIEWS_ADDRESS_HIDDEN_VIEWS', value: '["top_accounts"]' }, + { name: 'NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS', value: '["value","fee_currency","gas_price","gas_fees","burnt_fees"]' }, + { name: 'NEXT_PUBLIC_VIEWS_TX_ADDITIONAL_FIELDS', value: '["fee_per_gas"]' }, +]; diff --git a/types/api/transaction.ts b/types/api/transaction.ts index 590e240eac..06c4056a82 100644 --- a/types/api/transaction.ts +++ b/types/api/transaction.ts @@ -2,6 +2,7 @@ import type { AddressParam } from './addressParams'; import type { BlockTransactionsResponse } from './block'; import type { DecodedInput } from './decodedInput'; import type { Fee } from './fee'; +import type { TokenInfo } from './token'; import type { TokenTransfer } from './tokenTransfer'; import type { TxAction } from './txAction'; @@ -55,6 +56,15 @@ export type Transaction = { execution_node?: AddressParam | null; allowed_peekers?: Array; wrapped?: Pick; + // Stability fields + stability_fee?: { + dapp_address: AddressParam; + dapp_fee: string; + token: TokenInfo; + total_fee: string; + validator_address: AddressParam; + validator_fee: string; + }; } export type TransactionsResponse = TransactionsResponseValidated | TransactionsResponsePending; diff --git a/ui/address/__screenshots__/AddressTxs.pw.tsx_mobile_base-view-mobile-1.png b/ui/address/__screenshots__/AddressTxs.pw.tsx_mobile_base-view-mobile-1.png index f82bc87b3f..9ec178775e 100644 Binary files a/ui/address/__screenshots__/AddressTxs.pw.tsx_mobile_base-view-mobile-1.png and b/ui/address/__screenshots__/AddressTxs.pw.tsx_mobile_base-view-mobile-1.png differ diff --git a/ui/home/LatestTxsItem.tsx b/ui/home/LatestTxsItem.tsx index 1c5010591f..13b0b2ae16 100644 --- a/ui/home/LatestTxsItem.tsx +++ b/ui/home/LatestTxsItem.tsx @@ -17,6 +17,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import Icon from 'ui/shared/chakra/Icon'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity'; +import TxFeeStability from 'ui/shared/tx/TxFeeStability'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxStatus from 'ui/shared/TxStatus'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; @@ -112,9 +113,13 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ) } { !config.UI.views.tx.hiddenFields?.tx_fee && ( - + Fee - { getValueWithUnit(tx.fee.value).dp(5).toFormat() } + { tx.stability_fee ? ( + + ) : ( + { getValueWithUnit(tx.fee.value).dp(5).toFormat() } + ) } ) } diff --git a/ui/home/LatestTxsItemMobile.tsx b/ui/home/LatestTxsItemMobile.tsx index 0bb8424ac3..0e375b4e4d 100644 --- a/ui/home/LatestTxsItemMobile.tsx +++ b/ui/home/LatestTxsItemMobile.tsx @@ -16,6 +16,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import Icon from 'ui/shared/chakra/Icon'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity'; +import TxFeeStability from 'ui/shared/tx/TxFeeStability'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxStatus from 'ui/shared/TxStatus'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; @@ -98,9 +99,13 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ) } { !config.UI.views.tx.hiddenFields?.tx_fee && ( - - Fee { config.chain.currency.symbol } - { getValueWithUnit(tx.fee.value).dp(5).toFormat() } + + Fee { !config.UI.views.tx.hiddenFields?.fee_currency ? `${ config.chain.currency.symbol } ` : '' } + { tx.stability_fee ? ( + + ) : ( + { getValueWithUnit(tx.fee.value).dp(5).toFormat() } + ) } ) } diff --git a/ui/shared/tx/TxFeeStability.tsx b/ui/shared/tx/TxFeeStability.tsx new file mode 100644 index 0000000000..af81cd5075 --- /dev/null +++ b/ui/shared/tx/TxFeeStability.tsx @@ -0,0 +1,36 @@ +import { Skeleton, chakra } from '@chakra-ui/react'; +import React from 'react'; + +import type { Transaction } from 'types/api/transaction'; +import type { ExcludeUndefined } from 'types/utils'; + +import getCurrencyValue from 'lib/getCurrencyValue'; +import TokenEntity from 'ui/shared/entities/token/TokenEntity'; + +interface Props { + data: ExcludeUndefined; + isLoading?: boolean; + hideUsd?: boolean; + accuracy?: number; + className?: string; +} + +const TxFeeStability = ({ data, isLoading, hideUsd, accuracy, className }: Props) => { + + const { valueStr, usd } = getCurrencyValue({ + value: data.total_fee, + exchangeRate: data.token.exchange_rate, + decimals: data.token.decimals, + accuracy, + }); + + return ( + + { valueStr } + + { usd && !hideUsd && (${ usd }) } + + ); +}; + +export default React.memo(chakra(TxFeeStability)); diff --git a/ui/tx/TxDetails.pw.tsx b/ui/tx/TxDetails.pw.tsx index b1f973d37f..8b2a19aa2b 100644 --- a/ui/tx/TxDetails.pw.tsx +++ b/ui/tx/TxDetails.pw.tsx @@ -202,3 +202,27 @@ mainnetTest('without testnet warning', async({ mount, page }) => { maskColor: configs.maskColor, }); }); + +const stabilityTest = test.extend({ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + context: contextWithEnvs(configs.stabilityEnvs) as any, +}); + +stabilityTest('stability customization', async({ mount, page }) => { + await page.route(API_URL, (route) => route.fulfill({ + status: 200, + body: JSON.stringify(txMock.stabilityTx), + })); + + const component = await mount( + + + , + { hooksConfig }, + ); + + await expect(component).toHaveScreenshot({ + mask: [ page.locator(configs.adsBannerSelector) ], + maskColor: configs.maskColor, + }); +}); diff --git a/ui/tx/TxDetails.tsx b/ui/tx/TxDetails.tsx index e056c3c75a..06e979f2a6 100644 --- a/ui/tx/TxDetails.tsx +++ b/ui/tx/TxDetails.tsx @@ -42,6 +42,7 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import LogDecodedInputData from 'ui/shared/logs/LogDecodedInputData'; import RawInputData from 'ui/shared/RawInputData'; import TextSeparator from 'ui/shared/TextSeparator'; +import TxFeeStability from 'ui/shared/tx/TxFeeStability'; import TxStatus from 'ui/shared/TxStatus'; import Utilization from 'ui/shared/Utilization/Utilization'; import TxDetailsActions from 'ui/tx/details/TxDetailsActions'; @@ -306,13 +307,17 @@ const TxDetails = () => { hint="Total transaction fee" isLoading={ isPlaceholderData } > - + { data.stability_fee ? ( + + ) : ( + + ) } ) } diff --git a/ui/tx/__screenshots__/TxDetails.pw.tsx_default_stability-customization-1.png b/ui/tx/__screenshots__/TxDetails.pw.tsx_default_stability-customization-1.png new file mode 100644 index 0000000000..22b768b228 Binary files /dev/null and b/ui/tx/__screenshots__/TxDetails.pw.tsx_default_stability-customization-1.png differ diff --git a/ui/txs/TxsListItem.tsx b/ui/txs/TxsListItem.tsx index b938651ff3..329532a06b 100644 --- a/ui/txs/TxsListItem.tsx +++ b/ui/txs/TxsListItem.tsx @@ -12,12 +12,14 @@ import config from 'configs/app'; import rightArrowIcon from 'icons/arrows/east.svg'; import getValueWithUnit from 'lib/getValueWithUnit'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; +import { space } from 'lib/html-entities'; import Icon from 'ui/shared/chakra/Icon'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity'; import InOutTag from 'ui/shared/InOutTag'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; +import TxFeeStability from 'ui/shared/tx/TxFeeStability'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxStatus from 'ui/shared/TxStatus'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; @@ -121,18 +123,27 @@ const TxsListItem = ({ tx, isLoading, showBlockInfo, currentAddress, enableTimeI ) : '-' } { !config.UI.views.tx.hiddenFields?.value && ( - - Value { config.chain.currency.symbol } - { getValueWithUnit(tx.value).toFormat() } - + + Value + + { getValueWithUnit(tx.value).toFormat() } + { space } + { config.chain.currency.symbol } + + ) } { !config.UI.views.tx.hiddenFields?.tx_fee && ( - - - Fee{ config.UI.views.tx.hiddenFields?.fee_currency ? ' ' : ` ${ config.chain.currency.symbol } ` } - - { getValueWithUnit(tx.fee.value).toFormat() } - + + Fee + { tx.stability_fee ? ( + + ) : ( + + { getValueWithUnit(tx.fee.value).toFormat() } + { config.UI.views.tx.hiddenFields?.fee_currency ? '' : ` ${ config.chain.currency.symbol }` } + + ) } + ) } ); diff --git a/ui/txs/TxsTableItem.tsx b/ui/txs/TxsTableItem.tsx index 327efca702..b0b52fe13b 100644 --- a/ui/txs/TxsTableItem.tsx +++ b/ui/txs/TxsTableItem.tsx @@ -23,6 +23,7 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity'; import InOutTag from 'ui/shared/InOutTag'; +import TxFeeStability from 'ui/shared/tx/TxFeeStability'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxStatus from 'ui/shared/TxStatus'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; @@ -163,7 +164,11 @@ const TxsTableItem = ({ tx, showBlockInfo, currentAddress, enableTimeIncrement, ) } { !config.UI.views.tx.hiddenFields?.tx_fee && ( - + { tx.stability_fee ? ( + + ) : ( + + ) } ) } diff --git a/ui/txs/__screenshots__/TxsListItem.pw.tsx_dark-color-mode_base-view-dark-mode-1.png b/ui/txs/__screenshots__/TxsListItem.pw.tsx_dark-color-mode_base-view-dark-mode-1.png index 42cc8978e5..50ff51df8f 100644 Binary files a/ui/txs/__screenshots__/TxsListItem.pw.tsx_dark-color-mode_base-view-dark-mode-1.png and b/ui/txs/__screenshots__/TxsListItem.pw.tsx_dark-color-mode_base-view-dark-mode-1.png differ diff --git a/ui/txs/__screenshots__/TxsListItem.pw.tsx_default_base-view-dark-mode-1.png b/ui/txs/__screenshots__/TxsListItem.pw.tsx_default_base-view-dark-mode-1.png index 030176bdcc..304fba7300 100644 Binary files a/ui/txs/__screenshots__/TxsListItem.pw.tsx_default_base-view-dark-mode-1.png and b/ui/txs/__screenshots__/TxsListItem.pw.tsx_default_base-view-dark-mode-1.png differ diff --git a/ui/txs/__screenshots__/TxsListItem.pw.tsx_default_with-base-address-1.png b/ui/txs/__screenshots__/TxsListItem.pw.tsx_default_with-base-address-1.png index ba21d65688..ac6657a22a 100644 Binary files a/ui/txs/__screenshots__/TxsListItem.pw.tsx_default_with-base-address-1.png and b/ui/txs/__screenshots__/TxsListItem.pw.tsx_default_with-base-address-1.png differ