Merge pull request #198 from ArtemKolodko/refactor_txs_columns

Refactor transaction columns
pull/199/head
Artem 2 years ago committed by GitHub
commit 83d83890bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .gitignore
  2. 7
      src/components/block/BlockDetails.tsx
  3. 6
      src/components/block/BlockList.tsx
  4. 1
      src/components/block/helpers.tsx
  5. 1
      src/components/metrics/index.tsx
  6. 28
      src/components/tables/TransactionsTable.tsx
  7. 13
      src/components/transaction/TransactionDetails.tsx
  8. 1
      src/components/transaction/helpers.tsx
  9. 71
      src/components/ui/Address.tsx
  10. 10
      src/components/ui/ONEValue.tsx
  11. 4
      src/components/ui/Pagination/index.tsx
  12. 39
      src/components/ui/Tooltip.tsx
  13. 21
      src/index.css
  14. 18
      src/pages/AddressPage/AddressDetails.tsx
  15. 1
      src/pages/AddressPage/TokenInfo.tsx
  16. 2
      src/pages/AddressPage/index.tsx
  17. 15
      src/pages/AddressPage/tabs/events/Events.tsx
  18. 10
      src/pages/AddressPage/tabs/transactions/Transactions.tsx
  19. 164
      src/pages/AddressPage/tabs/transactions/columns/common.tsx
  20. 141
      src/pages/AddressPage/tabs/transactions/columns/erc20.tsx
  21. 11
      src/pages/AddressPage/tabs/transactions/columns/index.tsx
  22. 160
      src/pages/AddressPage/tabs/transactions/columns/nft.tsx
  23. 122
      src/pages/AddressPage/tabs/transactions/columns/staking.tsx
  24. 177
      src/pages/AddressPage/tabs/transactions/columns/transactions.tsx
  25. 778
      src/pages/AddressPage/tabs/txsColumns.tsx
  26. 11
      src/pages/AllBlocksPage/AllBlocksTable.tsx
  27. 12
      src/pages/ERC1155List/ERC1155Table.tsx
  28. 18
      src/pages/ERC20List/ERC20Table.tsx
  29. 12
      src/pages/ERC721List/ERC721Table.tsx
  30. 6
      src/pages/ExportData/index.tsx
  31. 7
      src/pages/MainPage/LatestBlocksTable.tsx
  32. 9
      src/pages/MainPage/LatestTransactionsTable.tsx
  33. 16
      src/pages/tools/CheckHRC/index.tsx
  34. 43
      src/theme.ts

1
.gitignore vendored

