11import type { Hex } from "viem" ;
22
33import { assertHardhatInvariant } from "@nomicfoundation/hardhat-errors" ;
4+ import { ensureError } from "@nomicfoundation/hardhat-utils/error" ;
45import { isPrefixedHexString } from "@nomicfoundation/hardhat-utils/hex" ;
56
67/**
7- * Recursively extracts, if it exists, the revert data hex string from a nested Viem error.
8+ * Recursively extracts, if it exists, the revert data hex string from an error.
89 *
910 * When a contract call reverts, Viem throws an `Error` whose `data` property
1011 * contains the hex-encoded revert reason. That `data` may live on the top-level
@@ -17,29 +18,41 @@ import { isPrefixedHexString } from "@nomicfoundation/hardhat-utils/hex";
1718 *
1819 * @throws If no valid `0x` prefixed hex string revert data is found anywhere in the error chain.
1920 */
20- export function extractRevertData (
21- error : Error & { data ?: unknown ; cause ?: unknown } ,
22- ) : Hex {
23- let errorData : Hex | undefined ;
24- let current : typeof error | undefined = error ;
21+ export function extractRevertError ( error : unknown ) : {
22+ name : string ;
23+ message : string ;
24+ data : Hex ;
25+ } {
26+ ensureError ( error ) ;
2527
28+ let dataReason : Hex | undefined ;
29+
30+ let current : Error | undefined = error ;
31+ let message : string = "" ;
2632 while ( current !== undefined ) {
27- const { data } = current ;
33+ // Traverse the cause chain to find a valid raw error reason, if one exists.
34+ if ( "data" in current ) {
35+ const { data } = current ;
2836
29- if ( typeof data === "string" && isPrefixedHexString ( data ) ) {
30- errorData = data ;
37+ if ( typeof data === "string" && isPrefixedHexString ( data ) ) {
38+ dataReason = data ;
39+ message = current . message ;
40+ }
3141 }
3242
3343 /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
3444 -- all the nested errors might contain a `cause` field */
35- current = current . cause as typeof error | undefined ;
45+ current = current . cause as Error | undefined ;
3646 }
3747
38- // In a revert scenario, a data field containing the revert reason is always expected
3948 assertHardhatInvariant (
40- errorData !== undefined ,
41- " No revert data found on error" ,
49+ dataReason !== undefined ,
50+ ` No revert data found on error.\nError name: " ${ error . name } ", message: ${ error . message } ` ,
4251 ) ;
4352
44- return errorData ;
53+ return {
54+ name : error . name ,
55+ message,
56+ data : dataReason ,
57+ } ;
4558}
0 commit comments