Commit 671d8ad5 authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

Merge pull request #147 from blockscout/tx-state

tx state tab
parents 9ea805eb d5f207f5
export const privateTagsTransaction = [
{
transaction: '0x44b51ef7746ff48f74f45699d33557faa96059eb8655fdd7bf14a5f529ea3528',
tag: 'some_tag',
},
{
transaction: '0x44b51ef7746ff48f74f45699d33557faa96059eb8655fdd7bf14a5f529ea9999',
tag: 'some_other_tag',
},
];
export type TPrivateTagsTransaction = Array<TPrivateTagsTransactionItem>
export type TPrivateTagsTransactionItem = {
transaction: string;
tag: string;
}
export const publicTags = [
{
addresses: [
{
address: '0x35317007D203b8a86CA727ad44E473E40450E377',
addressName: 'DarkForest',
},
{
address: '0x35317007D203b8a86CA727ad44E473E40450E378',
addressName: 'DarkForest2',
},
],
tags: [
{
name: 'darkforest',
// colorHex: '#4A5568',
// backgroundHex: '#E2E8F0',
},
],
date: 'Jun 10, 2022',
id: '123',
userName: 'Tatyana',
userEmail: 'sample@gmail.com',
companyName: 'Contract name',
companyUrl: 'contractname.com',
comment: 'Please use #ED8936 color for tag...',
},
{
addresses: [
{
address: '0x35317007D203b8a86CA727ad44E473E40450E377',
},
],
tags: [
{
name: 'OMNI',
colorHex: '#FFFFFF',
backgroundHex: '#1A202C',
},
{
name: '123456789012345678901237123123',
colorHex: '#FFFFFF',
backgroundHex: '#6B46C1',
},
],
date: 'Jun 5, 2022',
id: '456',
},
{
addresses: [
{
address: '0x35317007D203b8a86CA727ad44E473E40450E377',
addressName: 'Contract name',
},
],
tags: [
{
name: 'SANA',
colorHex: '#FFFFFF',
backgroundHex: '#ED8936',
},
],
date: 'Jun 1, 2022',
id: '789',
},
];
export type TPublicTags = Array<TPublicTagItem>
export type TPublicTagItem = {
addresses: Array<TPublicTagAddress>;
tags: Array<TPublicTag>;
// status: typeof STATUS;
date: string;
// id is for react element key, as tag or address may not be unique
id: string;
userName?: string;
userEmail?: string;
companyName?: string;
companyUrl?: string;
comment?: string;
}
export type TPublicTagAddress = {
address: string;
addressName?: string;
}
export type TPublicTag = {
name: string;
colorHex?: string;
backgroundHex?: string;
}
export const data = [
{
address: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
miner: 'KuCoin Pool',
after: {
balance: '0.012192910371186045',
nonce: '4',
},
before: {
balance: '0.008350264867549483',
nonce: '5',
},
diff: '0.003842645503636562',
storage: [
{
address: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
before: '0x000000000000000000000000730bc43aac5a6cf94a72f69a42adfa114fe119b5',
after: '0x000000000000000000000000730bc43aac5a6cf94a72f69a42adfa114fe119b5',
},
{
address: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
before: '0x730bc43aac5a6cf94a72f69a42adfa114fe119b5',
after: '0x000000000000000000000000730bc43aac5a6cf94a72f69a42adfa114fe119b5',
},
],
},
{
address: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
miner: 'KuCoin Pool',
after: {
balance: '0.012192910371186045',
nonce: '4',
},
before: {
balance: '0.008350264867549483',
nonce: '5',
},
diff: '0.003842645503636562',
storage: [
{
address: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
before: '0x000000000000000000000000730bc43aac5a6cf94a72f69a42adfa114fe119b5',
after: '0x000000000000000000000000730bc43aac5a6cf94a72f69a42adfa114fe119b5',
},
{
address: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
before: '0x730bc43aac5a6cf94a72f69a42adfa114fe119b5',
after: '0x000000000000000000000000730bc43aac5a6cf94a72f69a42adfa114fe119b5',
},
],
},
{
address: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
miner: 'KuCoin Pool',
after: {
balance: '0.012192910371186045',
},
before: {
balance: '0.008350264867549483',
},
diff: '-0.003842645503636562',
},
];
export type TTxState = Array<TTxStateItem>;
export type TTxStateItem = {
address: string;
miner: string;
after: {
balance: string;
nonce?: string;
};
before: {
balance: string;
nonce?: string;
};
diff: string;
storage?: Array<TTxStateItemStorage>;
}
export type TTxStateItemStorage = {
address: string;
before: string;
after: string;
}
export const watchlist = [
{
address: '0x4831c121879d3de0e2b181d9d55e9b0724f5d926',
tokenBalance: 100.1,
tokenBalanceUSD: 101.2,
tokensAmount: 2,
tokensUSD: 202.2,
totalUSD: 123123,
tag: 'some_tag',
notification: true,
},
{
address: '0x8c461F78760988c4135e363a87dd736f8b671ff0',
tokensAmount: 2,
tokensUSD: 2202.2,
totalUSD: 3000.5,
tag: 'some_other_tag',
notification: false,
},
{
address: '0x930F381E649c84579Ef58117E923714964C55D16',
tokenBalance: 200.2,
tokenBalanceUSD: 202.4,
totalUSD: 3000.5,
tag: '12345678901234567890123456789012345',
notification: false,
},
];
export type TWatchlist = Array<TWatchlistItem>
export type TWatchlistItem = {
address: string;
tokenBalance?: number;
tokenBalanceUSD?: number;
tokensAmount?: number;
tokensUSD?: number;
totalUSD?: number;
tag: string;
notification?: boolean;
}
...@@ -75,6 +75,10 @@ const variantOutline = defineStyle((props) => { ...@@ -75,6 +75,10 @@ const variantOutline = defineStyle((props) => {
borderColor: props.isActive ? activeBg : 'blue.400', borderColor: props.isActive ? activeBg : 'blue.400',
color: props.isActive ? activeColor : 'blue.400', color: props.isActive ? activeColor : 'blue.400',
}, },
_disabled: {
color,
borderColor,
},
}, },
_disabled: { _disabled: {
opacity: 0.2, opacity: 0.2,
...@@ -83,6 +87,10 @@ const variantOutline = defineStyle((props) => { ...@@ -83,6 +87,10 @@ const variantOutline = defineStyle((props) => {
bg: activeBg, bg: activeBg,
borderColor: activeBg, borderColor: activeBg,
color: activeColor, color: activeColor,
_disabled: {
color,
borderColor,
},
}, },
}; };
}); });
......
...@@ -40,6 +40,19 @@ const sizes = { ...@@ -40,6 +40,19 @@ const sizes = {
py: 6, py: 6,
}, },
}), }),
sm: definePartsStyle({
th: {
px: '10px',
py: '10px',
fontSize: 'sm',
},
td: {
px: '10px',
py: 6,
fontSize: 'sm',
fontWeight: 500,
},
}),
}; };
const variants = { const variants = {
......
...@@ -16,6 +16,7 @@ import TxDetails from 'ui/tx/TxDetails'; ...@@ -16,6 +16,7 @@ import TxDetails from 'ui/tx/TxDetails';
import TxInternals from 'ui/tx/TxInternals'; import TxInternals from 'ui/tx/TxInternals';
import TxLogs from 'ui/tx/TxLogs'; import TxLogs from 'ui/tx/TxLogs';
import TxRawTrace from 'ui/tx/TxRawTrace'; import TxRawTrace from 'ui/tx/TxRawTrace';
import TxState from 'ui/tx/TxState';
interface Tab { interface Tab {
type: 'details' | 'internal_txn' | 'logs' | 'raw_trace' | 'state'; type: 'details' | 'internal_txn' | 'logs' | 'raw_trace' | 'state';
...@@ -29,7 +30,7 @@ const TABS: Array<Tab> = [ ...@@ -29,7 +30,7 @@ const TABS: Array<Tab> = [
{ type: 'details', routeName: 'tx_index', name: 'Details', component: <TxDetails/> }, { type: 'details', routeName: 'tx_index', name: 'Details', component: <TxDetails/> },
{ type: 'internal_txn', routeName: 'tx_internal', name: 'Internal txn', component: <TxInternals/> }, { type: 'internal_txn', routeName: 'tx_internal', name: 'Internal txn', component: <TxInternals/> },
{ type: 'logs', routeName: 'tx_logs', name: 'Logs', component: <TxLogs/> }, { type: 'logs', routeName: 'tx_logs', name: 'Logs', component: <TxLogs/> },
{ type: 'state', routeName: 'tx_state', name: 'State' }, { type: 'state', routeName: 'tx_state', name: 'State', component: <TxState/> },
{ type: 'raw_trace', routeName: 'tx_raw_trace', name: 'Raw trace', component: <TxRawTrace/> }, { type: 'raw_trace', routeName: 'tx_raw_trace', name: 'Raw trace', component: <TxRawTrace/> },
]; ];
......
...@@ -10,7 +10,7 @@ const TxInternals = () => { ...@@ -10,7 +10,7 @@ const TxInternals = () => {
<Box> <Box>
<Filters/> <Filters/>
<TableContainer width="100%" mt={ 6 }> <TableContainer width="100%" mt={ 6 }>
<Table variant="simple" minWidth="950px"> <Table variant="simple" minWidth="950px" size="sm">
<Thead> <Thead>
<Tr> <Tr>
<Th width="20%">Type</Th> <Th width="20%">Type</Th>
......
import {
Accordion,
Text,
Table,
Thead,
Tbody,
Tr,
Th,
TableContainer,
} from '@chakra-ui/react';
import React from 'react';
import { data } from 'data/txState';
import TxStateTableItem from './state/TxStateTableItem';
const CURRENCY = 'ETH';
const TxState = () => {
return (
<>
<Text>
A set of information that represents the current state is updated when a transaction takes place on the network. The below is a summary of those changes
</Text>
<Accordion allowToggle allowMultiple>
<TableContainer width="100%" mt={ 6 }>
<Table variant="simple" minWidth="950px" size="sm">
<Thead>
<Tr>
<Th width="92px">Storage</Th>
<Th width="146px">Address</Th>
<Th width="120px">Miner</Th>
<Th width="33%" isNumeric>{ `After ${ CURRENCY }` }</Th>
<Th width="33%" isNumeric>{ `Before ${ CURRENCY }` }</Th>
<Th width="33%" isNumeric>{ `State difference ${ CURRENCY }` }</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item, index) => <TxStateTableItem txStateItem={ item } key={ index }/>) }
</Tbody>
</Table>
</TableContainer>
</Accordion>
</>
);
};
export default TxState;
import {
Grid,
GridItem,
Select,
useColorModeValue,
} from '@chakra-ui/react';
import React from 'react';
import type { TTxStateItemStorage } from 'data/txState';
const TxStateStorageItem = ({ storageItem }: {storageItem: TTxStateItemStorage}) => {
const gridData = [
{ name: 'Storage Address:', value: storageItem.address },
{ name: 'Before:', value: storageItem.before, select: true },
{ name: 'After:', value: storageItem.after, select: true },
];
const backgroundColor = useColorModeValue('white', 'gray.900');
const OPTIONS = [ 'Hex', 'Number', 'Text', 'Address' ];
return (
<Grid
gridTemplateColumns="auto 1fr"
columnGap={ 3 }
rowGap={ 4 }
px={ 6 }
py={ 4 }
background="blackAlpha.50"
borderRadius="12px"
mb={ 4 }
>
{ gridData.map((item) => (
<>
<GridItem alignSelf="center" fontWeight={ 600 } textAlign="end">{ item.name }</GridItem>
<GridItem>
{ item.select && (
<Select
size="sm"
borderRadius="base"
focusBorderColor="none"
display="inline-block"
w="auto"
mr={ 3 }
background={ backgroundColor }
>
{ OPTIONS.map((option) => <option key={ option } value={ option }>{ option }</option>) }
</Select>
) }
{ item.value }
</GridItem>
</>
)) }
</Grid>
);
};
export default TxStateStorageItem;
import {
AccordionItem,
AccordionButton,
AccordionPanel,
AccordionIcon,
Text,
Box,
Tr,
Td,
Flex,
Stat,
StatArrow,
Portal,
Link,
Button,
} from '@chakra-ui/react';
import React, { useRef } from 'react';
import type { TTxStateItem } from 'data/txState';
import { nbsp } from 'lib/html-entities';
import AddressIcon from 'ui/shared/AddressIcon';
import AddressLinkWithTooltip from 'ui/shared/AddressLinkWithTooltip';
import TxStateStorageItem from './TxStateStorageItem';
const TxStateTableItem = ({ txStateItem }: { txStateItem: TTxStateItem }) => {
const ref = useRef<HTMLTableDataCellElement>(null);
const hasStorageData = Boolean(txStateItem.storage?.length);
return (
<>
<AccordionItem as="tr" isDisabled={ !hasStorageData } fontWeight={ 500 } border={ 0 }>
{ ({ isExpanded }) => (
<>
<Td border={ 0 }>
<AccordionButton
_hover={{ background: 'unset' }}
padding="0"
>
<Button
variant="outline"
borderWidth="1px"
// button can't be inside button (AccordionButton)
as="div"
isActive={ isExpanded }
size="sm"
fontWeight={ 400 }
isDisabled={ !hasStorageData }
colorScheme="gray"
// AccordionButton has its own opacity rule when disabled
_disabled={{ opacity: 1 }}
>
{ txStateItem.storage?.length || '0' }
</Button>
<AccordionIcon color="blue.600" width="30px"/>
</AccordionButton>
</Td>
<Td border={ 0 }>
<Flex height="30px" alignItems="center">
<AddressIcon address={ txStateItem.address }/>
<AddressLinkWithTooltip address={ txStateItem.address } fontWeight="500" truncated withCopy={ false } ml={ 2 }/>
</Flex>
</Td>
<Td border={ 0 } lineHeight="30px"><Link>{ txStateItem.miner }</Link></Td>
<Td border={ 0 } isNumeric lineHeight="30px">
<Box>{ txStateItem.after.balance }</Box>
{ typeof txStateItem.after.nonce !== 'undefined' && (
<Box justifyContent="end" display="inline-flex">Nonce: <Text fontWeight={ 600 }>{ nbsp + txStateItem.after.nonce }</Text></Box>
) }
</Td>
<Td border={ 0 } isNumeric lineHeight="30px">{ txStateItem.before.balance }</Td>
<Td border={ 0 } isNumeric lineHeight="30px">
<Stat>
{ txStateItem.diff }
<StatArrow ml={ 2 } type={ Number(txStateItem.diff) > 0 ? 'increase' : 'decrease' }/>
</Stat>
</Td>
{ hasStorageData && (
<Portal containerRef={ ref }>
<AccordionPanel fontWeight={ 500 }>
{ txStateItem.storage?.map((storageItem, index) => <TxStateStorageItem key={ index } storageItem={ storageItem }/>) }
</AccordionPanel>
</Portal>
) }
</>
) }
</AccordionItem>
<Tr><Td colSpan={ 6 } ref={ ref } padding={ 0 }></Td></Tr>
</>
);
};
export default TxStateTableItem;
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