From d5572898096754d137a1471d186f29505780d946 Mon Sep 17 00:00:00 2001 From: "vien.nguyen2-tiki" <vien.nguyen2@tiki.vn> Date: Mon, 17 Oct 2022 09:59:20 +0700 Subject: [PATCH] feat: decode inputdata --- api/api_list.ts | 1 + components/Card/CardInfo/index.tsx | 15 +++++---- pages/tx/[tx].tsx | 2 +- types/address.d.ts | 8 +++++ views/transactions/DecodeInput.tsx | 36 +++++++++++++------- views/transactions/LogItem.tsx | 49 +++++++++++++++++++++------- views/transactions/style.module.scss | 4 --- 7 files changed, 79 insertions(+), 36 deletions(-) diff --git a/api/api_list.ts b/api/api_list.ts index 6154a13f..bc8e099f 100644 --- a/api/api_list.ts +++ b/api/api_list.ts @@ -16,6 +16,7 @@ const API_LIST = { COSMOS_TRANSACTION: '/api/v1?module=transaction&action=getTxCosmosInfo&txhash=', // call axios ABI: '/api/v1?module=contract&action=getabi&address=', + HASH_ABI: '/api/v1?module=transaction&action=getabibytxhash&txhash=', VALIDATORS: 'http://128.199.238.171:8080/api/v1/validators', diff --git a/components/Card/CardInfo/index.tsx b/components/Card/CardInfo/index.tsx index 8e0cb603..b98c852d 100644 --- a/components/Card/CardInfo/index.tsx +++ b/components/Card/CardInfo/index.tsx @@ -67,8 +67,8 @@ export default function CardInfo({ }: CardInfoProps) { const { isMobile: isSmallDevice } = useMobileLayout('small') const { isMobile: isMediumDevice } = useMobileLayout('medium') - const _ellipsis = (text: string | number) => - ellipseRightText(`${text}`, isSmallDevice ? 27 : isMediumDevice ? 45 : 80) + const _ellipsis = (text: string | number, cut = true): string => + cut ? ellipseRightText(`${text}`, isSmallDevice ? 27 : isMediumDevice ? 45 : 150) : (text as string) return ( <BackgroundCard @@ -114,13 +114,14 @@ export default function CardInfo({ ) : null} {type === 'text' ? ( <span className="money money-sm contrast-color-100 word-break-all"> - {_ellipsis(content.value)} {content.suffix && content.suffix} + {_ellipsis(content.value, responsive.ellipsis)}{' '} + {content.suffix && content.suffix} </span> ) : null} {type === 'copy' ? ( <CopyButton - textCopy={_ellipsis(content?.value as string)} - textTitle={_ellipsis(content?.value as string)} + textCopy={_ellipsis(content?.value as string, responsive.ellipsis)} + textTitle={_ellipsis(content?.value as string, responsive.ellipsis)} /> ) : null} {type === 'link' ? ( @@ -129,13 +130,13 @@ export default function CardInfo({ fontType="Titi" fontSize="text-500" > - {_ellipsis(content.value as string)} + {_ellipsis(content.value as string, responsive.ellipsis)} </Typography.LinkText> ) : null} {type === 'link-copy' ? ( <div className="block-center"> <Typography.LinkText href={content.link || ''}> - {_ellipsis(content.value as string)} + {_ellipsis(content.value as string, responsive.ellipsis)} </Typography.LinkText> <CopyButton textCopy={content.value as string} /> </div> diff --git a/pages/tx/[tx].tsx b/pages/tx/[tx].tsx index 85556535..acb093ff 100644 --- a/pages/tx/[tx].tsx +++ b/pages/tx/[tx].tsx @@ -46,7 +46,7 @@ const TransactionDetailPage: React.FC<Props> = ({ data, evmHash, cosmosHash }: P </div> <CardInfo items={items} classes={['margin-top-sm']} /> {moreItems.length > 0 && <CardInfo items={moreItems} classes={['margin-top-sm']} />} - {data.rawInput && <DecodeInput dataInput={data.rawInput} address={data.to} />} + {data.rawInput && <DecodeInput dataInput={data.rawInput} address={data.to} evmHash={evmHash} />} <TransactionTabs evmHash={evmHash} cosmosHash={cosmosHash} diff --git a/types/address.d.ts b/types/address.d.ts index 0ce548b0..84b5299e 100644 --- a/types/address.d.ts +++ b/types/address.d.ts @@ -4,6 +4,14 @@ interface AbiResponse { status: string } +interface HashAbiResponse { + message: string + result: { + abi: any + } + status: string +} + interface AddressCounterResponse { message: string result: AddressCounterData diff --git a/views/transactions/DecodeInput.tsx b/views/transactions/DecodeInput.tsx index d19adaf2..9410e716 100644 --- a/views/transactions/DecodeInput.tsx +++ b/views/transactions/DecodeInput.tsx @@ -17,28 +17,37 @@ export interface AbiItemDecode extends AbiItem { type DecodeInputProps = { dataInput: string address: string + evmHash?: string } -export default function DecodeInput({ dataInput, address }: DecodeInputProps) { +export default function DecodeInput({ dataInput, address, evmHash }: DecodeInputProps) { if (!dataInput || !address) { return null } const [load, setLoad] = useState(false) const [items, setItems] = useState<LogElementProps[]>() - const getAbi = async (address: string): Promise<AbiItem[]> => { - const res = await evmApi.get<AbiResponse>(`${API_LIST.ABI}${address}`) - if (res.data.message === 'OK') { - return JSON.parse(res?.data?.result) + const getAbi = async (address: string): Promise<{ abi: AbiItem[]; hasAbi: boolean }> => { + const addressAbiRes = await evmApi.get<AbiResponse>(`${API_LIST.ABI}${address}`) + if (addressAbiRes.data.message === 'OK') { + return { abi: JSON.parse(addressAbiRes?.data?.result), hasAbi: true } } - return undefined + // datainput from hash + if (evmHash) { + const hashAbiRes = await evmApi.get<HashAbiResponse>(`${API_LIST.HASH_ABI}${evmHash}`) + if (hashAbiRes.data.message === 'OK') { + return { abi: [hashAbiRes?.data?.result?.abi], hasAbi: false } + } + } + + return { abi: undefined, hasAbi: false } } useEffect(() => { async function data() { if (!isEmpty(dataInput)) { const items: LogElementProps[] = [] - const abi = await getAbi(address) + const { abi, hasAbi } = await getAbi(address) const item: LogElementProps = { address: address, data: '', @@ -48,11 +57,14 @@ export default function DecodeInput({ dataInput, address }: DecodeInputProps) { } items.push(item) item.methodId = evmMethodId(dataInput) + + item.verified = hasAbi + item.useDraftAbiToDecode = !hasAbi && !!abi + if (Array.isArray(abi)) { - item.verified = true abiDecoder.addABI(abi) - const logObj = abiDecoder.decodeMethod(dataInput) as AbiItemDecode - const name = logObj.name + const inputObj = abiDecoder.decodeMethod(dataInput) as AbiItemDecode + const name = inputObj.name const interfaceItem = abi.find(item => item.name === name) const params = interfaceItem.inputs const call = `${interfaceItem.name}(${interfaceItem.inputs @@ -61,12 +73,12 @@ export default function DecodeInput({ dataInput, address }: DecodeInputProps) { item.call = call item.callRow = call for (let para of params) { - const input = logObj?.params.find(input => input.name === para.name) + const input = inputObj?.params.find(input => input.name === para.name) if (input) { input.indexed = para.indexed } } - item.methodParams = logObj.params + item.methodParams = inputObj.params } setItems(items) } diff --git a/views/transactions/LogItem.tsx b/views/transactions/LogItem.tsx index 308f3ba6..bca762bd 100644 --- a/views/transactions/LogItem.tsx +++ b/views/transactions/LogItem.tsx @@ -18,6 +18,7 @@ export type LogElementProps = { index: string borderTop?: boolean showLeftBorder?: boolean + useDraftAbiToDecode?: boolean } export default function LogElement({ @@ -32,26 +33,35 @@ export default function LogElement({ borderTop, callRow, showAddress = true, - showLeftBorder = true + showLeftBorder = true, + useDraftAbiToDecode }: LogElementProps) { let items: CardRowItem[] = [] if (address && showAddress) { items.push({ label: 'Address:', type: 'text', - contents: [{ value: address }] + contents: [{ value: address }], + responsive: { + ellipsis: false, + wrap: 'sm' + } }) } if (callRow) { items.push({ label: '', type: 'text', - contents: [{ value: callRow }] + contents: [{ value: callRow }], + responsive: { + ellipsis: false, + wrap: 'sm' + } }) } let topElement: React.ReactNode = null - if (verified) { + if (verified || useDraftAbiToDecode) { items.push({ label: 'Decode:', type: 'decode', @@ -65,13 +75,20 @@ export default function LogElement({ } ] }) - } else { + } + if (useDraftAbiToDecode || !verified) { topElement = ( - <div className="padding-left-2xl padding-right-2xl"> - <div className={clsx(styles.verifyContract, 'contrast-color-100')}> + <div className="padding-left-2xl padding-right-2xl sm-padding-left-md sm-padding-right-md"> + <div + className={clsx( + styles.verifyContract, + 'contrast-color-100', + 'padding-top-sm padding-bottom-sm padding-left-xs padding-right-xs' + )} + > To see accurate decoded input data, the contract must be verified. Verify the contract{' '} <Link href={LinkMaker.address(address, '/verify')}> - <a className="link padding-left-xs"> here</a> + <a className="link"> here</a> </Link> . </div> @@ -86,19 +103,27 @@ export default function LogElement({ items.push({ label: label, type: 'text', - contents: [{ value: `[${idx}] ${topics[idx]}` }] + contents: [{ value: `[${idx}] ${topics[idx]}` }], + responsive: { + ellipsis: false, + wrap: 'sm' + } }) } if (data) { items.push({ - label: 'Data', + label: 'Data:', type: 'text', - contents: [{ value: data }] + contents: [{ value: data }], + responsive: { + ellipsis: false, + wrap: 'sm' + } }) } if (index) { items.push({ - label: 'Log Index', + label: 'Log Index:', type: 'text', contents: [{ value: index }] }) diff --git a/views/transactions/style.module.scss b/views/transactions/style.module.scss index aca5e439..3b300aae 100644 --- a/views/transactions/style.module.scss +++ b/views/transactions/style.module.scss @@ -34,10 +34,6 @@ } } .verifyContract { - display: flex; - align-items: center; - padding: 6px 16px; - min-height: 48px; background: rgba(255, 200, 42, 0.16); border: 1px solid rgba(255, 200, 42, 0.1); border-radius: 8px;