Commit c256c241 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #227 from blockscout/decode-tx-data

decode tx data
parents ca51d193 ca1a7da6
export default function hexToAddress(hex: string) {
const shortenHex = hex.slice(0, 66);
return shortenHex.slice(0, 2) + shortenHex.slice(26);
}
export default function hexToBytes(hex: string) {
const bytes = [];
for (let c = 0; c < hex.length; c += 2) {
bytes.push(parseInt(hex.substring(c, c + 2), 16));
}
return bytes;
}
import hexToBytes from 'lib/hexToBytes';
export default function hexToUtf8(hex: string) {
const utf8decoder = new TextDecoder();
const bytes = new Uint8Array(hexToBytes(hex));
return utf8decoder.decode(bytes);
}
......@@ -73,6 +73,10 @@ export const ROUTES = {
pattern: `${ BASE_PATH }/address/[id]`,
crossNetworkNavigation: true,
},
address_contract_verification: {
pattern: `${ BASE_PATH }/address/[id]/contract_verifications/new`,
crossNetworkNavigation: true,
},
// APPS
apps: {
......
import { Box, Flex, Select, Textarea } from '@chakra-ui/react';
import React from 'react';
import hexToUtf8 from 'lib/hexToUtf8';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
type DataType = 'Hex' | 'UTF-8'
......@@ -26,7 +27,7 @@ const RawInputData = ({ hex }: Props) => {
<CopyToClipboard text={ hex }/>
</Flex>
<Textarea
value={ selectedDataType === 'Hex' ? hex : 'UTF-8 equivalent' }
value={ selectedDataType === 'Hex' ? hex : hexToUtf8(hex) }
w="100%"
maxH="220px"
mt={ 2 }
......@@ -38,4 +39,4 @@ const RawInputData = ({ hex }: Props) => {
);
};
export default RawInputData;
export default React.memo(RawInputData);
import { Text, Grid, GridItem, Link, Tooltip, Button, Icon, useColorModeValue } from '@chakra-ui/react';
import { Text, Grid, GridItem, Tooltip, Button, useColorModeValue, Alert, Link } from '@chakra-ui/react';
import React from 'react';
import type { Log } from 'types/api/log';
import searchIcon from 'icons/search.svg';
// import searchIcon from 'icons/search.svg';
import { space } from 'lib/html-entities';
import useLink from 'lib/link/useLink';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
......@@ -22,6 +24,7 @@ const TxLogItem = ({ address, index, topics, data, decoded }: Props) => {
const borderColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
const dataBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
const link = useLink();
return (
<Grid
......@@ -36,17 +39,26 @@ const TxLogItem = ({ address, index, topics, data, decoded }: Props) => {
pt: 0,
}}
>
{ !decoded && (
<GridItem colSpan={{ base: 1, lg: 2 }}>
<Alert status="warning" display="inline-table" whiteSpace="normal">
To see accurate decoded input data, the contract must be verified.{ space }
<Link href={ link('address_contract_verification', { id: address.hash }) }>Verify the contract here</Link>
</Alert>
</GridItem>
) }
<RowHeader>Address</RowHeader>
<GridItem display="flex" alignItems="center">
<Address>
<Address mr={{ base: 9, lg: 0 }}>
<AddressIcon hash={ address.hash }/>
<AddressLink hash={ address.hash } alias={ address.name } ml={ 2 }/>
</Address>
<Tooltip label="Find matches topic">
{ /* api doesn't have find topic feature yet */ }
{ /* <Tooltip label="Find matches topic">
<Link ml={ 2 } mr={{ base: 9, lg: 0 }} display="inline-flex">
<Icon as={ searchIcon } boxSize={ 5 }/>
</Link>
</Tooltip>
</Tooltip> */ }
<Tooltip label="Log index">
<Button variant="outline" colorScheme="gray" isActive ml="auto" size="sm" fontWeight={ 400 }>
{ index }
......@@ -63,7 +75,13 @@ const TxLogItem = ({ address, index, topics, data, decoded }: Props) => {
) }
<RowHeader>Topics</RowHeader>
<GridItem>
{ topics.filter(Boolean).map((item, index) => <TxLogTopic key={ index } hex={ item } index={ index }/>) }
{ topics.filter(Boolean).map((item, index) => (
<TxLogTopic
key={ index }
hex={ item }
index={ index }
/>
)) }
</GridItem>
<RowHeader>Data</RowHeader>
<GridItem p={ 4 } fontSize="sm" borderRadius="md" bgColor={ dataBgColor }>
......
import { Flex, Button, Select, Box } from '@chakra-ui/react';
import capitalize from 'lodash/capitalize';
import React from 'react';
import hexToAddress from 'lib/hexToAddress';
import hexToUtf8 from 'lib/hexToUtf8';
import Address from 'ui/shared/address/Address';
import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
interface Props {
......@@ -8,36 +14,71 @@ interface Props {
index: number;
}
type DataType = 'Hex' | 'Dec'
const OPTIONS: Array<DataType> = [ 'Hex', 'Dec' ];
type DataType = 'hex' | 'text' | 'address' | 'number';
const VALUE_CONVERTERS: Record<DataType, (hex: string) => string> = {
hex: (hex) => hex,
text: hexToUtf8,
address: hexToAddress,
number: (hex) => BigInt(hex).toString(),
};
const OPTIONS: Array<DataType> = [ 'hex', 'address', 'text', 'number' ];
const TxLogTopic = ({ hex, index }: Props) => {
const [ selectedDataType, setSelectedDataType ] = React.useState<DataType>('Hex');
const [ selectedDataType, setSelectedDataType ] = React.useState<DataType>('hex');
const handleSelectChange = React.useCallback((event: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedDataType(event.target.value as DataType);
}, []);
const value = VALUE_CONVERTERS[selectedDataType.toLowerCase() as Lowercase<DataType>](hex);
const content = (() => {
switch (selectedDataType) {
case 'hex':
case 'number':
case 'text': {
return (
<>
<Box overflow="hidden" whiteSpace="nowrap">
<HashStringShortenDynamic hash={ value }/>
</Box>
<CopyToClipboard text={ value }/>
</>
);
}
case 'address': {
return (
<Address>
<AddressLink hash={ value }/>
<CopyToClipboard text={ value }/>
</Address>
);
}
}
})();
return (
<Flex alignItems="center" px={{ base: 0, lg: 3 }} _notFirst={{ mt: 3 }} overflow="hidden" maxW="100%">
<Button variant="outline" colorScheme="gray" isActive size="xs" fontWeight={ 400 } mr={ 3 } w={ 6 }>
{ index }
</Button>
{ index !== 0 && (
<Select
size="sm"
borderRadius="base"
value={ selectedDataType }
onChange={ handleSelectChange }
focusBorderColor="none"
w="75px"
mr={ 3 }
flexShrink={ 0 }
w="auto"
>
{ OPTIONS.map((option) => <option key={ option } value={ option }>{ option }</option>) }
{ OPTIONS.map((option) => <option key={ option } value={ option }>{ capitalize(option) }</option>) }
</Select>
<Box overflow="hidden" whiteSpace="nowrap">
<HashStringShortenDynamic hash={ hex }/>
</Box>
) }
{ content }
</Flex>
);
};
......
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