Refactor erc20, erc721 transfers (#152)

* Refactor erc20, erc721 transfers

* Default tx method render for regular transactions

* Add contract methods to erc transfers history

* Update styles

* Remove unused methods

* Fix imports: react-router -> react-router-dom
pull/179/head
Artem 3 years ago committed by GitHub
parent ccc62bc65f
commit 820ad94328
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      src/components/ui/TokenValue.tsx
  2. 367
      src/pages/AddressPage/tabs/Transactions.tsx
  3. 255
      src/pages/AddressPage/tabs/erc20Columns.tsx
  4. 787
      src/pages/AddressPage/tabs/txsColumns.tsx
  5. 2
      src/pages/AllTransactionsPage/index.tsx
  6. 2
      src/pages/ApprovalPage/index.tsx
  7. 2
      src/pages/VerifyContract/VerifyContract.tsx
  8. 2
      src/theme.ts

@ -5,6 +5,7 @@ import { formatNumber as _formatNumber } from "src/components/ui/utils";
import { useERC20Pool } from "src/hooks/ERC20_Pool";
import { useERC721Pool } from "src/hooks/ERC721_Pool";
import styled from "styled-components";
interface ONEValueProps {
value: string | number;
@ -12,12 +13,29 @@ interface ONEValueProps {
style?: React.CSSProperties;
formatNumber?: boolean;
hideSymbol?: boolean;
isShort?: boolean;
}
Big.DP = 21;
Big.NE = -20;
Big.PE = 15;
const TextWrapper = styled(Text)<{ isShort: boolean }>`
${(props) => props.isShort &&
`
width: 200px;
display: flex;
b {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
`
}
`
// @ts-ignore
export const TokenValue = (props: ONEValueProps) => {
const {
@ -26,6 +44,7 @@ export const TokenValue = (props: ONEValueProps) => {
style,
formatNumber,
hideSymbol = false,
isShort = false
} = props;
const erc20Map = useERC20Pool();
const erc721Map = useERC721Pool();
@ -49,8 +68,8 @@ export const TokenValue = (props: ONEValueProps) => {
const v = formatNumber ? _formatNumber(bi.toNumber()) : bi.toString();
return (
<Text size="small" style={style}>
<b>{v}</b> {hideSymbol ? null : tokenInfo.symbol}
</Text>
<TextWrapper size="small" isShort={isShort} style={style}>
<b>{v}</b> {hideSymbol ? null : <span style={{ whiteSpace: 'nowrap' }}>{tokenInfo.symbol}</span>}
</TextWrapper>
);
};

@ -1,5 +1,5 @@
import React, { useEffect, useRef, useState } from "react";
import { Box, ColumnConfig, Text, Tip } from "grommet";
import { Box } from "grommet";
import { useParams } from "react-router-dom";
import {
getByteCodeSignatureByHash,
@ -17,9 +17,7 @@ import {
RelatedTransaction,
RelatedTransactionType, RPCTransactionHarmony
} from "src/types";
import styled, { css } from "styled-components";
import { TRelatedTransaction } from "src/api/client.interface";
import { getERC20Columns } from "./erc20Columns";
import { getAddress, mapBlockchainTxToRelated } from "src/utils";
import { ExportToCsvButton } from "../../../components/ui/ExportToCsvButton";
import {
@ -27,366 +25,10 @@ import {
hmyv2_getTransactionsCount,
hmyv2_getTransactionsHistory
} from "../../../api/rpc";
const TxMethod = styled(Text)`
width: 100px;
> div {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
`
const Marker = styled.div<{ out: boolean }>`
border-radius: 2px;
padding: 5px;
text-align: center;
font-weight: bold;
${(props) =>
props.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;
font-weight: bold;
`;
import { getColumns, getERC20Columns, getNFTColumns, getStackingColumns } from "./txsColumns";
const internalTxsBlocksFrom = 23000000
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={<TipContent message={signature} />} plain>
<TxMethod size="10px">
<NeutralMarker background={"backgroundTip"}>
{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) => (
<Text size="12px">
<Marker out={data.from === id}>
{data.from === id ? "OUT" : "IN"}
</Marker>
</Text>
),
},
{
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">
<ONEValueWithInternal tx={data} 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>
),
},
];
}
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) => (
<Text size="12px">
<Marker out={data.from === id}>
{data.from === id ? "OUT" : "IN"}
</Marker>
</Text>
),
},
{
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>
),
},
];
};
const relatedTxMap: Record<RelatedTransactionType, string> = {
transaction: "Transaction",
internal_transaction: "Internal Transaction",
@ -597,6 +239,11 @@ export function Transactions(props: {
break;
}
case "erc721": {
columns = getNFTColumns(id)
break;
}
default: {
columns = getColumns(id);
break;

@ -1,255 +0,0 @@
import { Box, ColumnConfig, Text } from 'grommet'
import { Address, TokenValue, DateTime } from 'src/components/ui'
import { RelatedTransaction } from 'src/types'
import React from 'react'
import { parseSuggestedEvent } from 'src/web3/parseByteCode'
import styled, { css } from 'styled-components'
import { zeroAddress } from 'src/utils/zeroAddress'
const erc20TransferTopic =
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
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 Marker = styled.div<{ out: boolean }>`
border-radius: 2px;
padding: 5px;
text-align: center;
font-weight: bold;
${(props) =>
props.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;
font-weight: bold;
`
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 { parsed } = extractTransfer(data)
const address1 = parsed['$0']
const address2 = parsed['$1']
const method = address1 === zeroAddress ? 'Mint' : address2 === zeroAddress ? 'Burn' : 'Transfer'
return (
<Text size="12px">
<NeutralMarker background={'backgroundBack'}>
{method}
</NeutralMarker>
</Text>
)
}
},
{
property: 'from',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '120px' }}
>
From
</Text>
),
render: (data: RelatedTransaction) => {
const { parsed } = extractTransfer(data)
const address = (parsed['$0'] || '') || '?'
return (
<Text size="12px">
<Address isShort address={address} />
</Text>)
}
},
{
property: 'marker',
header: <></>,
render: (data: RelatedTransaction) => {
const { parsed } = extractTransfer(data)
const address = (parsed['$0'] || '') || '?'
return (
<Text size="12px">
<Marker out={address === id}>
{address === id ? 'OUT' : 'IN'}
</Marker>
</Text>
)
}
},
{
property: 'to',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '120px' }}
>
To
</Text>
),
render: (data: RelatedTransaction) => {
const { parsed } = extractTransfer(data)
const address = (parsed['$1'] || '') || '?'
return (
<Text size="12px">
<Address isShort address={address} />
</Text>)
}
},
{
property: 'value',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '320px' }}
>
Value
</Text>
),
render: (data: RelatedTransaction) => {
const { parsed, transferLog } = extractTransfer(data)
const value = parsed['$2']
if (!transferLog || !value) {
return '?'
}
return (
<Text size="12px">
<TokenValue tokenAddress={transferLog.address} value={value} />
</Text>)
}
},
{
property: 'token',
header: (
<Text
color="minorText"
size="small"
style={{ fontWeight: 300, width: '120px' }}
>
Token
</Text>
),
render: (data: any) => {
const { transferLog } = extractTransfer(data)
const address = transferLog ? transferLog.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>
)
}
]
}

