Commit 7fb7b12a authored by tom goriunov's avatar tom goriunov Committed by GitHub

custom tx fee for Stability chain (#1298)

* Stability UI customizations V1

Fixes #1273

* fix API fetch from next.js

* stability config for review env

* update screenshot

* rollback envs for demo
parent a7d54437
...@@ -270,6 +270,47 @@ export const l2tx: Transaction = { ...@@ -270,6 +270,47 @@ export const l2tx: Transaction = {
l1_fee: '1584574188135760', 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 = { export const base2 = {
...base, ...base,
hash: '0x02d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3193', hash: '0x02d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3193',
......
...@@ -38,3 +38,9 @@ export const viewsEnvs = { ...@@ -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"]' },
];
...@@ -2,6 +2,7 @@ import type { AddressParam } from './addressParams'; ...@@ -2,6 +2,7 @@ import type { AddressParam } from './addressParams';
import type { BlockTransactionsResponse } from './block'; import type { BlockTransactionsResponse } from './block';
import type { DecodedInput } from './decodedInput'; import type { DecodedInput } from './decodedInput';
import type { Fee } from './fee'; import type { Fee } from './fee';
import type { TokenInfo } from './token';
import type { TokenTransfer } from './tokenTransfer'; import type { TokenTransfer } from './tokenTransfer';
import type { TxAction } from './txAction'; import type { TxAction } from './txAction';
...@@ -55,6 +56,15 @@ export type Transaction = { ...@@ -55,6 +56,15 @@ export type Transaction = {
execution_node?: AddressParam | null; execution_node?: AddressParam | null;
allowed_peekers?: Array<string>; allowed_peekers?: Array<string>;
wrapped?: Pick<Transaction, WrappedTransactionFields>; wrapped?: Pick<Transaction, WrappedTransactionFields>;
// 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; export type TransactionsResponse = TransactionsResponseValidated | TransactionsResponsePending;
......
...@@ -17,6 +17,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; ...@@ -17,6 +17,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
...@@ -112,9 +113,13 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -112,9 +113,13 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
</Skeleton> </Skeleton>
) } ) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && ( { !config.UI.views.tx.hiddenFields?.tx_fee && (
<Skeleton isLoaded={ !isLoading }> <Skeleton isLoaded={ !isLoading } display="flex" whiteSpace="pre">
<Text as="span">Fee </Text> <Text as="span">Fee </Text>
{ tx.stability_fee ? (
<TxFeeStability data={ tx.stability_fee } accuracy={ 5 } color="text_secondary" hideUsd/>
) : (
<Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).dp(5).toFormat() }</Text> <Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).dp(5).toFormat() }</Text>
) }
</Skeleton> </Skeleton>
) } ) }
</Box> </Box>
......
...@@ -16,6 +16,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; ...@@ -16,6 +16,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
...@@ -98,9 +99,13 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -98,9 +99,13 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
</Skeleton> </Skeleton>
) } ) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && ( { !config.UI.views.tx.hiddenFields?.tx_fee && (
<Skeleton isLoaded={ !isLoading } fontSize="sm" w="fit-content"> <Skeleton isLoaded={ !isLoading } fontSize="sm" w="fit-content" display="flex" whiteSpace="pre">
<Text as="span">Fee { config.chain.currency.symbol } </Text> <Text as="span">Fee { !config.UI.views.tx.hiddenFields?.fee_currency ? `${ config.chain.currency.symbol } ` : '' }</Text>
{ tx.stability_fee ? (
<TxFeeStability data={ tx.stability_fee } accuracy={ 5 } color="text_secondary" hideUsd/>
) : (
<Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).dp(5).toFormat() }</Text> <Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).dp(5).toFormat() }</Text>
) }
</Skeleton> </Skeleton>
) } ) }
</Box> </Box>
......
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<Transaction['stability_fee']>;
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 (
<Skeleton whiteSpace="pre" isLoaded={ !isLoading } display="flex" className={ className }>
<span>{ valueStr } </span>
<TokenEntity token={ data.token } noIcon noCopy onlySymbol w="auto"/>
{ usd && !hideUsd && <chakra.span color="text_secondary"> (${ usd })</chakra.span> }
</Skeleton>
);
};
export default React.memo(chakra(TxFeeStability));
...@@ -202,3 +202,27 @@ mainnetTest('without testnet warning', async({ mount, page }) => { ...@@ -202,3 +202,27 @@ mainnetTest('without testnet warning', async({ mount, page }) => {
maskColor: configs.maskColor, 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(
<TestApp>
<TxDetails/>
</TestApp>,
{ hooksConfig },
);
await expect(component).toHaveScreenshot({
mask: [ page.locator(configs.adsBannerSelector) ],
maskColor: configs.maskColor,
});
});
...@@ -42,6 +42,7 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; ...@@ -42,6 +42,7 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LogDecodedInputData from 'ui/shared/logs/LogDecodedInputData'; import LogDecodedInputData from 'ui/shared/logs/LogDecodedInputData';
import RawInputData from 'ui/shared/RawInputData'; import RawInputData from 'ui/shared/RawInputData';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import Utilization from 'ui/shared/Utilization/Utilization'; import Utilization from 'ui/shared/Utilization/Utilization';
import TxDetailsActions from 'ui/tx/details/TxDetailsActions'; import TxDetailsActions from 'ui/tx/details/TxDetailsActions';
...@@ -306,6 +307,9 @@ const TxDetails = () => { ...@@ -306,6 +307,9 @@ const TxDetails = () => {
hint="Total transaction fee" hint="Total transaction fee"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
{ data.stability_fee ? (
<TxFeeStability data={ data.stability_fee } isLoading={ isPlaceholderData }/>
) : (
<CurrencyValue <CurrencyValue
value={ data.fee.value } value={ data.fee.value }
currency={ config.UI.views.tx.hiddenFields?.fee_currency ? '' : config.chain.currency.symbol } currency={ config.UI.views.tx.hiddenFields?.fee_currency ? '' : config.chain.currency.symbol }
...@@ -313,6 +317,7 @@ const TxDetails = () => { ...@@ -313,6 +317,7 @@ const TxDetails = () => {
flexWrap="wrap" flexWrap="wrap"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
/> />
) }
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
......
...@@ -12,12 +12,14 @@ import config from 'configs/app'; ...@@ -12,12 +12,14 @@ import config from 'configs/app';
import rightArrowIcon from 'icons/arrows/east.svg'; import rightArrowIcon from 'icons/arrows/east.svg';
import getValueWithUnit from 'lib/getValueWithUnit'; import getValueWithUnit from 'lib/getValueWithUnit';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import { space } from 'lib/html-entities';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag'; import InOutTag from 'ui/shared/InOutTag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
...@@ -121,18 +123,27 @@ const TxsListItem = ({ tx, isLoading, showBlockInfo, currentAddress, enableTimeI ...@@ -121,18 +123,27 @@ const TxsListItem = ({ tx, isLoading, showBlockInfo, currentAddress, enableTimeI
) : '-' } ) : '-' }
</Flex> </Flex>
{ !config.UI.views.tx.hiddenFields?.value && ( { !config.UI.views.tx.hiddenFields?.value && (
<Box mt={ 2 }> <Flex mt={ 2 } columnGap={ 2 }>
<Skeleton isLoaded={ !isLoading } display="inline-block" whiteSpace="pre">Value { config.chain.currency.symbol } </Skeleton> <Skeleton isLoaded={ !isLoading } display="inline-block" whiteSpace="pre">Value</Skeleton>
<Skeleton isLoaded={ !isLoading } display="inline-block" variant="text_secondary">{ getValueWithUnit(tx.value).toFormat() }</Skeleton> <Skeleton isLoaded={ !isLoading } display="inline-block" variant="text_secondary" whiteSpace="pre">
</Box> { getValueWithUnit(tx.value).toFormat() }
{ space }
{ config.chain.currency.symbol }
</Skeleton>
</Flex>
) } ) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && ( { !config.UI.views.tx.hiddenFields?.tx_fee && (
<Box mt={ 2 } mb={ 3 }> <Flex mt={ 2 } mb={ 3 } columnGap={ 2 }>
<Skeleton isLoaded={ !isLoading } display="inline-block" whiteSpace="pre"> <Skeleton isLoaded={ !isLoading } display="inline-block" whiteSpace="pre">Fee</Skeleton>
Fee{ config.UI.views.tx.hiddenFields?.fee_currency ? ' ' : ` ${ config.chain.currency.symbol } ` } { tx.stability_fee ? (
<TxFeeStability data={ tx.stability_fee } isLoading={ isLoading } hideUsd/>
) : (
<Skeleton isLoaded={ !isLoading } display="inline-block" variant="text_secondary" whiteSpace="pre">
{ getValueWithUnit(tx.fee.value).toFormat() }
{ config.UI.views.tx.hiddenFields?.fee_currency ? '' : ` ${ config.chain.currency.symbol }` }
</Skeleton> </Skeleton>
<Skeleton isLoaded={ !isLoading } display="inline-block" variant="text_secondary">{ getValueWithUnit(tx.fee.value).toFormat() }</Skeleton> ) }
</Box> </Flex>
) } ) }
</ListItemMobile> </ListItemMobile>
); );
......
...@@ -23,6 +23,7 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity'; ...@@ -23,6 +23,7 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag'; import InOutTag from 'ui/shared/InOutTag';
import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus'; import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo'; import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
...@@ -163,7 +164,11 @@ const TxsTableItem = ({ tx, showBlockInfo, currentAddress, enableTimeIncrement, ...@@ -163,7 +164,11 @@ const TxsTableItem = ({ tx, showBlockInfo, currentAddress, enableTimeIncrement,
) } ) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && ( { !config.UI.views.tx.hiddenFields?.tx_fee && (
<Td isNumeric> <Td isNumeric>
{ tx.stability_fee ? (
<TxFeeStability data={ tx.stability_fee } isLoading={ isLoading } accuracy={ 8 } justifyContent="end" hideUsd/>
) : (
<CurrencyValue value={ tx.fee.value } accuracy={ 8 } isLoading={ isLoading }/> <CurrencyValue value={ tx.fee.value } accuracy={ 8 } isLoading={ isLoading }/>
) }
</Td> </Td>
) } ) }
</Tr> </Tr>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment