From 0754c4f4bfbe1086b405f004659e9a3666942aea Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 12 Dec 2021 23:32:30 -0300 Subject: [PATCH 1/4] Add failed tx error msg support; depends on ots_getTransactionError custom API --- src/params.ts | 2 +- src/transaction/Details.tsx | 17 ++++++++++++++--- src/useErigonHooks.ts | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/params.ts b/src/params.ts index 7ac916a..d1464c6 100644 --- a/src/params.ts +++ b/src/params.ts @@ -1,3 +1,3 @@ -export const MIN_API_LEVEL = 4; +export const MIN_API_LEVEL = 5; export const PAGE_SIZE = 25; diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index e4daf2f..36141ca 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -41,6 +41,7 @@ import { DevDoc, UserDoc } from "../sourcify/useSourcify"; import { ResolvedAddresses } from "../api/address-resolver"; import { RuntimeContext } from "../useRuntime"; import { useContractsMetadata } from "../hooks"; +import { useTransactionError } from "../useErigonHooks"; type DetailsProps = { txData: TransactionData; @@ -96,6 +97,7 @@ const Details: React.FC = ({ return _addresses; }, [txData]); const metadatas = useContractsMetadata(addresses, provider); + const errorMsg = useTransactionError(provider, txData.transactionHash); return ( @@ -114,10 +116,19 @@ const Details: React.FC = ({ Success ) : ( - +
- Fail - + + Fail + {errorMsg && ( + <> + {" "} + with revert message: ' + {errorMsg}' + + )} + +
)} {txData.confirmedData && ( diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index 30effa2..324adc7 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -3,6 +3,7 @@ import { Block, BlockWithTransactions } from "@ethersproject/abstract-provider"; import { JsonRpcProvider } from "@ethersproject/providers"; import { getAddress } from "@ethersproject/address"; import { Contract } from "@ethersproject/contracts"; +import { defaultAbiCoder } from "@ethersproject/abi"; import { BigNumber } from "@ethersproject/bignumber"; import { arrayify, hexDataSlice, isHexString } from "@ethersproject/bytes"; import { extract4Bytes } from "./use4Bytes"; @@ -484,3 +485,37 @@ export const useAddressesWithCode = ( return results; }; + +export const useTransactionError = ( + provider: JsonRpcProvider | undefined, + txHash: string +): string | undefined => { + const [errorMsg, setErrorMsg] = useState(); + + useEffect(() => { + // Reset + setErrorMsg(undefined); + + if (provider === undefined) { + return; + } + + const readCodes = async () => { + const result = (await provider.send("ots_getTransactionError", [ + txHash, + ])) as string; + + // Filter hardcoded Error(string) selector because ethers don't let us + // construct it + if (result.substr(0, 10) !== "0x08c379a0") { + return; + } + + const msg = defaultAbiCoder.decode(["string"], "0x" + result.substr(10)); + setErrorMsg(msg[0]); + }; + readCodes(); + }, [provider, txHash]); + + return errorMsg; +}; From d5fa5dda36e4410d10dcea12b489180141a8a1bb Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 13 Dec 2021 15:11:34 -0300 Subject: [PATCH 2/4] Small refactorings; no semantic changes --- src/useErigonHooks.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index 324adc7..ff70e38 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -486,6 +486,9 @@ export const useAddressesWithCode = ( return results; }; +// Error(string) +const ERROR_MESSAGE_SELECTOR = "0x08c379a0"; + export const useTransactionError = ( provider: JsonRpcProvider | undefined, txHash: string @@ -505,14 +508,22 @@ export const useTransactionError = ( txHash, ])) as string; - // Filter hardcoded Error(string) selector because ethers don't let us - // construct it - if (result.substr(0, 10) !== "0x08c379a0") { + // Empty or success + if (result === "0x") { return; } - const msg = defaultAbiCoder.decode(["string"], "0x" + result.substr(10)); - setErrorMsg(msg[0]); + // Filter hardcoded Error(string) selector because ethers don't let us + // construct it + const selector = result.substr(0, 10); + if (selector === ERROR_MESSAGE_SELECTOR) { + const msg = defaultAbiCoder.decode( + ["string"], + "0x" + result.substr(10) + ); + setErrorMsg(msg[0]); + return; + } }; readCodes(); }, [provider, txHash]); From f22199d7d5d39b6982e2ed33aef0c6c851640c7f Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 13 Dec 2021 15:41:37 -0300 Subject: [PATCH 3/4] Add basic structure for custom errors --- src/components/ExpanderSwitch.tsx | 22 ++++++++ src/transaction/Details.tsx | 90 +++++++++++++++++++++++++------ src/transaction/TraceInput.tsx | 17 ++---- src/useErigonHooks.ts | 17 +++++- 4 files changed, 116 insertions(+), 30 deletions(-) create mode 100644 src/components/ExpanderSwitch.tsx diff --git a/src/components/ExpanderSwitch.tsx b/src/components/ExpanderSwitch.tsx new file mode 100644 index 0000000..71292db --- /dev/null +++ b/src/components/ExpanderSwitch.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { Switch } from "@headlessui/react"; + +type ExpanderSwitchProps = { + expanded: boolean; + setExpanded: React.Dispatch>; +}; + +const ExpanderSwitch: React.FC = ({ + expanded, + setExpanded, +}) => ( + + {expanded ? [-] : <>[...]} + +); + +export default ExpanderSwitch; diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 36141ca..ca21ea4 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -1,4 +1,5 @@ -import React, { useContext, useMemo } from "react"; +import React, { useContext, useMemo, useState } from "react"; +import { Tab } from "@headlessui/react"; import { TransactionDescription } from "@ethersproject/abi"; import { BigNumber } from "@ethersproject/bignumber"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -8,6 +9,8 @@ import { faTimesCircle } from "@fortawesome/free-solid-svg-icons/faTimesCircle"; import ContentFrame from "../ContentFrame"; import InfoRow from "../components/InfoRow"; import BlockLink from "../components/BlockLink"; +import ModeTab from "../components/ModeTab"; +import ExpanderSwitch from "../components/ExpanderSwitch"; import BlockConfirmations from "../components/BlockConfirmations"; import TransactionAddress from "../components/TransactionAddress"; import Copy from "../components/Copy"; @@ -97,7 +100,11 @@ const Details: React.FC = ({ return _addresses; }, [txData]); const metadatas = useContractsMetadata(addresses, provider); - const errorMsg = useTransactionError(provider, txData.transactionHash); + const [errorMsg, outputData, isCustomError] = useTransactionError( + provider, + txData.transactionHash + ); + const [expanded, setExpanded] = useState(false); return ( @@ -111,24 +118,75 @@ const Details: React.FC = ({ {txData.confirmedData === undefined ? ( Pending ) : txData.confirmedData.status ? ( - - + + Success ) : ( -
- - - Fail - {errorMsg && ( - <> - {" "} - with revert message: ' - {errorMsg}' - + <> +
+
+ + + Fail + {errorMsg && ( + <> + {" "} + with revert message: ' + {errorMsg}' + + )} + {isCustomError && <> with custom error} + +
+ {isCustomError && ( + )} - -
+
+ {expanded && ( + + + Decoded + Raw + + + + {/* {fourBytes === "0x" ? ( + <>No parameters + ) : resolvedTxDesc === undefined ? ( + <>Waiting for data... + ) : resolvedTxDesc === null ? ( + <>Can't decode data + ) : ( + + )} */} + + +