@ -6,6 +6,7 @@
.pnp.js
.firebase/*
/.firebase
/firebase

@ -20,7 +20,6 @@ const columns = [
<Tip
dropProps={{ align: { left: "right" } }}
content={<TipContent message={blockPropertyDescriptions[e.key]} />}
plain
>
<span>
<CircleQuestion size="small" />
@ -101,12 +100,10 @@ export const BlockDetails: FunctionComponent<BlockDetailsProps> = ({
data={blockData}
step={10}
border={{
header: {
color: "none",
},
header: false,
body: {
color: "border",
side: "top",
side: "bottom",
size: "1px",
},
}}

@ -71,12 +71,10 @@ export const BlockList: FunctionComponent<BlockDetailsProps> = ({ block }) => {
data={blockData}
step={10}
border={{
header: {
color: 'none'
},
header: false,
body: {
color: 'border',
side: 'top',
side: 'bottom',
size: '1px'
}
}}

@ -58,6 +58,7 @@ export const blockPropertyDisplayNames: Record<string, string> = {
};
export const blockPropertyDescriptions: Record<string, string> = {
shard: 'Shard Number',
number:
"Also known as Block Number. The block height, which indicates the length of the blockchain, increases after the addition of the new block.",
hash: "The hash of the block header of the current block.",

@ -311,7 +311,6 @@ function BlockLatency(params: { latency: number; latencyPerBlock: number[] }) {
}
/>
}
plain
>
<Text size="small" weight="bold">
{params.latency.toFixed(2)}s

@ -22,7 +22,7 @@ function getColumns(props: any) {
size: "xxsmall",
resizeable: false,
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
<Text color="minorText" size="small">
Shard
</Text>
),
@ -43,7 +43,7 @@ function getColumns(props: any) {
size: "xsmall",
resizeable: false,
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
<Text color="minorText" size="small">
Hash
</Text>
),
@ -65,7 +65,7 @@ function getColumns(props: any) {
size: "260px",
resizeable: false,
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
<Text color="minorText" size="small">
Block number
</Text>
),
@ -89,7 +89,7 @@ function getColumns(props: any) {
size: "large",
resizeable: false,
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
<Text color="minorText" size="small">
From
</Text>
),
@ -100,7 +100,7 @@ function getColumns(props: any) {
size: "large",
resizeable: false,
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
<Text color="minorText" size="small">
To
</Text>
),
@ -111,7 +111,7 @@ function getColumns(props: any) {
size: "380px",
resizeable: false,
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
<Text color="minorText" size="small">
ONEValue
</Text>
),
@ -125,7 +125,7 @@ function getColumns(props: any) {
property: "timestamp",
resizeable: false,
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300, width: '180px' }}>
<Text color="minorText" size="small" style={{ width: '180px' }}>
Timestamp
</Text>
),
@ -195,8 +195,7 @@ export function TransactionsTable(props: TransactionTableProps) {
direction="row"
justify={hidePagination ? "start" : "between"}
pad={{ bottom: "small" }}
margin={{ bottom: "small" }}
border={{ size: "xsmall", side: "bottom", color: "border" }}
margin={{ bottom: "0" }}
>
{!hideCounter ? (
<Text style={{ flex: "1 1 100%" }}>
@ -239,15 +238,22 @@ export function TransactionsTable(props: TransactionTableProps) {
<TableComponent
alwaysOpenedRowDetails={props.rowDetails ? true : false}
tableProps={{
className: "g-table-header",
className: "g-table-transactions",
style: { width: "100%", minWidth, tableLayout: 'auto' },
columns: columns ? columns : getColumns({ history }),
data: data,
step,
primaryKey: props.primaryKey ? props.primaryKey : undefined,
background: {
header: {
color: 'tableRowHover'
}
},
border: {
header: {
color: "brand",
color: "border",
side: 'top',
size: '1px'
},
body: {
color: "border",

@ -33,12 +33,13 @@ const getColumns = ({ type = "" }) => [
content={
<TipContent
message={
transactionPropertyDescriptions[e.key + type] ||
transactionPropertyDescriptions[e.key]
<Text size={'small'}>
{transactionPropertyDescriptions[e.key + type] ||
transactionPropertyDescriptions[e.key]}
</Text>
}
/>
}
plain
>
<span>
<CircleQuestion size="small" />
@ -187,12 +188,10 @@ export const TransactionDetails: FunctionComponent<TransactionDetailsProps> = ({
data={txData}
step={10}
border={{
header: {
color: "none",
},
header: false,
body: {
color: "border",
side: "top",
side: "bottom",
size: "1px",
},
}}

@ -91,6 +91,7 @@ export const transactionPropertySort: Record<string, number> = {
};
export const transactionPropertyDescriptions: Record<string, string> = {
Status: "The status of the transaction",
shardID: "The shard number where the transaction belongs.",
blockNumber: "The number of the block in which the transaction was recorded.",
hash: "A TxHash or transaction hash is a unique 66 characters identifier that is generated whenever a transaction is executed.",

@ -27,6 +27,7 @@ interface IAddress {
displayHash?: boolean;
noHistoryPush?: boolean;
hideCopyBtn?: boolean;
showLink?: boolean;
}
const AddressText = styled(Text)<{ isShortEllipsis?: boolean }>`
@ -48,6 +49,7 @@ export const Address = (props: IAddress) => {
color = "brand",
displayHash,
hideCopyBtn = false,
showLink = true
} = props;
const history = useHistory();
const ERC20Map = useERC20Pool();
@ -81,13 +83,39 @@ export const Address = (props: IAddress) => {
parsedName = address === EMPTY_ADDRESS ? "0x0" : parsedName;
let outPutAddress = address;
let outPutAddress: string;
try {
outPutAddress = currency === "ONE" ? getAddress(address).bech32 : toChecksumAddress(address);
} catch {
outPutAddress = address;
}
const addressContent = <AddressText
size="small"
color={color}
style={{
marginLeft: hideCopyBtn ? "0px" : "7px",
cursor: showLink ? 'pointer' : 'default',
...style,
}}
isShortEllipsis={isShortEllipsis}
onClick={
address === EMPTY_ADDRESS
? undefined
: props.noHistoryPush
? undefined
: (e) => {
e.preventDefault();
history.push(`/${type}/${address}`);
}
}
>
{parsedName ||
(isShort
? `${outPutAddress.substr(0, 4)}...${outPutAddress.substr(-4)}`
: outPutAddress)}
</AddressText>
return (
<div style={{ display: "inline-block" }}>
<Box direction={"row"} align={"center"} justify={"start"}>
@ -108,39 +136,14 @@ export const Address = (props: IAddress) => {
}}
/>
)}
<Link to={address === EMPTY_ADDRESS ? "" : `/${type}/${address}`}>
<AddressText
size="small"
color={color}
style={{
marginLeft: hideCopyBtn ? "0px" : "7px",
cursor: "pointer",
textDecoration:
address === EMPTY_ADDRESS
? "none"
: !!parsedName
? "underline"
: "none",
...style,
}}
isShortEllipsis={isShortEllipsis}
onClick={
address === EMPTY_ADDRESS
? undefined
: props.noHistoryPush
? undefined
: (e) => {
e.preventDefault();
history.push(`/${type}/${address}`);
}
}
>
{parsedName ||
(isShort
? `${outPutAddress.substr(0, 4)}...${outPutAddress.substr(-4)}`
: outPutAddress)}
</AddressText>
</Link>
{showLink &&
<Link to={address === EMPTY_ADDRESS ? "" : `/${type}/${address}`}>
{addressContent}
</Link>
}
{!showLink &&
addressContent
}
</Box>
</div>
);

@ -56,25 +56,25 @@ export const ONEValue = (props: ONEValueProps) => {
</Text>
{USDValue && +price > 0 && !isTodayTransaction && !hideTip && (
<Tip
dropProps={{ align: { left: "right" }, margin: { left: "small" } }}
dropProps={{ align: { bottom: "top" }}}
content={
<TipContent
showArrow={true}
message={
<span>
<Text size={'small'}>
{`Displaying value on ${dayjs(timestamp).format(
"YYYY-MM-DD"
)}. Current value`}{" "}
)}. Current value:`}{" "}
<b>
$
{formatNumber(v * +lastPrice, {
maximumFractionDigits: 2,
})}
</b>
</span>
</Text>
}
/>
}
plain
>
<Text size="small">(${USDValue})</Text>
</Tip>

@ -173,6 +173,8 @@ export function PaginationRecordsPerPage(props: ElementsPerPage) {
onChange(newFilter);
};
const renderOption = (option: string) => <Box pad={'small'}><Text size={'small'}>{option}</Text></Box>
return (
<Box direction="row" gap="small" align="center">
<Box style={{ width: "105px" }}>
@ -180,7 +182,7 @@ export function PaginationRecordsPerPage(props: ElementsPerPage) {
options={options}
value={limit.toString()}
onChange={onChangeLimit}
/>
>{renderOption}</Select>
</Box>
<Text size="small">records per page</Text>
</Box>

@ -1,13 +1,34 @@
import React from 'react'
import { Box, Text } from 'grommet'
import styled from "styled-components";
import { grommet, Box, Button, Grommet, Heading, Text, Tip } from 'grommet'
import { Trash } from 'grommet-icons'
const ArrowDown = styled(Box)`
position: absolute;
top: 100%;
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid ${(props) => props.theme.global.colors.backgroundTip};
border-bottom: 0 solid transparent;
`
// @ts-ignore
export const TipContent = ({ message }) => (
<Box direction="row" align="center">
<Box background="background" direction="row" pad="small" border={{color: 'border', size: '0px' }}>
<div>{message}</div>
</Box>
export const TipContent = (props: { message: string | JSX.Element, showArrow?: boolean }) => {
let message = props.message
if (typeof message === 'string') {
message = <Text size={'small'}>{message}</Text>
}
return <Box
direction="column"
align="center"
background="backgroundTip"
pad={{ top: 'xxsmall', left: 'small', right: 'small', bottom: 'xxsmall' }}
round={{ size: 'xsmall' }}
style={{ position: 'relative', color: 'white', width: 'fit-content' }}
>
<Box>{message}</Box>
{props.showArrow &&
<ArrowDown border={{ color: '#EFF8FF' }} />
}
</Box>
)
}

@ -29,12 +29,25 @@ a {
background: transparent !important;
}
/* Tooltip override */
body.light > div > div[aria-hidden=false] > div > div {
background: #fff !important;
border: 1px solid #f3f3f3;
box-shadow: none;
background: unset;
}
body.dark > div > div[aria-hidden=false] > div > div {
background: #1b2a5e !important;
border: 1px solid #3a54b3;
box-shadow: none;
background: unset;
}
table:not(.g-table-transactions) tr:hover {
background: none;
}
table:not(.g-table-transactions) thead tr:first-child th, table:not(.g-table-transactions) thead tr:first-child td {
border: none;
}
.g-table-transactions thead tr th {
font-weight: 700;
}