@ -0,0 +1,787 @@
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'
const Marker = styled.div<{ out: boolean }>`
border-radius: 2px;
padding: 5px;
text-align: center;
font-weight: bold;
${(props) =>
props.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;
font-weight: bold;
`
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 ''
})
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) => {
const { from } = data
return (
<Text size="10px">
<Marker out={from === id}>
{from === id ? 'OUT' : 'IN'}
</Marker>
</Text>
)
}
},
{
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) => (
<Text size="12px">
<Marker out={data.from === id}>
{data.from === id ? "OUT" : "IN"}
</Marker>
</Text>
),
},
{
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) => (
<Text size="10px">
<Marker out={data.from === id}>
{data.from === id ? "OUT" : "IN"}
</Marker>
</Text>
),
},
{
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) => (
<Text size="12px">
<Marker out={data.from === id}>
{data.from === id ? "OUT" : "IN"}
</Marker>
</Text>
),
},
{
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>
),
},
];
};

@ -3,7 +3,7 @@ import { Box, Heading, Text } from "grommet";
import { BasePage, BaseContainer } from "src/components/ui";
import { TransactionsTable } from "../../components/tables/TransactionsTable";
import { Filter, RPCTransactionHarmony } from "../../types";
import { useHistory } from "react-router";
import { useHistory } from "react-router-dom";
import { getTransactions, getCount } from "src/api/client";
import { ShardDropdown } from "src/components/ui/ShardDropdown";
import { useParams } from "react-router-dom";

@ -3,7 +3,7 @@ import { Box, Heading, Tab, Tabs, Text } from "grommet";
import { BasePage, BaseContainer } from "src/components/ui";
import { TransactionsTable } from "../../components/tables/TransactionsTable";
import { ApprovalDetails, Filter, RPCTransactionHarmony } from "../../types";
import { useHistory } from "react-router";
import { useHistory } from "react-router-dom";
import { getTransactions, getCount } from "src/api/client";
import { ShardDropdown } from "src/components/ui/ShardDropdown";
import { useParams } from "react-router-dom";

@ -15,7 +15,7 @@ import { IVerifyContractData, verifyContractCode } from "src/api/explorerV1";
import { SubtractCircle } from "grommet-icons";
import { breakpoints } from "../../responsive/breakpoints";
import { useMediaQuery } from "react-responsive";
import { useHistory } from "react-router";
import { useHistory } from "react-router-dom";
import { getAddress, getQueryVariable } from "../../utils";
import { getContractsByField, getTransactionByField } from "../../api/client";

@ -76,7 +76,7 @@ export const theme = {
tr {
th, td {
padding: 16px 12px;
padding: 16px 8px;
}
td:last-child {
text-align: right;

Loading…
Cancel
Save