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;