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 = {
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',
......
......@@ -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';
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<string>;
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;
......
......@@ -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) => {
</Skeleton>
) }
{ !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" variant="secondary">{ getValueWithUnit(tx.fee.value).dp(5).toFormat() }</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>
) }
</Skeleton>
) }
</Box>
......
......@@ -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) => {
</Skeleton>
) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && (
<Skeleton isLoaded={ !isLoading } fontSize="sm" w="fit-content">
<Text as="span">Fee { config.chain.currency.symbol } </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).dp(5).toFormat() }</Text>
<Skeleton isLoaded={ !isLoading } fontSize="sm" w="fit-content" display="flex" whiteSpace="pre">
<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>
) }
</Skeleton>
) }
</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 }) => {
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';
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 }
>
<CurrencyValue
value={ data.fee.value }
currency={ config.UI.views.tx.hiddenFields?.fee_currency ? '' : config.chain.currency.symbol }
exchangeRate={ data.exchange_rate }
flexWrap="wrap"
isLoading={ isPlaceholderData }
/>
{ data.stability_fee ? (
<TxFeeStability data={ data.stability_fee } isLoading={ isPlaceholderData }/>
) : (
<CurrencyValue
value={ data.fee.value }
currency={ config.UI.views.tx.hiddenFields?.fee_currency ? '' : config.chain.currency.symbol }
exchangeRate={ data.exchange_rate }
flexWrap="wrap"
isLoading={ isPlaceholderData }
/>
) }
</DetailsInfoItem>
) }
......
......@@ -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
) : '-' }
</Flex>
{ !config.UI.views.tx.hiddenFields?.value && (
<Box mt={ 2 }>
<Skeleton isLoaded={ !isLoading } display="inline-block" whiteSpace="pre">Value { config.chain.currency.symbol } </Skeleton>
<Skeleton isLoaded={ !isLoading } display="inline-block" variant="text_secondary">{ getValueWithUnit(tx.value).toFormat() }</Skeleton>
</Box>
<Flex mt={ 2 } columnGap={ 2 }>
<Skeleton isLoaded={ !isLoading } display="inline-block" whiteSpace="pre">Value</Skeleton>
<Skeleton isLoaded={ !isLoading } display="inline-block" variant="text_secondary" whiteSpace="pre">
{ getValueWithUnit(tx.value).toFormat() }
{ space }
{ config.chain.currency.symbol }
</Skeleton>
</Flex>
) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && (
<Box mt={ 2 } mb={ 3 }>
<Skeleton isLoaded={ !isLoading } display="inline-block" whiteSpace="pre">
Fee{ config.UI.views.tx.hiddenFields?.fee_currency ? ' ' : ` ${ config.chain.currency.symbol } ` }
</Skeleton>
<Skeleton isLoaded={ !isLoading } display="inline-block" variant="text_secondary">{ getValueWithUnit(tx.fee.value).toFormat() }</Skeleton>
</Box>
<Flex mt={ 2 } mb={ 3 } columnGap={ 2 }>
<Skeleton isLoaded={ !isLoading } display="inline-block" whiteSpace="pre">Fee</Skeleton>
{ 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>
) }
</Flex>
) }
</ListItemMobile>
);
......
......@@ -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 && (
<Td isNumeric>
<CurrencyValue value={ tx.fee.value } accuracy={ 8 } isLoading={ isLoading }/>
{ tx.stability_fee ? (
<TxFeeStability data={ tx.stability_fee } isLoading={ isLoading } accuracy={ 8 } justifyContent="end" hideUsd/>
) : (
<CurrencyValue value={ tx.fee.value } accuracy={ 8 } isLoading={ isLoading }/>
) }
</Td>
) }
</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