@ -262,15 +262,15 @@ const addressPropertyDisplayValues: Record<
formatNumber
/>
<Tip
dropProps={{ align: { left: "right" } }}
dropProps={{ align: { bottom: "top" }}}
content={
<TipContent
message={`last update block height ${formatNumber(
showArrow={true}
message={`Last update block height: ${formatNumber(
+data.lastUpdateBlockNumber
)}`}
/>
}
plain
>
<span style={{ marginLeft: "5px" }}>
<CircleQuestion size="small" />
@ -283,15 +283,15 @@ const addressPropertyDisplayValues: Record<
<Box direction={"row"}>
<>{formatNumber(+value)}</>
<Tip
dropProps={{ align: { left: "right" } }}
dropProps={{ align: { bottom: "top" }}}
content={
<TipContent
message={`last update block height ${formatNumber(
showArrow={true}
message={`Last update block height: ${formatNumber(
+data.lastUpdateBlockNumber
)}`}
/>
}
plain
>
<span style={{ marginLeft: "5px" }}>
<CircleQuestion size="small" />
@ -312,15 +312,15 @@ const addressPropertyDisplayValues: Record<
formatNumber
/>
<Tip
dropProps={{ align: { left: "right" } }}
dropProps={{ align: { bottom: "top" }}}
content={
<TipContent
message={`last update block height ${formatNumber(
showArrow={true}
message={`Last update block height: ${formatNumber(
+data.lastUpdateBlockNumber
)}`}
/>
}
plain
>
<span style={{ marginLeft: "5px" }}>
<CircleQuestion size="small" />

@ -179,7 +179,6 @@ export function TokensInfo(props: { value: Token[] }) {
<Tip
dropProps={{ align: { left: "right" } }}
content={<TipContent message={"Outdated"} />}
plain
>
<span>
<Alert size="small" />

@ -16,7 +16,7 @@ import { useHistory, useParams } from "react-router-dom";
import { useERC20Pool } from "src/hooks/ERC20_Pool";
import { useERC721Pool } from "src/hooks/ERC721_Pool";
import { useERC1155Pool } from "src/hooks/ERC1155_Pool";
import { Transactions } from "./tabs/Transactions";
import { Transactions } from "./tabs/transactions/Transactions";
import {
IUserERC721Assets,
TRelatedTransaction,

@ -10,6 +10,7 @@ import {
} from "../../../../api/client";
import styled from "styled-components";
import { DisplaySignature, parseSuggestedEvent } from "../../../../web3/parseByteCode";
import { TipContent } from "../../../../components/ui";
const TopicsContainer = styled.div`
text-align: left;
@ -66,12 +67,15 @@ const CenteredContainer = styled.div`
function TxsHashColumn (props: { log: LogWithSignature }) {
const { log } = props
return <div style={{ width: '140px' }}>
<Tip content={'Txn Hash'}>
<Tip
dropProps={{ align: { bottom: "top" }}}
content={<TipContent showArrow={true} message={'Txn Hash'} />}
>
<Link to={`/tx/${log.transactionHash}`}>
<LinkText>{log.transactionHash}</LinkText>
</Link>
</Tip>
<Tip content={'Block number'}>
<Tip dropProps={{ align: { bottom: "top" }}} content={<TipContent showArrow={true} message={'Block number'} />}>
<div style={{ display: 'flex', marginTop: '4px' }}>
#&nbsp;
<Link to={`/block/${log.blockNumber}`} style={{ display: 'inline-block' }}>
@ -80,7 +84,10 @@ function TxsHashColumn (props: { log: LogWithSignature }) {
</div>
</Tip>
{log.timestamp &&
<Tip content={dayjs(log.timestamp).format('MMM-DD-YYYY hh:mm:ss a') }>
<Tip
dropProps={{ align: { bottom: "top" }}}
content={<TipContent showArrow={true} message={dayjs(log.timestamp).format('MMM-DD-YYYY hh:mm:ss a')} />}
>
<div style={{ marginTop: '4px' }}>{dayjs(log.timestamp).fromNow()}</div>
</Tip>
}
@ -92,7 +99,7 @@ function TxMethod (props: { log: LogWithSignature }) {
return <div style={{ width: '140px' }}>
<Text size="12px">
<Tip content={'MethodID'}>
<Tip dropProps={{ align: { bottom: "top" }}} content={<TipContent showArrow={true} message={'MethodID'} />}>
<NeutralMarker background={"backgroundBack"} width={'100px'}>
<TextEllipsis>{props.log.input.slice(0, 10)}</TextEllipsis>
</NeutralMarker>

@ -14,14 +14,14 @@ import {
} from "src/types";
import { TRelatedTransaction } from "src/api/client.interface";
import { getAddress, mapBlockchainTxToRelated } from "src/utils";
import { ExportToCsvButton } from "../../../components/ui/ExportToCsvButton";
import { ExportToCsvButton } from "../../../../components/ui/ExportToCsvButton";
import {
hmyv2_getStakingTransactionsCount, hmyv2_getStakingTransactionsHistory,
hmyv2_getTransactionsCount,
hmyv2_getTransactionsHistory
} from "../../../api/rpc";
import { getColumns, getERC20Columns, getNFTColumns, getStackingColumns } from "./txsColumns";
import useQuery from "../../../hooks/useQuery";
} from "../../../../api/rpc";
import { getColumns, getERC20Columns, getNFTColumns, getStakingColumns } from "./columns";
import useQuery from "../../../../hooks/useQuery";
const internalTxsBlocksFrom = 23000000
const allowedLimits = [10, 25, 50, 100]
@ -217,7 +217,7 @@ export function Transactions(props: {
switch (props.type) {
case "staking_transaction": {
columns = getStackingColumns(id);
columns = getStakingColumns(id);
break;
}
case "erc20": {

@ -0,0 +1,164 @@
import { Box, ColumnConfig, Text, Tip } from "grommet";
import React from "react";
import { Address, DateTime, ONEValue, TokenValue } from "src/components/ui";
import { Log, RelatedTransaction, Topic } from "src/types";
import { parseSuggestedEvent } from "src/web3/parseByteCode";
import styled, { css } from "styled-components";
import { ABIManager, IABI } from "src/web3/ABIManager";
import ERC721ABI from "src/web3/abi/ERC721ABI.json";
import ERC1155ABI from "src/web3/abi/ERC1155ABI.json";
const erc721ABIManager = ABIManager(ERC721ABI as IABI)
const erc1155ABIManager = ABIManager(ERC1155ABI as IABI)
export const transferSignature = erc721ABIManager.getEntryByName('Transfer')!.signature
export const transferSingleSignature = erc1155ABIManager.getEntryByName('TransferSingle')!.signature
export const erc20TransferTopic =
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
export type TxDirection = 'in' | 'out' | 'self'
export const Marker = styled.div<{ direction: TxDirection }>`
border-radius: 4px;
padding: 6px 3px;
width: 32px;
text-align: center;
font-weight: bold;
font-size: 90%;
${(props) =>
props.direction === 'self'
? css`
background: ${(props) => props.theme.global.colors.backgroundBack};
`
: props.direction === 'out'
? css`
color: ${(props) => props.theme.global.colors.warning};
background: ${(props) => props.theme.global.colors.warningBackground};
`
: css`
color: ${(props) => props.theme.global.colors.success};
background: ${(props) => props.theme.global.colors.successBackground}
`};
`
export const TxMethod = styled(Text)`
width: 100px;
display: block;
border-radius: 4px;
padding: 2px 4px;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
background: ${(props) => props.theme.global.colors.backgroundMark};
font-size: 12px;
`
export const TextEllipsis = styled(Text)`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`
export const memo = (f: Function) => {
const cache = new Map()
return (data: any) => {
const hash: string = data.hash + (data.logs ? data.logs.length : '')
if (cache.has(hash)) {
return cache.get(hash)
}
const res = f(data)
const { parsed } = res
if (!parsed) {
return res
}
cache.set(hash, res)
return res
}
}
// take only first related at the moment
export const extractTransfer = memo((data: any) => {
const { relatedAddress } = data
const transferLogs = data.logs ? data.logs
.filter((d: any) => d.topics.includes(erc20TransferTopic)) : []
for (let i = 0; i < transferLogs.length; i++) {
const transferLog = transferLogs[i]
const event = parseSuggestedEvent('Transfer(address,address,uint256)', transferLog.data, transferLog.topics) || null
if (!event) {
continue
}
event.parsed['$0'] = event.parsed['$0'].toLowerCase()
event.parsed['$1'] = event.parsed['$1'].toLowerCase()
if (relatedAddress === event.parsed['$0'] || relatedAddress === event.parsed['$1']) {
return {
transferLog: transferLog || {},
parsed: event.parsed || {}
}
}
}
return {
transferLog: {},
parsed: {}
}
})
export const extractTokenId = memo((data: any) => {
const { transactionType, logs = [] } = data
const eventType = transactionType === 'erc721' ? 'Transfer' : 'TransferSingle'
const signature = transactionType === 'erc721' ? transferSignature : transferSingleSignature
const abi = transactionType === 'erc721' ? erc721ABIManager : erc1155ABIManager
const transferLogs = logs.filter(({ topics }: { topics: Topic[] }) => topics.includes(signature))
if (transferLogs.length > 0) {
try {
const log = transferLogs[0]
const [topic0, ...topics] = log.topics
const {tokenId, id} = abi.decodeLog(eventType, log.data, topics)
if (tokenId || id) {
return tokenId || id
}
} catch (e) {
console.error('Cannot decode log', (e as Error).message)
return ''
}
}
return ''
})
export const TransactionAddress = (props: { id: string, address: string, width?: string }) => {
const { id: rootAddress, address, width = '120px' } = props
const isRootAddress = rootAddress === address
return <Text size="12px">
<Address
isShortEllipsis={true}
address={props.address}
color={isRootAddress ? 'text' : 'brand'}
showLink={!isRootAddress}
style={{ width }}
/>
</Text>
}
export const TransferDirectionMarker = (props: { id: string, data: RelatedTransaction }) => {
const { id, data: { from, to } } = props
let direction: TxDirection = from === id ? 'out' : 'in'
if (from === to) {
direction = 'self'
}
return <Text size="12px">
<Marker direction={direction}>{direction.toUpperCase()}</Marker>
</Text>
}

@ -0,0 +1,141 @@
import { Box, ColumnConfig, Text } from "grommet";
import { Address, DateTime, TokenValue } from "../../../../../components/ui";
import { RelatedTransaction } from "../../../../../types";
import React from "react";
import { TransactionAddress, TransferDirectionMarker, TxMethod } from "./common";
export function getERC20Columns(id: string): ColumnConfig<any>[] {
return [
{
property: 'hash',
header: (
<Text
color="minorText"
size="small"
style={{ width: '95px' }}
>
Hash
</Text>
),
render: (data: any) => (
<Address address={data.transactionHash || data.hash} type="tx" isShortEllipsis={true} style={{ width: '170px' }} />
)
},
{
property: 'event',
header: (
<Text color="minorText" size="small">
Event
</Text>
),
render: (data: any) => {
const eventType = data.eventType || '-'
return (
<TxMethod>{eventType}</TxMethod>
)
}
},
{
property: 'from',
header: (
<Text
color="minorText"
size="small"
style={{ width: '120px' }}
>
From
</Text>
),
render: (data: RelatedTransaction) => <TransactionAddress id={id} address={data.from} />
},
{
property: 'marker',
header: <></>,
render: (data: RelatedTransaction) => <TransferDirectionMarker id={id} data={data} />
},
{
property: 'to',
header: (
<Text
color="minorText"
size="small"
style={{ width: '120px' }}
>
To
</Text>
),
render: (data: RelatedTransaction) => <TransactionAddress id={id} address={data.to} />
},
{
property: 'value',
header: (
<Text
color="minorText"
size="small"
style={{ width: '320px' }}
>
Value
</Text>
),
render: (data: any) => {
const { address, value, eventType } = data
if (!value) {
return '?'
}
if (eventType === 'Approval') {
return (
<Box direction={'row'} gap={'4px'}>
<TokenValue isShort={true} tokenAddress={address} value={value} />
</Box>)
}
return (
<Text size="12px">
<TokenValue tokenAddress={address} value={value} />
</Text>)
}
},
{
property: 'token',
header: (
<Text
color="minorText"
size="small"
style={{ width: '120px' }}
>
Token
</Text>
),
render: (data: any) => {
const address = data.address ? data.address : '—'
return (
<Text size="12px">
<Address address={address} />
</Text>
)
}
},
{
property: 'timestamp',
header: (
<Text
color="minorText"
size="small"
style={{ width: '140px' }}
>
Timestamp
</Text>
),
render: (data: RelatedTransaction) => (
<Box direction="row" gap="xsmall" justify="end">
<DateTime
date={data.timestamp}
/>
</Box>
)
}
]
}

@ -0,0 +1,11 @@
import { getColumns } from "./transactions";
import { getStakingColumns } from './staking'
import { getERC20Columns } from './erc20'
import { getNFTColumns } from './nft'
export {
getColumns,
getStakingColumns,
getERC20Columns,
getNFTColumns,
}

@ -0,0 +1,160 @@
import { Box, ColumnConfig, Text, Tip } from "grommet";
import React from "react";
import { RelatedTransaction } from "../../../../../types";
import { Address, DateTime } from "../../../../../components/ui";
import {
extractTokenId,
TextEllipsis,
TransactionAddress,
TransferDirectionMarker,
TxMethod
} from "./common";
export function getNFTColumns(id: string): ColumnConfig<any>[] {
return [
{
property: "hash",
header: (
<Text
color="minorText"
size="small"
style={{ width: "95px" }}
>
Hash
</Text>
),
render: (data: any) => (
<Address
address={data.transactionHash || data.hash}
type="tx"
isShortEllipsis={true}
style={{ width: "170px" }}
/>
),
},
{
property: 'event',
header: (
<Text color="minorText" size="small">
Event
</Text>
),
render: (data: any) => {
const eventType = data.eventType || '-'
return (
<TxMethod>{eventType}</TxMethod>
)
}
},
{
property: "from",
header: (
<Text
color="minorText"
size="small"
style={{ width: "180px" }}
>
From
</Text>
),
render: (data: RelatedTransaction) => <TransactionAddress id={id} address={data.from} width={'180px'} />,
},
{
property: "marker",
header: <></>,
render: (data: RelatedTransaction) => <TransferDirectionMarker id={id} data={data} />,
},
{
property: "to",
header: (
<Text
color="minorText"
size="small"
style={{ width: "180px" }}
>
To
</Text>
),
render: (data: RelatedTransaction) => data.to.trim() && <TransactionAddress id={id} address={data.to} width={'180px'} />,
},
// {
// property: "value",
// header: (
// <Text
// color="minorText"
// size="small"
// style={{ width: "120px" }}
// >
// Value
// </Text>
// ),
// render: (data: RelatedTransaction) => (
// <Box justify="center">
// <ONEValue value={data.value} timestamp={data.timestamp} />
// </Box>
// ),
// },
{
property: 'tokenId',
header: (
<Text
color="minorText"
size="small"
style={{ width: '120px' }}
>
TokenId
</Text>
),
render: (data: any) => {
const tokenId = extractTokenId(data)
return (
<Tip content={tokenId}>
<TextEllipsis size="12px" style={{ width: '115px' }}>
{tokenId}
</TextEllipsis>
</Tip>
)
}
},
{
property: 'token',
header: (
<Text
color="minorText"
size="small"
style={{ width: '120px' }}
>
Token
</Text>
),
render: (data: any) => {
const address = data.address ? data.address : '—'
return (
<Text size="12px">
<Address address={address} />
</Text>
)
}
},
{
property: "timestamp",
header: (
<Text
color="minorText"
size="small"
style={{ width: "140px" }}
>
Timestamp
</Text>
),
render: (data: RelatedTransaction) => (
<Box direction="row" gap="xsmall" justify="end">
<DateTime
date={data.timestamp}
/>
</Box>
),
},
];
}

@ -0,0 +1,122 @@
import { Box, ColumnConfig, Text } from "grommet";
import React from "react";
import { RelatedTransaction } from "../../../../../types";
import { Address, DateTime, ONEValue } from "../../../../../components/ui";
import { TransactionAddress, TransferDirectionMarker } from "./common";
export const getStakingColumns = (id: string): ColumnConfig<any>[] => {
return [
{
property: "hash",
header: (
<Text
color="minorText"
size="small"
style={{ width: "95px" }}
>
Hash
</Text>
),
render: (data: any) => (
<Address
address={data.transactionHash || data.hash}
type="staking-tx"
isShortEllipsis={true}
style={{ width: "170px" }}
/>
),
},
{
property: "type",
header: (
<Text
color="minorText"
size="small"
style={{ width: "140px" }}
>
Type
</Text>
),
render: (data: RelatedTransaction) => (
<Text size="small" style={{ width: "140px" }}>
{data.type}
</Text>
),
},
{
property: "validator",
header: (
<Text
color="minorText"
size="small"
style={{ width: "170px" }}
>
Validator
</Text>
),
render: (data: RelatedTransaction) => data.msg?.validatorAddress
? <TransactionAddress id={id} address={data.msg?.validatorAddress || data.from} width={'170px'} />
: '—'
},
{
property: "marker",
header: <></>,
render: (data: RelatedTransaction) => <TransferDirectionMarker id={id} data={data} />,
},
{
property: "delegator",
header: (
<Text
color="minorText"
size="small"
style={{ width: "170px" }}
>
Delegator
</Text>
),
render: (data: RelatedTransaction) => data.msg?.delegatorAddress
? <TransactionAddress id={id} address={data.msg?.delegatorAddress} width={'170px'} />
: '—',
},
{
property: "value",
header: (
<Text
color="minorText"
size="small"
style={{ width: "220px" }}
>
Value
</Text>
),
render: (data: RelatedTransaction) => (
<Box justify="center">
{data.msg?.amount ? (
<ONEValue value={data.msg?.amount} timestamp={data.timestamp} />
) : data.amount ? (
<ONEValue value={data.amount} timestamp={data.timestamp} />
) : (
"—"
)}
</Box>
),
},
{
property: "timestamp",
header: (
<Text
color="minorText"
size="small"
style={{ width: "140px" }}
>
Timestamp
</Text>
),
render: (data: RelatedTransaction) => (
<Box direction="row" gap="xsmall" justify="end">
<DateTime date={data.timestamp} />
</Box>
),
},
];
};

@ -0,0 +1,177 @@
import { Box, ColumnConfig, Text, Tip } from "grommet";
import React from "react";
import { RelatedTransaction } from "../../../../../types";
import { Address, DateTime, ONEValue, TipContent } from "../../../../../components/ui";
import { TransactionAddress, TransferDirectionMarker, TxMethod } from "./common";
export function getColumns(id: string): ColumnConfig<any>[] {
return [
// {
// property: "type",
// size: "",
// header: (
// <Text
// color="minorText"
// size="small"
// style={{ width: "140px" }}
// >
// Type
// </Text>
// ),
// render: (data: RelatedTransaction) => (
// <Text size="small" style={{ width: "140px" }}>
// {relatedTxMap[data.transactionType] || data.transactionType}
// </Text>
// ),
// },
{
property: "hash",
header: (
<Text
color="minorText"
size="small"
style={{ width: "95px" }}
>
Hash
</Text>
),
render: (data: any) => (
<Address
address={data.transactionHash || data.hash}
type="tx"
isShortEllipsis={true}
style={{ width: "170px" }}
/>
),
},
{
property: "method",
header: (
<Text color="minorText" size="small">
Method
</Text>
),
render: (data: any) => {
let signature;
try {
// @ts-ignore
signature =
data.signatures &&
data.signatures.map((s: any) => s.signature)[0].split("(")[0];
} catch (err) {}
if (!signature && data.value !== "0") {
signature = "transfer";
}
if (!signature && data.input.length >= 10) {
signature = data.input.slice(2, 10);
}
if (!signature) {
return <Text size="small">{"—"}</Text>;
}
const tipContent = <TipContent
showArrow={true}
message={<Text size={'small'} textAlign={'center'}>{signature}</Text>}
/>
return (
<Tip
dropProps={{ align: { bottom: "top" }}}
content={tipContent}
>
<TxMethod>{signature}</TxMethod>
</Tip>
);
},
},
// {
// property: "shard",
// header: (
// <Text color="minorText" size="small">
// Shard
// </Text>
// ),
// render: (data: RelatedTransaction) => (
// <Box direction="row" gap="3px" align="center">
// <Text size="small">{0}</Text>
// <FormNextLink
// size="small"
// color="brand"
// style={{ marginBottom: "2px" }}
// />
// <Text size="small">{0}</Text>
// </Box>
// ),
// },
{
property: "from",
header: (
<Text
color="minorText"
size="small"
style={{ width: "180px" }}
>
From
</Text>
),
render: (data: RelatedTransaction) => <TransactionAddress id={id} address={data.from} width={'180px'} />,
},
{
property: "marker",
header: <></>,
render: (data: RelatedTransaction) => <TransferDirectionMarker id={id} data={data} />,
},
{
property: "to",
header: (
<Text
color="minorText"
size="small"
style={{ width: "180px" }}
>
To
</Text>
),
render: (data: RelatedTransaction) => <TransactionAddress id={id} address={data.to} width={'180px'} />,
},
{
property: "value",
header: (
<Text
color="minorText"
size="small"
style={{ width: "120px" }}
>
Value
</Text>
),
render: (data: RelatedTransaction) => (
<Box justify="center">
<ONEValue value={data.value} timestamp={data.timestamp} />
</Box>
),
},
{
property: "timestamp",
header: (
<Text
color="minorText"
size="small"
style={{ width: "140px" }}
>
Timestamp
</Text>
),
render: (data: RelatedTransaction) => (
<Box direction="row" gap="xsmall" justify="end">
<DateTime date={data.timestamp} />
</Box>
),
},
];
}

@ -1,778 +0,0 @@
import { Box, ColumnConfig, Text, Tip } from "grommet";
import { Address, DateTime, ONEValue, TokenValue } from "../../../components/ui";
import { Log, RelatedTransaction, Topic } from "../../../types";
import React from "react";
import { parseSuggestedEvent } from "../../../web3/parseByteCode";
import styled, { css } from "styled-components";
import { ABIManager, IABI } from "../../../web3/ABIManager";
import ERC721ABI from "../../../web3/abi/ERC721ABI.json";
import ERC1155ABI from "../../../web3/abi/ERC1155ABI.json";
const erc721ABIManager = ABIManager(ERC721ABI as IABI)
const erc1155ABIManager = ABIManager(ERC1155ABI as IABI)
const transferSignature = erc721ABIManager.getEntryByName('Transfer')!.signature
const transferSingleSignature = erc1155ABIManager.getEntryByName('TransferSingle')!.signature
const erc20TransferTopic =
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
type TxDirection = 'in' | 'out' | 'self'
const Marker = styled.div<{ direction: TxDirection }>`
border-radius: 2px;
padding: 5px;
text-align: center;
font-weight: bold;
${(props) =>
props.direction === 'self'
? css`
background: ${(props) => props.theme.global.colors.backgroundBack};
`
: props.direction === 'out'
? css`
background: rgb(239 145 62);
color: #fff;
`
: css`
background: rgba(105, 250, 189, 0.8);
color: #1b295e;
`};
`
const NeutralMarker = styled(Box)`
border-radius: 2px;
padding: 5px;
text-align: center;
`
const TxMethod = styled(Text)`
width: 100px;
> div {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
`
const TextEllipsis = styled(Text)`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`
const memo = (f: Function) => {
const cache = new Map()
return (data: any) => {
const hash: string = data.hash + (data.logs ? data.logs.length : '')
if (cache.has(hash)) {
return cache.get(hash)
}
const res = f(data)
const { parsed } = res
if (!parsed) {
return res
}
cache.set(hash, res)
return res
}
}
// take only first related at the moment
const extractTransfer = memo((data: any) => {
const { relatedAddress } = data
const transferLogs = data.logs ? data.logs
.filter((d: any) => d.topics.includes(erc20TransferTopic)) : []
for (let i = 0; i < transferLogs.length; i++) {
const transferLog = transferLogs[i]
const event = parseSuggestedEvent('Transfer(address,address,uint256)', transferLog.data, transferLog.topics) || null
if (!event) {
continue
}
event.parsed['$0'] = event.parsed['$0'].toLowerCase()
event.parsed['$1'] = event.parsed['$1'].toLowerCase()
if (relatedAddress === event.parsed['$0'] || relatedAddress === event.parsed['$1']) {
return {
transferLog: transferLog || {},
parsed: event.parsed || {}
}
}
}
return {
transferLog: {},
parsed: {}
}
})
const extractTokenId = memo((data: any) => {
const { transactionType, logs = [] } = data
const eventType = transactionType === 'erc721' ? 'Transfer' : 'TransferSingle'
const signature = transactionType === 'erc721' ? transferSignature : transferSingleSignature
const abi = transactionType === 'erc721' ? erc721ABIManager : erc1155ABIManager
const transferLogs = logs.filter(({ topics }: { topics: Topic[] }) => topics.includes(signature))
if (transferLogs.length > 0) {
try {
const log = transferLogs[0]
const [topic0, ...topics] = log.topics
const {tokenId, id} = abi.decodeLog(eventType, log.data, topics)
if (tokenId || id) {
return tokenId || id
}
} catch (e) {
console.error('Cannot decode log', (e as Error).message)
return ''
}
}
return ''
})
const TransferDirectionMarker = (props: { id: string, data: RelatedTransaction }) => {
const { id, data: { from, to } } = props
let direction: TxDirection = from === id ? 'out' : 'in'
if (from === to) {
direction = 'self'
}
return <Text size="12px">
<Marker direction={direction}>{direction.toUpperCase()}</Marker>
</Text>
}
export function getERC20Columns(id: string): ColumnConfig<any>[] {
return [
{
property: 'hash',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '95px' }}
>
Hash
</Text>
),
render: (data: any) => (
<Address address={data.transactionHash || data.hash} type="tx" isShortEllipsis={true} style={{ width: '170px' }} />
)
},
{
property: 'event',
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
Event
</Text>
),
render: (data: any) => {
const eventType = data.eventType || '-'
return (
<TxMethod size="10px">
<NeutralMarker background={'backgroundBack'}>
{eventType}
</NeutralMarker>
</TxMethod>
)
}
},
{
property: 'from',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '120px' }}
>
From
</Text>
),
render: (data: RelatedTransaction) => {
const { from } = data
return (
<Text size="12px">
<Address isShortEllipsis={true} address={from} style={{ width: '120px' }} />
</Text>)
}
},
{
property: 'marker',
header: <></>,
render: (data: RelatedTransaction) => <TransferDirectionMarker id={id} data={data} />
},
{
property: 'to',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '120px' }}
>
To
</Text>
),
render: (data: RelatedTransaction) => {
const { to } = data
return (
<Text size="12px">
<Address isShortEllipsis={true} address={to} style={{ width: '120px' }} />
</Text>)
}
},
{
property: 'value',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '320px' }}
>
Value
</Text>
),
render: (data: any) => {
const { address, value, eventType } = data
if (!value) {
return '?'
}
if (eventType === 'Approval') {
return (
<Box direction={'row'} gap={'4px'}>
<TokenValue isShort={true} tokenAddress={address} value={value} />
</Box>)
}
return (
<Text size="12px">
<TokenValue tokenAddress={address} value={value} />
</Text>)
}
},
{
property: 'token',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '120px' }}
>
Token
</Text>
),
render: (data: any) => {
const address = data.address ? data.address : '—'
return (
<Text size="12px">
<Address address={address} />
</Text>
)
}
},
{
property: 'timestamp',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '140px' }}
>
Timestamp
</Text>
),
render: (data: RelatedTransaction) => (
<Box direction="row" gap="xsmall" justify="end">
<DateTime
date={data.timestamp}
/>
</Box>
)
}
]
}
export function getColumns(id: string): ColumnConfig<any>[] {
return [
// {
// property: "type",
// size: "",
// header: (
// <Text
// color="minorText"
// size="small"
// style={{ fontWeight: 300, width: "140px" }}
// >
// Type
// </Text>
// ),
// render: (data: RelatedTransaction) => (
// <Text size="small" style={{ width: "140px" }}>
// {relatedTxMap[data.transactionType] || data.transactionType}
// </Text>
// ),
// },
{
property: "hash",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "95px" }}
>
Hash
</Text>
),
render: (data: any) => (
<Address
address={data.transactionHash || data.hash}
type="tx"
isShortEllipsis={true}
style={{ width: "170px" }}
/>
),
},
{
property: "method",
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
Method
</Text>
),
render: (data: any) => {
let signature;
try {
// @ts-ignore
signature =
data.signatures &&
data.signatures.map((s: any) => s.signature)[0].split("(")[0];
} catch (err) {}
if (!signature && data.value !== "0") {
signature = "transfer";
}
if (!signature && data.input.length >= 10) {
signature = data.input.slice(2, 10);
}
if (!signature) {
return <Text size="small">{"—"}</Text>;
}
return (
<Tip content={<span>{signature}</span>}>
<TxMethod size="10px">
<NeutralMarker background={"backgroundBack"}>
{signature}
</NeutralMarker>
</TxMethod>
</Tip>
);
},
},
// {
// property: "shard",
// header: (
// <Text color="minorText" size="small" style={{ fontWeight: 300 }}>
// Shard
// </Text>
// ),
// render: (data: RelatedTransaction) => (
// <Box direction="row" gap="3px" align="center">
// <Text size="small">{0}</Text>
// <FormNextLink
// size="small"
// color="brand"
// style={{ marginBottom: "2px" }}
// />
// <Text size="small">{0}</Text>
// </Box>
// ),
// },
{
property: "from",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "180px" }}
>
From
</Text>
),
render: (data: RelatedTransaction) => (
<Text size="12px">
<Address address={data.from} isShortEllipsis={true} style={{ width: '180px' }} />
</Text>
),
},
{
property: "marker",
header: <></>,
render: (data: RelatedTransaction) => <TransferDirectionMarker id={id} data={data} />,
},
{
property: "to",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "180px" }}
>
To
</Text>
),
render: (data: RelatedTransaction) => (
<Text size="12px">
<Address address={data.to} isShortEllipsis={true} style={{ width: '180px' }} />
</Text>
),
},
{
property: "value",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "120px" }}
>
Value
</Text>
),
render: (data: RelatedTransaction) => (
<Box justify="center">
<ONEValue value={data.value} timestamp={data.timestamp} />
</Box>
),
},
{
property: "timestamp",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "140px" }}
>
Timestamp
</Text>
),
render: (data: RelatedTransaction) => (
<Box direction="row" gap="xsmall" justify="end">
<DateTime
date={data.timestamp}
/>
</Box>
),
},
];
}
export function getNFTColumns(id: string): ColumnConfig<any>[] {
return [
{
property: "hash",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "95px" }}
>
Hash
</Text>
),
render: (data: any) => (
<Address
address={data.transactionHash || data.hash}
type="tx"
isShortEllipsis={true}
style={{ width: "170px" }}
/>
),
},
{
property: 'event',
header: (
<Text color="minorText" size="small" style={{ fontWeight: 300 }}>
Event
</Text>
),
render: (data: any) => {
const eventType = data.eventType || '-'
return (
<TxMethod size="10px">
<NeutralMarker background={'backgroundBack'}>
{eventType}
</NeutralMarker>
</TxMethod>
)
}
},
{
property: "from",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "180px" }}
>
From
</Text>
),
render: (data: RelatedTransaction) => (
<Text size="12px">
<Address address={data.from} isShortEllipsis={true} style={{ width: '180px' }} />
</Text>
),
},
{
property: "marker",
header: <></>,
render: (data: RelatedTransaction) => <TransferDirectionMarker id={id} data={data} />,
},
{
property: "to",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "180px" }}
>
To
</Text>
),
render: (data: RelatedTransaction) => {
return (
<Text size="12px">
{data.to.trim() && <Address address={data.to} isShortEllipsis={true} style={{ width: '180px' }} />}
</Text>
)
},
},
// {
// property: "value",
// header: (
// <Text
// color="minorText"
// size="small"
// style={{ fontWeight: 300, width: "120px" }}
// >
// Value
// </Text>
// ),
// render: (data: RelatedTransaction) => (
// <Box justify="center">
// <ONEValue value={data.value} timestamp={data.timestamp} />
// </Box>
// ),
// },
{
property: 'tokenId',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '120px' }}
>
TokenId
</Text>
),
render: (data: any) => {
const tokenId = extractTokenId(data)
return (
<Tip content={tokenId}>
<TextEllipsis size="12px" style={{ width: '115px' }}>
{tokenId}
</TextEllipsis>
</Tip>
)
}
},
{
property: 'token',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '120px' }}
>
Token
</Text>
),
render: (data: any) => {
const address = data.address ? data.address : '—'
return (
<Text size="12px">
<Address address={address} />
</Text>
)
}
},
{
property: "timestamp",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "140px" }}
>
Timestamp
</Text>
),
render: (data: RelatedTransaction) => (
<Box direction="row" gap="xsmall" justify="end">
<DateTime
date={data.timestamp}
/>
</Box>
),
},
];
}
export const getStackingColumns = (id: string): ColumnConfig<any>[] => {
return [
{
property: "hash",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "95px" }}
>
Hash
</Text>
),
render: (data: any) => (
<Address
address={data.transactionHash || data.hash}
type="staking-tx"
isShortEllipsis={true}
style={{ width: "170px" }}
/>
),
},
{
property: "type",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "140px" }}
>
Type
</Text>
),
render: (data: RelatedTransaction) => (
<Text size="small" style={{ width: "140px" }}>
{data.type}
</Text>
),
},
{
property: "validator",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "170px" }}
>
Validator
</Text>
),
render: (data: RelatedTransaction) => (
<Text size="12px">
{data.msg?.validatorAddress ? (
<Address address={data.msg?.validatorAddress || data.from} isShortEllipsis={true} style={{ width: "170px" }} />
) : (
"—"
)}
</Text>
),
},
{
property: "marker",
header: <></>,
render: (data: RelatedTransaction) => <TransferDirectionMarker id={id} data={data} />,
},
{
property: "delegator",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "170px" }}
>
Delegator
</Text>
),
render: (data: RelatedTransaction) => (
<Text size="12px">
{data.msg?.delegatorAddress ? (
<Address address={data.msg?.delegatorAddress} isShortEllipsis={true} style={{ width: "170px" }} />
) : (
"—"
)}
</Text>
),
},
{
property: "value",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "220px" }}
>
Value
</Text>
),
render: (data: RelatedTransaction) => (
<Box justify="center">
{data.msg?.amount ? (
<ONEValue value={data.msg?.amount} timestamp={data.timestamp} />
) : data.amount ? (
<ONEValue value={data.amount} timestamp={data.timestamp} />
) : (
"—"
)}
</Box>
),
},
{
property: "timestamp",
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: "140px" }}
>
Timestamp
</Text>
),
render: (data: RelatedTransaction) => (
<Box direction="row" gap="xsmall" justify="end">
<DateTime date={data.timestamp} />
</Box>
),
},
];
};

@ -167,14 +167,21 @@ export function AllBlocksTable() {
</Box>
<Box style={{ overflow: "auto" }}>
<DataTable
className={"g-table-header"}
className={"g-table-transactions"}
style={{ width: "100%", minWidth: "1110px" }}
columns={getColumns({ history, shardNumber })}
data={blocks}
step={10}
background={{
header: {
color: 'tableRowHover'
}
}}
border={{
header: {
color: "brand",
color: "border",
side: 'top',
size: '1px'
},
body: {
color: "border",

@ -87,15 +87,14 @@ export function ERC1155Table(props: TransactionTableProps) {
columns={getColumns({ history })}
data={data}
border={{
header: {
color: "brand",
},
header: false,
body: {
color: "border",
side: "top",
side: "bottom",
size: "1px",
},
}}
background={{header: 'unset'}}
/>
</Box>
<Box
@ -146,7 +145,7 @@ function getColumns(props: any) {
render: (data: Erc20) => <Box direction={'row'} style={{ display: 'flex', alignItems: 'center' }}>
<Text size={'small'}>{data.name}</Text>
{data.isBridged && <div style={{ marginLeft: "4px", height: '14px', cursor: 'pointer' }}>
<Tip content={'Token is available on Harmony Bridge'}>
<Tip dropProps={{ align: { bottom: "top" }}} content={<TipContent showArrow={true} message={'Token is available on Harmony Bridge'} />}>
<StatusGood size={'14px'} color={'successText'} />
</Tip>
</div>}
@ -204,12 +203,11 @@ function getColumns(props: any) {
dropProps={{ align: { right: "left" } }}
content={
<TipContent
message={`last update block height ${formatNumber(
message={`Last update block height: ${formatNumber(
+data.lastUpdateBlockNumber
)}`}
/>
}
plain
>
<span style={{ marginLeft: "5px" }}>
<CircleQuestion size="small" />

@ -87,15 +87,14 @@ export function ERC20Table(props: TransactionTableProps) {
primaryKey={'address'}
data={data}
border={{
header: {
color: "brand",
},
header: false,
body: {
color: "border",
side: "top",
side: "bottom",
size: "1px",
},
}}
background={{header: 'unset'}}
/>
</Box>
<Box
@ -132,7 +131,7 @@ function getColumns(props: any) {
render: (data: Erc20) => <Box direction={'row'} style={{ display: 'flex', alignItems: 'center' }}>
<Text size={'small'}>{data.name}</Text>
{data.isBridged && <div style={{ marginLeft: "4px", height: '14px', cursor: 'pointer' }}>
<Tip content={'Token is available on Harmony Bridge'}>
<Tip dropProps={{ align: { bottom: "top" }}} content={<TipContent showArrow={true} message={'Token is available on Harmony Bridge'} />}>
<StatusGood size={'14px'} color={'successText'} />
</Tip>
</div>}
@ -181,12 +180,11 @@ function getColumns(props: any) {
dropProps={{ align: { left: "right" } }}
content={
<TipContent
message={`last update block height ${formatNumber(
message={`Last update block height: ${formatNumber(
+data.lastUpdateBlockNumber
)}`}
/>
}
plain
>
<span style={{ marginLeft: "5px" }}>
<CircleQuestion size="small" />
@ -218,12 +216,11 @@ function getColumns(props: any) {
dropProps={{ align: { right: "left" } }}
content={
<TipContent
message={`last update block height ${formatNumber(
message={`Last update block height: ${formatNumber(
+data.lastUpdateBlockNumber
)}`}
/>
}
plain
>
<span style={{ marginLeft: "5px" }}>
<CircleQuestion size="small" />
@ -251,12 +248,11 @@ function getColumns(props: any) {
dropProps={{ align: { right: "left" } }}
content={
<TipContent
message={`last update block height ${formatNumber(
message={`Last update block height: ${formatNumber(
+data.lastUpdateBlockNumber
)}`}
/>
}
plain
>
<span style={{ marginLeft: "5px" }}>
<CircleQuestion size="small" />

@ -86,15 +86,14 @@ export function ERC721Table(props: TransactionTableProps) {
data={data}
primaryKey={'address'}
border={{
header: {
color: "brand",
},
header: false,
body: {
color: "border",
side: "top",
side: "bottom",
size: "1px",
},
}}
background={{header: 'unset'}}
/>
</Box>
<Box
@ -131,7 +130,7 @@ function getColumns(props: any) {
render: (data: Erc20) => <Box direction={'row'} style={{ display: 'flex', alignItems: 'center' }}>
<Text size={'small'}>{data.name}</Text>
{data.isBridged && <div style={{ marginLeft: "4px", height: '14px', cursor: 'pointer' }}>
<Tip content={'Token is available on Harmony Bridge'}>
<Tip dropProps={{ align: { bottom: "top" }}} content={<TipContent showArrow={true} message={'Token is available on Harmony Bridge'} />}>
<StatusGood size={'14px'} color={'successText'} />
</Tip>
</div>}
@ -191,12 +190,11 @@ function getColumns(props: any) {
dropProps={{ align: { right: "left" } }}
content={
<TipContent
message={`last update block height ${formatNumber(
message={`Last update block height: ${formatNumber(
+data.lastUpdateBlockNumber
)}`}
/>
}
plain
>
<span style={{ marginLeft: "5px" }}>
<CircleQuestion size="small" />

@ -1,6 +1,6 @@
import React, { useState } from "react";
import { StatusCritical } from "grommet-icons";
import { Address, BaseContainer, BasePage, Button } from "src/components/ui";
import { Address, BaseContainer, BasePage, Button, TipContent } from "src/components/ui";
import { Heading, DateInput, Box, Spinner, Tip, Text } from "grommet";
import styled from "styled-components";
import useQuery from "../../hooks/useQuery";
@ -118,7 +118,7 @@ export const ExportData = () => {
</Box>
<FlexWrapper>
<InputContainer>
<Tip content={<span>Select start date</span>}>
<Tip dropProps={{ align: { bottom: "top" }}} content={<TipContent showArrow={true} message={'Select start date'} />}>
<DateInput
{...dateInputProps}
value={dayjs(dateFrom).toISOString()}
@ -128,7 +128,7 @@ export const ExportData = () => {
</InputContainer>
<div>to</div>
<InputContainer>
<Tip content={<span>Select end date</span>}>
<Tip dropProps={{ align: { bottom: "top" }}} content={<TipContent showArrow={true} message={'Select end date'} />}>
<DateInput
{...dateInputProps}
value={dayjs(dateTo).toISOString()}

@ -97,15 +97,14 @@ export const LatestBlocksTable = (params: { blocks: Block[] }) => {
data={params.blocks}
step={10}
border={{
header: {
color: "brand",
},
header: false,
body: {
color: "border",
side: "top",
side: "bottom",
size: "1px",
},
}}
background={{header: 'unset'}}
/>
</Box>
);

@ -154,21 +154,20 @@ export function LatestTransactionsTable() {
return (
<Box style={{ overflow: "auto" }}>
<DataTable
className={"g-table-header"}
className={"g-table-header g-table-header-plain"}
style={{ width: "100%", minWidth: "620px" }}
columns={getColumns({ history })}
data={transactions}
step={10}
border={{
header: {
color: "brand",
},
header: false,
body: {
color: "border",
side: "top",
side: "bottom",
size: "1px",
},
}}
background={{header: 'unset'}}
/>
</Box>
);

@ -1,7 +1,7 @@
import React, { useEffect, useState } from "react";
import { Box, Heading, Select, Spinner, Text, TextArea, TextInput, Tip } from "grommet";
import { Alert, StatusGood } from "grommet-icons";
import { BaseContainer, BasePage } from "../../../components/ui";
import { BaseContainer, BasePage, TipContent } from "../../../components/ui";
import useQuery from "../../../hooks/useQuery";
import { getContractsByField } from "../../../api/client";
import styled from "styled-components";
@ -230,8 +230,18 @@ export function CheckHRC() {
{(!isContractLoading && contractAddress) &&
<Box justify="center" align="center" margin={'24px 0 0 24px'}>
{isAllEventsMatched
? <Tip content={'All events found'}><StatusGood size="medium" color={'successText'} /></Tip>
: <Tip content={'Some events missing'}><Alert size="medium" color={'minorText'} /></Tip>}
? <Tip
dropProps={{ align: { bottom: "top" }}}
content={<TipContent showArrow={true} message={'All events found'} />}
>
<StatusGood size="medium" color={'successText'} />
</Tip>
: <Tip
dropProps={{ align: { bottom: "top" }}}
content={<TipContent showArrow={true} message={'Some events missing'} />}
>
<Alert size="medium" color={'minorText'} />
</Tip>}
</Box>
}
</Box>

@ -1,12 +1,18 @@
export const palette = {
WhiteGrey: "#F4F7F9",
LightGrey: "#e7ecf7",
Grey: "#b1b1b1",
CoolGray: "#758796",
WhiteBlue: '#EFF8FF',
Purple: "#00AEE9",
ElectricBlue: "#00AEE9",
ElectricBlueLight: "#e8f3ff",
WhiteGreen: '#dafef4',
MintGreen: "#69FABD",
DarkGreen: '#019267',
MidnightBlue: "#1B295E",
WhiteBrown: '#f7eacc',
GoldenBrown: '#b47d00'
};
export const theme = {
@ -16,7 +22,6 @@ export const theme = {
color: "transparent",
},
},
colors: {
text: '#55626d',
brand: palette.Purple,
@ -31,13 +36,19 @@ export const theme = {
minorText: palette.CoolGray,
iconMain: palette.ElectricBlue,
tableRow: palette.ElectricBlueLight,
tableRowHover: palette.WhiteGrey,
mintGreen: palette.MintGreen,
errorText: "#ff0000",
successText: "#14a266",
backgroundError: "rgba(230, 0, 0, 0.4)",
backgroundSuccess: "rgb(106 250 188 / 44%)",
backgroundToaster: "rgba(0, 174, 233, 0.7)",
backgroundTip: '#f3f3f3'
backgroundTip: palette.MidnightBlue,
backgroundMark: palette.WhiteBlue,
warning: palette.GoldenBrown,
warningBackground: palette.WhiteBrown,
success: palette.DarkGreen,
successBackground: palette.WhiteGreen,
},
palette,
select: {
@ -45,8 +56,6 @@ export const theme = {
color: "brand",
},
},
font: {
family: "Nunito",
// family: "Fira Sans",
@ -66,13 +75,13 @@ export const theme = {
borderColor: "brand",
},
dataTable: {
border: {
header: {
color: 'border'
}
},
body: {
extend: (props: any) => `
tr:first-child {
th, td {
border: none;
}
}
tr {
th, td {
@ -83,12 +92,10 @@ export const theme = {
}
}
tr:nth-child(even) {
th, td {
background-color: ${props.theme.global.colors.tableRow};
}
tr:hover {
background-color: ${props.theme.global.colors.tableRowHover};
}
`,
`
},
},
};
@ -121,6 +128,7 @@ export const darkTheme = {
minorText: "#5f98c7",
iconMain: palette.ElectricBlue,
tableRow: "#122852",
tableRowHover: '#1b3e7f',
mintGreen: palette.MintGreen,
errorText: "#ff5858",
successText: "#00d67b",
@ -128,7 +136,12 @@ export const darkTheme = {
backgroundSuccess: "rgb(106 250 188 / 23%)",
backgroundToaster: "rgb(93 111 181 / 70%)",
selected: "#3c53a2",
backgroundTip: '#22577E'
backgroundTip: '#22577E',
backgroundMark: '#3660ad',
warning: palette.GoldenBrown,
warningBackground: palette.WhiteBrown,
success: palette.DarkGreen,
successBackground: palette.WhiteGreen,
},
palette,
font: {

Loading…
Cancel
Save