Merge pull request #198 from ArtemKolodko/refactor_txs_columns
Refactor transaction columnspull/199/head
commit
83d83890bd
@ -1,13 +1,34 @@ |
|||||||
import React from 'react' |
import React from 'react' |
||||||
|
import { Box, Text } from 'grommet' |
||||||
|
import styled from "styled-components"; |
||||||
|
|
||||||
import { grommet, Box, Button, Grommet, Heading, Text, Tip } from 'grommet' |
const ArrowDown = styled(Box)` |
||||||
import { Trash } from 'grommet-icons' |
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 = (props: { message: string | JSX.Element, showArrow?: boolean }) => { |
||||||
export const TipContent = ({ message }) => ( |
let message = props.message |
||||||
<Box direction="row" align="center"> |
if (typeof message === 'string') { |
||||||
<Box background="background" direction="row" pad="small" border={{color: 'border', size: '0px' }}> |
message = <Text size={'small'}>{message}</Text> |
||||||
<div>{message}</div> |
} |
||||||
|
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> |
</Box> |
||||||
</Box> |
} |
||||||
) |
|
||||||
|
@ -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> |
|
||||||
), |
|
||||||
}, |
|
||||||
]; |
|
||||||
}; |
|
Loading…
Reference in new issue