From d99b9060e14739ac2f83a986a71d4725efde3ab3 Mon Sep 17 00:00:00 2001 From: port <108868128+portdeveloper@users.noreply.github.com> Date: Sun, 10 Mar 2024 12:50:07 +0300 Subject: [PATCH] Decompile ABI using a heimdall-rs backend --- packages/nextjs/pages/index.tsx | 200 ++++++++++++++++++++------------ 1 file changed, 123 insertions(+), 77 deletions(-) diff --git a/packages/nextjs/pages/index.tsx b/packages/nextjs/pages/index.tsx index 1cccdd91..24584ad6 100644 --- a/packages/nextjs/pages/index.tsx +++ b/packages/nextjs/pages/index.tsx @@ -18,6 +18,11 @@ enum TabName { addressAbi, } +enum AbiInputMethod { + Manual, + Heimdall, +} + const tabValues = Object.values(TabName) as TabName[]; const networks = getTargetNetworks(); @@ -29,8 +34,7 @@ const Home: NextPage = () => { const [localAbiContractAddress, setLocalAbiContractAddress] = useState(""); const [localContractAbi, setLocalContractAbi] = useState(""); const [isFetchingAbi, setIsFetchingAbi] = useState(false); - const [isCheckingContractAddress, setIsCheckingContractAddress] = useState(false); - const [isContract, setIsContract] = useState(false); + const [abiInputMethod, setAbiInputMethod] = useState(AbiInputMethod.Manual); const publicClient = usePublicClient({ chainId: parseInt(network), @@ -64,7 +68,25 @@ const Home: NextPage = () => { } catch (etherscanError: any) { setIsAbiAvailable(false); console.error("Error fetching ABI from Etherscan: ", etherscanError); - notification.error(etherscanError.message || "Error occurred while fetching ABI"); + + const bytecode = await publicClient.getBytecode({ + address: verifiedContractAddress, + }); + const isContract = Boolean(bytecode) && bytecode !== "0x"; + + if (isContract) { + notification.error( + "The contract is not verified on Etherscan. Please provide ABI manually or decompile ABI(experimental)", + { + duration: 10000, + position: "bottom-left", + }, + ); + setLocalAbiContractAddress(verifiedContractAddress); + setActiveTab(TabName.addressAbi); + } else { + notification.error("Address is not a contract, are you sure you are on the correct chain?"); + } } } finally { setIsFetchingAbi(false); @@ -82,35 +104,6 @@ const Home: NextPage = () => { } }, [verifiedContractAddress, network, setContractAbi]); - useEffect(() => { - const checkContract = async () => { - if (!isAddress(localAbiContractAddress)) { - setIsContract(false); - return; - } - - setIsCheckingContractAddress(true); - try { - const bytecode = await publicClient.getBytecode({ - address: localAbiContractAddress, - }); - const isContract = Boolean(bytecode) && bytecode !== "0x"; - setIsContract(isContract); - - if (!isContract) { - notification.error("Address is not a contract"); - } - } catch (e) { - notification.error("Error while checking for contract address"); - setIsContract(false); - } finally { - setIsCheckingContractAddress(false); - } - }; - - checkContract(); - }, [localAbiContractAddress, publicClient]); - useEffect(() => { if (router.pathname === "/") { setContractAbi([]); @@ -118,9 +111,9 @@ const Home: NextPage = () => { }, [router.pathname, setContractAbi]); const handleLoadContract = () => { - if (activeTab === TabName.verifiedContract) { + if (isAbiAvailable) { router.push(`/${verifiedContractAddress}/${network}`); - } else if (activeTab === TabName.addressAbi) { + } else if (localContractAbi.length > 0) { try { setContractAbi(parseAndCorrectJSON(localContractAbi)); } catch (error) { @@ -129,6 +122,26 @@ const Home: NextPage = () => { } setAbiContractAddress(localAbiContractAddress); router.push(`/${localAbiContractAddress}/${network}`); + } else { + fetchAbiFromHeimdall(localAbiContractAddress); + } + }; + + const fetchAbiFromHeimdall = async (contractAddress: string) => { + setIsFetchingAbi(true); + try { + const response = await fetch(`https://heimdall-api-cool-frog-2068.fly.dev/${network}/${contractAddress}`); + const abi = await response.json(); + setContractAbi(abi); + setIsAbiAvailable(true); + setAbiContractAddress(contractAddress); + router.push(`/${contractAddress}/${network}`); + } catch (error) { + console.error("Error fetching ABI from Heimdall: ", error); + notification.error("Failed to fetch ABI from Heimdall. Please try again or enter ABI manually."); + setIsAbiAvailable(false); + } finally { + setIsFetchingAbi(false); } }; @@ -145,31 +158,6 @@ const Home: NextPage = () => { setNetwork(option ? option.value.toString() : "")} /> -
- setActiveTab(TabName.verifiedContract)} - > - Verified Contract - - setActiveTab(TabName.addressAbi)} - > - Address + ABI - -
-
{tabValues.map(tabValue => ( @@ -187,7 +175,7 @@ const Home: NextPage = () => {
@@ -218,38 +206,96 @@ const Home: NextPage = () => {
) : ( -
- - +
+ {/* Tab navigation */} + +
+
setAbiInputMethod(AbiInputMethod.Manual)} + > + Input ABI Manually +
+
setAbiInputMethod(AbiInputMethod.Heimdall)} + > + Decompile ABI +
+
+ + {/* Content based on active tab */} + {abiInputMethod === AbiInputMethod.Manual ? ( + <> + + + + ) : ( + <> + + + )}
)}
))}
+ {activeTab !== TabName.verifiedContract && abiInputMethod === AbiInputMethod.Heimdall && ( +
+ Warning: this feature is experimental. You may lose funds if you interact with contracts using this + feature. +
+ )}
+ {activeTab === TabName.addressAbi && ( +
{ + setActiveTab(TabName.verifiedContract); + setVerifiedContractAddress(""); + }} + > + ← go back +
+ )} +