Next Article in Journal
Digital Twin-Based and Knowledge Graph-Enhanced Emergency Response in Urban Infrastructure Construction
Previous Article in Journal
Accident Risk Analysis of Gas Tankers in Maritime Transport Using an Integrated Fuzzy Approach
 
 
Font Type:
Arial Georgia Verdana
Font Size:
Aa Aa Aa
Line Spacing:
Column Width:
Background:
Article

ErrorExplainer: Automated Extraction of Error Contexts from Smart Contracts

by
JongHyup Lee
Department of Mathematical Finance, Gachon University, Seongnam 13120, Republic of Korea
Appl. Sci. 2025, 15(11), 6006; https://doi.org/10.3390/app15116006
Submission received: 27 April 2025 / Revised: 25 May 2025 / Accepted: 25 May 2025 / Published: 27 May 2025
(This article belongs to the Section Computing and Artificial Intelligence)

Abstract

:
A persistent semantic gap separates the low-level revert data emitted by smart contracts from the high-level explanations Web3 users need when a transaction fails. Existing automated analyzers treat such reverts as hints of hidden vulnerabilities and do not tell users what actually went wrong. To close this gap and give users useful feedback, I present ErrorExplainer, an automated error-explanation framework rather than another bug detector. ErrorExplainer takes a novel two-phase approach. A lightweight static analysis of verified source code lifts every transaction-reverting statement into a canonical error representation of an origin function, a guard condition, and an expected error message. At runtime, when a failure occurs, ErrorExplainer first checks the invariant part of the error data with the error representation of the called function. If no hit appears, it expands the candidates to call traces until a match is found and then shows the matched record as a clear, human-readable explanation. The evaluation results show that ErrorExplainer could effectively identify 6284 normalized error records from a reverting-related dataset of SC-Bench. The high information completeness (0.952) and matching fitness (0.954 and 0.604 at the function and trace levels, respectively) indicate that the extracted error context of ErrorExplainer can provide more understandable information to users on failed operations.

1. Introduction

No one explains users’ failures in Web3. As cryptocurrencies gain adoption across financial services and other industries, Web3 has evolved to encompass applications ranging from Decentralized Finance (DeFi) to social networks. However, the user experience remains one of the most challenging issues in Web3 [1]. The problem becomes more severe when users encounter errors while managing crypto-assets or interacting with smart contracts. A recent study [2] found that existing Web3 clients, i.e., wallet software, seldom inform users about the reason for failed operations.
Delivering a satisfactory user experience in this environment is challenging. When managing assets on the blockchain or using decentralized applications (dApps), users interact directly with smart contracts deployed on-chain. Smart contracts were initially designed with minimal functionality to limit complexity and cost. Thus, providing user-friendly information has never been a primary concern for developers. An Ethereum tutorial [3] even recommends replacing descriptive error messages with symbolic abbreviations to save gas.
Web3 services remain error-prone and unfamiliar to users; users must understand the basics of public-key cryptography to use their assets and, when transactions fail, grasp whatever error data are returned. However, error messages from smart contracts are not standardized and are frequently human-unreadable. For example,  Table 1 lists several revert cases (i.e., error conditions) defined in the ERC-20 standard [4], the most widely adopted token interface. Among the ERC-20 interface functions, the transfer function is specified to emit a Transfer event upon success and to define two error conditions (insufficient balance or a zero recipient address), without specifying any error message.
This lack of standardization has led developers to use inconsistent error messages. For the ERC-20 error case where a recipient address is zero, the OpenZeppelin implementation of IERC-20 reverts with the binary-encoded code object ERC20InvalidReceiver(address(0)), while other real-world smart contracts in the SC-Bench dataset [5] show at least three alternative outputs for the same condition: (1) a literal string “ERC20: transfer to the zero address”, (2) an empty error message, or (3) no revert at all.
To address this problem, a user-side solution is needed. Because smart contracts are immutable once deployed, changing them with standardized error messages is infeasible even for upgradable designs. Therefore, we propose ErrorExplainer, a client-side framework that automatically reconstructs error contexts to help users understand errors even with non-standardized error messages.
ErrorExplainer leverages a characteristic of the Web3 ecosystem: the source code of most deployed contracts is published in verified form on explorers, such as Etherscan [6]. By locating the statement that triggered a given revert, the framework extracts structured facts, including the error condition and the origin (i.e., the enclosing function), and presents them to users. Additionally, users can query Large Language Models (LLMs) with the structured information to obtain natural-language explanations of their failed operations.
 Table 2 shows an example of the raw data returned to the user versus the enriched error context provided by ErrorExplainer. For a failed transfer caused by insufficient balance, the user can receive only a binary-encoded error message. At the same time, ErrorExplainer provides more critical information to understand the error, such as the function, error condition, and code snippet responsible for the error.
ErrorExplainer extracts error-related information from the source code of smart contracts through static analysis and builds a database of error contexts. When a user encounters an error, ErrorExplainer matches the runtime data against the error contexts and provides the user with an “error description”. Each error description is expressive enough for users to recognize the reason for the error.
We can summarize the contributions of this paper as follows:
  • I identify the practical challenges of non-standardized error messages that make it difficult for users to understand errors in Web3 services.
  • I propose ErrorExplainer, an automated approach that analyzes smart contract code to generate rich, structured error descriptions matched to the user’s execution context.
  • I demonstrate the effectiveness of ErrorExplainer on real-world smart contracts by evaluating its identification accuracy, information completeness, and matching fitness.

2. Background

2.1. Transaction Execution Environment

  • Transactions on EVM. Ethereum-compatible blockchains execute all state–transition logic on the Ethereum Virtual Machine (EVM) [7]. Each transaction is authenticated with the sender’s signature before execution. A transaction either transfers assets or calls functions of smart contracts. When calling a function, the transaction adds a read-only chunk of bytes, referred to as “calldata”, to specify the function selector and the input arguments. The smart contract directly uses the calldata to execute its function. The called function is selected by matching the first four bytes of calldata with the Keccak-256 hash of the function signatures. The rest of the calldata contain the application binary interface (ABI)-encoded input arguments.
  • Crypto Wallets. A crypto wallet is the primary user client for blockchain systems and Web3 services. It manages accounts comprising private keys and their corresponding addresses derived from the public keys. Users interact with blockchain systems by signing transactions and sending them to the blockchain network through the crypto wallet. Therefore, the crypto wallet works as the closest interface to users in Web3.

2.2. Transaction Errors

The atomic execution model of blockchain systems accepts only transactions that are valid and fully executable. A transaction may fail for reasons such as insufficient balance, failed access control, or malformed calldata. In such cases, execution is aborted and the transaction is said to be reverted.
Users may inspect errors both pre- and post-submission. Before sending, crypto wallets simulate execution via JSON-RPC methods eth_call and eth_estimateGas, returning the simulated result and the estimated gas fee, respectively. After submission, the blockchain returns a transaction receipt whose status field indicates success or failure; if the transaction reverts, the receipt may contain a revert reason, which contains a binary-encoded payload.

2.3. Transaction-Reverting Statements

Developers use the statements revert, require, assert, and the deprecated throw to abort execution. Among the statements, require and assert evaluate a given condition and abort the execution depending on the result. require is intended for input checks, while assert guards invariants and, on failure, triggers the built-in Panic(0x01) error [8]. revert aborts unconditionally and can carry arbitrary error data, while throw (removed after Solidity 0.4.13) provides no message. Optionally, revert and require can specify an error message that returns as a binary-encoded payload. An explicitly defined custom error can be used instead of the error message. More specifically, each transaction-reverting statement has the following format:
  • require (condition, error message): This statement is commonly used to enforce input validation or preconditions. If the condition is false, the transaction reverts and returns the message.
  • assert (condition): assert is designed to check invariants in the contract. If the condition is false, it reverts with Panic(0x01). assert does not support a custom message.
  • revert (error message): If the transaction encounters revert, it unconditionally reverts and returns the message.
  • throw: This statement has been deprecated since Solidity 0.4.13, but has been retained in legacy smart contracts. throw does not support a custom message and returns no message.

2.4. Open Challenges in Smart Contract Error Reporting

Producing intelligible error messages is still an unsolved problem in Web3. The following intertwined factors make the task especially challenging:
  • Heterogeneity of Error Messages: Solidity compiles errors into different ABI payload patterns: (1) the standard Error(string) payload, emitted by both require and revert, (2) the Panic(uint256) payload produced by assert, (3) developer-defined custom error selectors with typed arguments, and (4) an empty payload by revert. An empirical study of 3866 verified contracts found that all the forms appear in the real-world smart contract code [9].
  • Gas-Cost Trade-Offs: Developers often shorten or omit error messages to reduce deployment and runtime gas. Replacing a literal message, such as “Unauthorized”, with a four-byte custom error saves 200–400 gas per call at the expense of human-readability.
  • Limited End-User Comprehension: Crypto-wallet user interfaces (UIs) expose little contextual information. Thus, users often misjudge the transaction risk [2]. The same UI limitations affect authentication flows: users routinely sign opaque wallet prompts without grasping the associated danger [10].

2.5. Standard Proposals on Error Messages

In Ethereum, the following standards are suggested to address the problems in smart-contract error reporting. However, adopting these standards remains limited because both on-chain contracts and off-chain clients must comply with them.
  • Status Codes (ERC-1066): ERC-1066 [11] defines a set of status codes to return the result of the transaction execution, as in HTTP codes. To translate the code into a human-readable description, a client must maintain a lookup table.
  • Custom Errors (ERC-838): To provide more informative error messages, ERC-838 [12] introduces a custom error definition to the ABI with named error types. It allows developers to define custom error messages that can be returned when a transaction reverts. However, decoding requires the client to know the error signature; otherwise, the error message remains raw data.
  • Error Definitions on Tokens (ERC-6093): In ERC-6093 [13], standardized error definitions are proposed for well-known token standards (i.e., ERC-20 [4], ERC-721 [14], ERC-1155 [15]) in the custom error format. Still, users can receive consistent error messages only if every token contract implements the standard.
  • Localized Error Messages (ERC-1444): Even if an error message is returned, it is generally in English and unsuitable for global users. ERC-1444 [16] suggests a lookup table mechanism that converts status codes or error identifiers to human-readable localized error messages in different languages.

3. Design Overview

ErrorExplainer transforms a low-level error message into a high-level error description, offering a structured explanation of the following:
  • Which condition triggered the error (e.g., a balance check in require)?
  • What message is given for the error (e.g., “ERC20: insufficient balance”)?
  • Where in the code did the failure arise (e.g., inside transfer function)?
ErrorExplainer’s workflow comprises two analysis stages and one generation stage. Figure 1 illustrates the two tracks of analysis to reconstruct error-relevant information from both the user-side and contract-side data. When a user’s transaction fails, the transaction is handed over to the execution environment analysis. Through the sequential steps, the execution environment analysis provides the implementation address and the user context to the source code analysis and the error description generation, respectively. ErrorExplainer analyzes source code on a component basis. The inter- and intra-component analyses are performed in an interleaved manner to propagate the results at the contract-wide level. The results from the two analysis tracks are delivered to the error description generation stage. ErrorExplainer synthesizes the information into an error description by matching the results.
Specifically, ErrorExplainer has the following stages:
  • Execution Environment Analysis. ErrorExplainer infers what was actually executed from user-level information. It first analyzes the user’s raw transaction data and then resolves the implementation contract address when a proxy pattern is detected, which is used for upgradability [17]. ErrorExplainer then retrieves the verified source code stored on a blockchain explorer, such as Etherscan [6]. Simultaneously, ErrorExplainer parses the calldata to recover the called function and its ABI-encoded arguments.
  • Source Code Analysis. ErrorExplainer performs structural, intra-component, and inter-component analyses to extract every potential revert site together with its guard condition and metadata. Because smart-contract bytecode is immutable, the analysis results can be cached and reused until the proxy’s implementation address changes.
  • Error Description Generation. ErrorExplainer matches the observed revert data against the pre-computed error contexts, identifies the exact failing statement, normalizes heterogeneous formats (strings or custom errors), and synthesizes a human-readable error description.
Assumption 1. 
We assume smart contracts are written in Solidity and executed on EVM-compatible platforms. This setup is widely used in real-world smart-contract deployments.

4. Execution Environment Analysis

In this stage, ErrorExplainer analyzes the user’s transaction to recover the user’s intended action and the implementation contract address at which the transaction has reverted. It then packs the results into a user context, U .

4.1. Transaction Data Analysis

A single transaction contains comprehensive information about a user action. The data required during the execution are encoded in the calldata, while the transaction object stores metadata for pre- and post-execution states. We focus on the following attributes that can provide clues for diagnosing errors:
  • TO Address: The destination address is read directly from the transaction object. Because the smart contract may use the proxy pattern, this address can reference only a forwarding proxy and the implementation logic is located at a different address from the TO address. The proxy analysis in Section 4.2 handles such cases.
  • Function Selector: The EVM interprets the first four bytes of calldata as the function selector, derived from the Keccak-256 hash of the function signature. For example, “0xa9059cbb” identifies “transfer(address,uint256)”. Since a single transaction can call a single function, the function indicated by the function selector is regarded as the entry point of this execution of the transaction.
  • Function Arguments: The remaining bytes of calldata encode the ABI-formatted arguments.
  • Revert Reason: If execution aborts, smart contracts provide a binary-encoded payload for error messages. It can also be obtained during off-chain simulation via eth_call or eth_estimateGas, and on-chain via eth_sendTransaction [18].

4.2. Proxy Analysis

Proxy patterns make smart contracts upgradeable for possible feature updates and against unknown vulnerabilities. With proxy patterns, the logic contract is deployed at another address, and the proxy contract forwards the call to the actual implementation contract. Consequently, the transaction-reverting statements are in the implementation contract, not the proxy contract. ErrorExplainer therefore resolves the implementation contract address before fetching the source code.
Depending on the proxy pattern, the address of the implementation contract is stored at a well-known storage slot [17,19]. ErrorExplainer supports the following popular patterns:
  • EIP-1967 Pattern: EIP-1967 [20] is a standard for upgradeable proxy contracts, where the address of the storage slot is obtained from the hash value of ‘eip1967.proxy.implementation’ minus one.
  • Transparent Proxy Pattern: This pattern is used by OpenZeppelin [21] and is the default pattern for TransparentUpgradeableProxy.
  • Legacy ZeppelinOS Pattern: It is the pattern by ZeppelinOS [22] and is used in legacy contracts.
Table 3 lists the storage slot address for each pattern.
To identify the proxy pattern, ErrorExplainer reads the value at the address of the storage slots in Table 3 via a method, eth_getStorageAt, in the standard JSON-RPC interface of Ethereum. If the slot contains a non-zero address, then the address indicates the implementation contract, and ErrorExplainer updates the TO address to the implementation address. Because forwarding calls are automatically handled by the proxy contract, ErrorExplainer focuses on finding the implementation contract address.

4.3. External Information Fetching

ErrorExplainer fetches the source code for the smart contract deployed at the TO address from the blockchain explorer. Developers upload the source code of deployed smart contracts to the blockchain explorer for public verification. The equivalence between the uploaded source code and the deployed smart contract is ensured since the block explorer marks the uploaded source code as verified only when the code produces the same binary as the deployed one. ErrorExplainer retrieves this verified source code from the blockchain explorer and passes it to the subsequent source code analysis phase.

4.4. Building User Context

From the gathered data, ErrorExplainer constructs the user context as follows:
U = { A : TO address , f s : function selector , ϵ ¯ : binary - encoded error message }

5. Source Code Analysis

5.1. Structure Analysis and Initialization

Before extracting error contexts, ErrorExplainer analyzes the structural features of the smart contract code and builds a component graph together with per-function trace information for subsequent analyses.

5.1.1. Component Graph Construction

A real-world smart contract comprises multiple components, such as interfaces, libraries, and inherited base contracts. In the first step, ErrorExplainer recursively resolves all import directives in the source code to find necessary components, which may point to local or remote sources. Based on these directives, it forms a component set C and expands it into a component graph G C , a directed acyclic graph (DAG) that captures inheritance and linkage relationships.

5.1.2. Trace Analysis

Errors can occur at any point along an execution path. Hence, ErrorExplainer groups candidate error contexts by feasible execution traces to narrow the search space. In Solidity, a trace starts at an external function and proceeds through internal calls. We call the ordered sequence of these functions a trace.
The transaction data reveal the entry function only, leaving all internal steps implicit. By computing which internal functions are reachable from which entry points, ErrorExplainer can pre-filter irrelevant errors. The reachability algorithm operates in three steps:
  • Call Graph Construction: Creates the call graph based on the function call relationships in the source code. The call graph is represented as G f = ( F , E ) where F is the set of functions and E F × F represents call relationships. An edge ( f 1 , f 2 ) E indicates that f 1 invokes f 2 .
  • Graph Reversal: Reverses the call graph to show reachability relationships explicitly. In the reversed call graph G f 1 , every edge ( f 1 , f 2 ) E is reversed to become ( f 2 , f 1 ) .
  • Entry Point Identification: For each function f F , ErrorExplainer traverses G f 1 to identify all external functions, denoted as F e x t , that can reach the given function f. The reachability mapping R c : F 2 F e x t from each function to its set of reachable entry-point functions is given by
    R c ( f ) = { f e x t f e x t F e x t , f e x t G f f } ,
    where f e x t G f f denotes that function f is reachable from function f e x t in the original call graph G f via zero or more intermediate calls.

5.1.3. Error Context Initialization

We denote the error context for a component c as E c . ErrorExplainer initializes E c as follows:
E c = D c , R c , N c ,
where D c stores custom error declarations, R c is the reachability mapping that comes from trace analysis, and N c will later hold normalized errors identified in the component.

5.2. Intra-Component Analysis

In intra-component analysis, ErrorExplainer analyzes statements in a component c C . Components are processed in topological order over G C . Through the analysis of a component c, ErrorExplainer updates the error context E c with custom error definitions, extracted error conditions, and lifted normalized errors.

5.2.1. Normalized Error

ErrorExplainer normalizes the transaction-reverting statements into a unified format and defines them as a normalized error.
The normalized error also contains custom errors, which are structured as a function signature or a type construct, with a name and a list of argument types. The error message is instantiated with a name and argument values when used in a transaction-reverting statement. Hence, before defining the normalized error, we define the error definition context D c for a component c as a map of the following form:
D c ( n ) = a ^ ,
where n is the name of the custom error and a ^ is the argument type list specified in the custom error. This information is used to encode and decode the error message as ABIs.
Finally, we define the normalized error e as the record
e = { τ , ϵ ¯ , ϵ , ϕ , r } ,
where the five fields have the following semantics:
  • τ (type of the error message) indicates whether it involves no message, a plain string, or a custom error type
    τ = | string | custom ( n ) .
    For a custom error type, the full signature is provided by D c ( n ) .
  • ϵ ¯ (binary-encoded message) contains the encoded version of the error message. We define encoding functions for a string (i.e., τ = string ) and custom errors (i.e., τ = custom ( n ) ) as Str ( ) and Custom ( n , a r g s ) , respectively. Otherwise (i.e., τ = ), ϵ ¯ is also ⊥ because the statement has no error message. This field will be used in matching with the error message in U . ϵ ¯ .
  • ϵ (error message text) is a readable form of a string or custom error extracted from the source code.
  • ϕ (error condition) is the source code’s expression that triggers the error, which is the immediate precondition of the transaction-reverting statement. It depends on whether the transaction-reverting statement is a conditional statement or not (e.g., require and revert, respectively). If we cannot find the error condition, it is ⊥.
  • r (source-code reference) is for adding code snippets to the error description.

5.2.2. Statement Traversal

To examine every transaction-reverting statement in a component, ErrorExplainer employs Slither’s built-in visitor mechanism. Slither is a static analysis framework for smart contracts [23]. It first obtains the Solidity abstract syntax tree (AST) by invoking the official Solidity compiler (i.e., solc). It loads each AST node into memory and wraps it in a dedicated Python object. The visitor helps ErrorExplainer to traverse the AST node across all smart contract components, including the abstract interfaces and modifiers.
During traversal, ErrorExplainer compares each statement against a set of predefined patterns and invokes the corresponding handling routine. For instance, the pattern for an error definition extracts custom error declarations, whereas the pattern for an if statement updates the current branch context. Patterns that match transaction-reverting statements are set up as the lifting rules discussed in the next section.

5.2.3. Lifting Error Contexts

The lifting phase has two responsibilities: (1) apply lifting rules for each transaction-reverting statement of require, assert, revert, and throw; and (2) collect custom error definitions and branch predicates needed to complete the normalized errors.
  • Custom Error Definitions. A custom error is declared with the error keyword. From the source code, ErrorExplainer extracts these declarations and parses them into a pair of name (n) and argument type list ( a ^ ). The resulting map is stored in D c and later queried during lifting to encode custom errors (Section 5.2.1).
  • Error Conditions. For every transaction-reverting statement, ErrorExplainer identifies the predicate that triggers the error. Conditional constructs, such as require and assert, include their own predicates. However, unconditional constructs, such as revert and throw, do not have predicates. In such cases, the effective guard condition is determined from the preceding context. Specifically, the immediately preceding control-flow condition becomes the effective condition for these unconditional error statements.
ErrorExplainer therefore captures predicates from conditional statements (i.e., if) and the conditional ternary operator (i.e., a ? b : c ) and stores a reference to the condition in B . Whenever a new conditional statement or operator is encountered, B is updated. In this way, ErrorExplainer can keep track of the branch predicates and uses them as the error conditions for the unconditional error statements.
  • Lifting Rules. Traversing the statements in the component, ErrorExplainer applies the rules in Table 4 to lift normalized errors from the transaction-reverting statements, require, assert, revert, and throw.
  • require (Rule 1a, 1b, 1c):
    Rule 1a. The require statement includes the error condition. If the error output is a literal string (e.g., “outString”), ErrorExplainer encodes it via an encoding function for strings, Str ( ) , as Str ( o u t S t r i n g ) . For example,
    : require ( x > 0 , Value must be positive )
    is lifted to a normalized error
    { τ : string , ϵ ¯ : 0 x 08 c 379 a 1656616 c 0000 , ϵ : Value must be positive , ϕ : x > 0 , r : } ,
    where the line number identifies the statement in the source code. (For brevity, we omit the description of r in other lifting rules).
    Rule 1b. If the second argument is a custom error n ( a r g s ) , then ErrorExplainer sets the type of the error message as custom ( n ) and encodes it by Custom ( n , a r g s ) , which retrieves the full signature of the custom error from D c ( n ) and returns the first four bytes that correspond to the custom error selector only.
    Rule 1c. If the error output is empty or omitted, then the three fields, τ , ϵ ¯ , and ϵ are represented as ⊥.
  • assert (Rule 2)
    An assert statement acts as a predefined custom error of Panic(0x01) without explicit error messages. Thus, it is lifted as a custom error with Custom ( Panic , 0 x 01 ) and the given error condition ϕ .
  • revert (Rule 3a, 3b, 3c)
    revert follows the same sub-rules as require for τ , ϵ ¯ , and ϵ , but it lacks an explicit predicate. Thus, the branch predicate in B is used for ϕ . Additionally, if revert is used without any arguments, it is lifted as the same as throw (Rule 3c).
  • throw (Rule 4)
    Legacy throw statements carry neither the error message nor the error condition. Thus, we lift it into an empty-output normalized error that inherits the error condition from B .

5.2.4. Updating Error Context

After lifting, all normalized errors are grouped by their enclosing function. ErrorExplainer then updates the normalized-error map N c as follows: The lifted normalized errors are collected on a per-function basis. ErrorExplainer updates the normalized error map N c by adding newly collected normalized errors as follows:
f F , N c ( f ) N c ( f ) { e f , 1 , e f , 2 , , e f , n } ,
where N c and N c denote the updated and the previous maps, respectively, and each e f , i is the normalized error lifted from the function f. Note that N c may already contain entries propagated from predecessor components along the component graph. Those entries are preserved, and new errors are merged in. This cumulative strategy ensures that information gathered in earlier components remains available during the subsequent inter-component analysis.

5.3. Inter-Component Analysis

ErrorExplainer next performs an inter-component pass to propagate information along the component graph. Components are processed in topological order. After each component c is analyzed, ErrorExplainer forwards the error context  E c to all the successors in the component graph.
Specifically, the freshly computed map is merged into the existing maps of all successor components:
N succ N succ N c for every successor s u c c of c .
Through this process, ErrorExplainer extends the intra-component analysis to the inter-component analysis by interleaving the analysis and the propagation steps. It ensures that any error discovered or partially analyzed in one component propagates throughout all the components. When the traversal reaches the final component, its error context contains the fully analyzed results for the deployed smart contract and is suitable for the subsequent matching process.

6. Error Description Generation

In the final stage, ErrorExplainer matches the user error information in U against the analyzed error contexts and generates an error description as the final output.

6.1. Matching Process

The goal is to map the runtime error information captured in U to a unique static error description produced by the analysis in Section 5. ErrorExplainer matches the error information in three filters: (1) function selector, (2) call-graph reachability, and (3) encoded error output. The following steps expand on this pipeline.
  • Choose the Richest Error Context: Because information flows forward along G C , the deployed contract (i.e., the last vertex in topological order) contains the most complete context. We denote this context by
    R 0 = E c ,
    where c is the final component.
  • Build Candidate Sets (Selector Filter): Two candidate pools are constructed from R 0 using the function selector observed at runtime ( U . f s ).
    • Function-level set contains only the normalized errors that belong to the function whose selector exactly matches the call site:
      R 1 = { ( e , f ) e R 0 . N c ( f ) , f = U . f s .
    • Trace-level set is a superset that includes errors located in any function transitively reachable from the entry point. This set is used if the function-level match fails:
      R 1 = { ( e , f ) e R 0 . N c ( f ) , U . f s R 0 . R c ( f ) , f = U . f s .
  • Compare Encoded Error Outputs (Output Filter): Each candidate carries a normalized error output e. ϵ ¯ . The binary error payload emitted on-chain is compared as follows:
    R 2 = { ( e , f ) R 1 | U . ϵ ¯ = e . ϵ ¯ , if e . τ = string U . ϵ ¯ | 32 = e . ϵ ¯ | 32 , if e . τ = custom } .
    For custom errors, only the first four bytes (the error selector) are stable across deployments and therefore used in the comparison.
  • Fallback to Trace-Level Candidates: If R 2 = , the procedure is repeated with R 1 in place of R 1 . This handles the case where a proxy causes the initial selector match to fail.
  • Emit the Final Match: The final set e ^ is chosen as
    e ^ = e R 2 e , if | R 2 | 1 , e R 2 , otherwise .
    A singleton R 2 presents an unambiguous error description. Multiple entries imply that the developer reuses identical messages or empty strings. In such cases, ErrorExplainer concatenates each field of the entries (denoted by the meet operator ⊓).

6.2. Error Description Construction

In the final step, ErrorExplainer converts e ^ into an error description in the four-field structure. The error description fields are described with the matched parameter from e ^ in Table 5.

7. Evaluation

7.1. Research Questions

To evaluate the effectiveness of ErrorExplainer in providing meaningful error descriptions for real-world cases, we investigate the following research questions:
  • RQ1 (Identification accuracy): How thoroughly does ErrorExplainer locate and extract all transaction-reverting statements from the source code of Solidity smart contracts?
  • RQ2 (Information completeness): How rich is each extracted error context, and does it supply all data fields required for a useful description?
  • RQ3 (Matching fitness): How unambiguously can ErrorExplainer map user-side error information to the correct error context?
RQ1 measures the soundness of the static analysis in identifying and extracting error contexts from the source code of Solidity smart contracts. RQ2 and RQ3 evaluate the practical utility of the resulting error contexts for diagnosing user-reported failures.

7.2. Implementation

ErrorExplainer is implemented in Python. Static analysis is built on top of Slither [23], which provides an analysis framework at the level of an abstract syntax tree (AST) of Solidity contracts. We first recover the inter-component structure of smart contracts, including inheritance hierarchies, modifiers, interfaces, and libraries, with the help of Slither. Within each contract, we then enumerate all transaction-reverting statements (require, assert, revert, throw) and assemble precise error contexts with the structural metadata. For ABI encoding and decoding of calldata, we use the web3.py library [24].

7.3. Dataset

We evaluate ErrorExplainer on the SC-Bench dataset [5], a corpus of real-world Solidity smart contracts drawn from blockchain explorers: Etherscan (Ethereum) and Polygonscan (Polygon). The benchmark covers the most popular token standards (ERC-20, ERC-721, and ERC-1155) and spans a wide range of contracts that capture the structural complexity found in production code. The dataset is designed to analyze the impact of error-injected smart contracts on real-world applications. Thus, it provides each contract in two versions: (1) the original source code and (2) its mutated version in which randomly selected statements have been altered or removed. Accompanying metadata specify exactly which statements were deleted or mutated.
This configuration is suitable for our evaluation because real-world smart contracts rarely document the total number of transaction-reverting statements. If ErrorExplainer counts all transaction-reverting statements in both the original and mutated versions correctly, the difference between the two counts should be equal to the number of deletions recorded in the metadata, providing reliable ground-truth for RQ1.
We therefore filter SC-Bench for our evaluation as follows:
  • Keep only contract pairs whose mutation log explicitly includes the removal of at least one transaction-reverting statement.
  • Discard any pair whose mutated contract no longer compiles.
The resulting evaluation dataset contains 335 original-mutated pairs, i.e., 670 individual smart contracts.
  • Runtime Cost. We measured the computational overhead of ErrorExplainer’s static analysis pipeline. On an Apple silicon M1 (10-core CPU, 32 GB RAM), the end-to-end analysis of a single contract takes, on average, 0.64 s with a standard deviation of 0.55 s across the entire evaluation set. Because blockchain networks typically operate with block times on the order of seconds, this latency is negligible for practical front-end integration and real-time error reporting. Furthermore, this analysis is required only once per contract, and the results can be cached and reused, as the smart contracts remain immutable for their lifetime.

7.4. RQ1: Identification Accuracy

We first measure how completely ErrorExplainer recovers transaction-reverting statements. Across the 335 contract pairs, ErrorExplainer extracted a total of 6284 normalized errors. Each corresponds to one transaction-reverting statement. Of the 1161 statements that SC-Bench intentionally removed in the mutated variants, ErrorExplainer correctly detected 96.99% of those deletions, missing only 3.01% of them. This high recall indicates that few transaction-reverting statements are missed by the static analysis.
Figure 2 reports the mean number of errors per contract: 18.76 for original versions and 15.4 for mutated versions. The drop in the mutated version matches the ground-truth removals, which validates the precision of ErrorExplainer.
Further analysis is provided in Figure 3, which breaks the results down by compiler version. Three quarters of the smart contracts target ≥0.8.4, i.e., after custom errors became available. ErrorExplainer handles both cases uniformly. The largest contract analyzed (Solidity 0.8.1) contained 49 distinct transaction-reverting statements.
Lastly, Figure 4 plots the number of identified errors against the source-code length. The correlation is weak ( 0.29 ), but an upward trend confirms that contracts with more logic naturally embed more guard conditions. Figure 4 also shows that ErrorExplainer can scale with the complexity increase.

7.5. RQ2: Information Completeness

This research question asks how fully ErrorExplainer fills each error context. For a normalized error record, we expect five fields { τ , ϵ ¯ , ϵ , ϕ , r } . We define the completeness of a contract C as the mean fraction of filled fields:
I ( C ) = 1 | E C | e E C filled ( e ) T ,
where T is the total number of fields (i.e., T = 5 ) and filled ( e ) counts non-empty fields in error e.
We compute this metric for every smart contract in both the original and mutated versions (670 smart contracts in total). The global average completeness is 0.952 (i.e., 95.2%).
Figure 5 presents per-version completeness statistics. Completeness remains consistently high, ranging from 0.9 to 1.0 for all compiler releases newer than 0.4.24. The dip in 0.4.24 is caused by unconditional throw statements and blank revert, where two fields of normalized error records are skipped by ErrorExplainer.
Figure 6 shows the relationship between completeness and lines of code. The correlation is mild but positive (+0.19). Larger smart contracts tend to include more modifiers, library calls, and descriptive error messages, all of which let ErrorExplainer fill more fields.
Higher completeness means that ErrorExplainer can identify more necessary information to describe the error. However, this also means that the developers fundamentally provide more precise transaction-reverting statements (e.g., suppressing unconditional revert statements and empty error messages). This tendency persists as more enhanced features for error definition are introduced.

7.6. RQ3: Matching Fitness

Matching fitness quantifies how precisely ErrorExplainer links user-supplied evidence to the correct error context. For a contract component C, we consider two granularities:
  • Function-level matching. Let S C E C be the subset in which every pair of contexts differs both in the enclosing function and in the encoded error output:
    i j ( i . f j . f ) ( i . ϵ ¯ j . ϵ ¯ ) .
  • Trace-level matching. Let S C E C comprise contexts whose traces have disjoint entry points but still have distinct error outputs:
    i j ( i . f ¯ e j . f ¯ e = ) ( i . ϵ ¯ j . ϵ ¯ ) .
We define the two matching fitness scores as
M F = | S C | | E C | , M T = | S C | | E C | .
Across the entire dataset, ErrorExplainer achieves an average  M F = 0.954 and M T = 0.604 . In other words, once the target function is correctly identified, ErrorExplainer returns a unique match 95.4 % of the time, while with only an entry function, that probability remains 60.4 % . Function-level discrimination relies only on distinct error outputs within the same function, which is an easier requirement than discriminating across entire traces because many functions may share identical error outputs or selectors. Hence, M F M T for every contract.
Figure 7 and Figure 8 break fitness down by Solidity version and lines of code, respectively. M F stays in the range between 0.9 and 1.0 for recent versions. At Solidity 0.4.24, the dip resembles the earlier completeness drop and reflects blank error messages that provide no single matches distinguishable by error outputs. For mid-size smart contracts (1800 lines of code), multiple business logics are aggregated but reuse identical error messages, which leads to a drop in M T .

8. Discussion and Limitations

8.1. Practical Use Cases

The usability of ErrorExplainer has been evaluated in the most common on-chain scenario: ERC-20, ERC-721, and ERC-1155 contracts. Those standards dominate wallet interactions, token bridges, and marketplace front ends. With an average latency of only 0.64 s (Section 7.3), a provider can pre-index verified token contracts once, cache the results, and return human-readable explanations to users in real time.
The same pipeline applies to DeFi protocols, where business logic is more complex (e.g., multi-step liquidity provision, leveraged vaults, or automated liquidations). In such settings, a failed transaction can incur direct financial risk. By analyzing every revert path, ErrorExplainer reveals a clear revert reason, such as “Health factor below 1.0” and “Pool cap reached”. This enables users to adjust parameters or strategy in a single iteration rather than through trial and error.
For instance, DeFi staking products have multiple lock-up conditions. Unstaking logic may check the minimum lock period, a cool-down window, and delegation status. When a withdrawal attempt reverts, the crypto wallet can only display “execution reverted”, leaving the user to guess which condition failed. However, ErrorExplainer maps the runtime information to the code-level error context and can provide a detailed error message drawn from the source code, such as “Withdrawal blocked: cool-down period ends in 2 days”. The user can learn what must change to unblock the withdrawal.

8.2. Abuse of Semantic Error Analysis

Although ErrorExplainer is designed to improve Web3 usability, detailed error diagnostics inevitably have a dual-use aspect. By observing which branch reverts under forged inputs, an attacker can reverse-engineer contract logic and find vulnerabilities.
Prior work confirms that revert data leak valuable information. SmartState [25] demonstrates that “state-reverting” patterns can be searched to locate profitable and denial-of-service faults. ContractFuzzer [26] uses the presence or absence of specific revert selectors as guidance for deeper fuzzing.
In practice, however, abusing semantic error analysis, as in ErrorExplainer, is limited by a mismatch of objectives. Attack tools must explore a vast input space to trigger reverts, but ErrorExplainer delivers richer information only after a revert has occurred. Therefore, we position ErrorExplainer as a usability enhancement rather than a new attack oracle.

8.3. Limitations

ErrorExplainer is intentionally lightweight. It visits Solidity AST and builds error contexts without fine-grained data-flow analysis. As a result, ErrorExplainer cannot determine whether a try–catch block handles a revert that originates deeper in the call stack. If a catch handler converts the failure into a benign return value, ErrorExplainer still lists the original error, because nothing in the syntax indicates its cancellation.
At present, ErrorExplainer skips the inline assembly blocks (assembly {}). Thus, any reverts issued inside these blocks remain undetected. Extending coverage would require assembly pattern signatures or a decompiler pass. Both are left for future work.
ErrorExplainer assumes that the source code has been verified on a block explorer, which means the published hashes exactly match the on-chain bytecode. Verification is a one-time task best performed by the developer. When source code is unavailable, we can fall back to bytecode decompilation. However, the recovered high-level abstractions are coarse, and the resulting error context may be unreliable.

9. Related Work

9.1. Error Handling in Smart Contracts

Recent work has characterized how developers write and evolve error handling in smart contracts. Lu Liu et al. [9] systematically classified the real-world use of transaction-reverting statements into seven categories, including address authority check, token verification, range check, and so on. They showed that explicit require and revert checks appear more often than if statements in smart contracts. By removing those statements and re-analyzing the code with vulnerability detectors, they demonstrated the crucial roles of transaction-reverting statements.
Two companion studies by C. Mitropoulos et al. charted the adoption of Solidity error-handling features [27] and addressed the security problems when the transaction-reverting statements fail to protect against invalid states [28]. Using regular-expression pattern matching, they highlight misuses such as missing validations for external-call return values.
From a usability angle, Y. Panicker et al. [2] investigated how end-users perceive the transfer risk in ERC-20 smart contracts. They found that 71% of participants misunderstood the transfer risks, and even Web3-proficient developers held similar misconceptions. In particular, mainstream crypto wallets, such as MetaMask, do not provide the reason for transfer failure errors, making it difficult for users to recognize the transfer risk.
ErrorExplainer complements these studies by automatically linking a runtime failure to its exact revert code and returning a rich, human-readable error context, which addresses the discussed comprehensive gap.

9.2. Static and Dynamic Vulnerability Analysis

Most security analyzers treat reverts as a signal of vulnerability. Symbolic-execution-based tools like Oyente [29] and Mythril [30] detect missing or unreachable reverts by exploring feasible paths. The static analyzer Slither [23] also finds missing or unreachable reverts to diagnose re-entrancy, integer overflow, or access-control bugs. SmartState [25] extends this approach by searching for state-reverting patterns that attackers can exploit through atomic execution. It finds the assertion-related state dependencies through data-flow analysis of the smart contract source code and the temporal dependencies from historical transaction traces. ContractFuzzer [26] guides input generation by using revert as a signal in extending fuzzing coverage.
In contrast, ErrorExplainer starts after a revert has already been triggered and explains the failure to users. Rather than detecting new bug patterns, it identifies a matched transaction-reverting statement to the user-reported error from the source code and builds an error context.

9.3. Datasets and Large-Scale Instrumentations

To support automated auditing, S. Xia et al. created the SC-Bench dataset [5]. They collected 5377 real-world smart contracts and expanded them by automatically injecting errors. The injected errors include the missing error checks with transaction-reverting statements, which the ERC standards require. Because SC-Bench preserves real-world complexity and modern coding style, it is suitable for evaluating ErrorExplainer, although our goal is interpretation rather than ERC-rule compliance.

10. Conclusions

Diagnosing transaction failures is critical for both users and developers in Web3. However, the absence of standardized error messages and the structural complexity of smart contracts make the task challenging. In particular, non-standardized error outputs leave users guessing the causes of failures and appropriate remedies without a clear explanation.
I presented ErrorExplainer, a client-side framework that links low-level revert data to source-level context, providing clear, human-readable explanations. Its lightweight static pipeline extracts every transaction-reverting statement into a uniform error context, including the error message, the location of the error, and the error condition. Extensive experiments on the real-world SC-Bench dataset show that ErrorExplainer locates 6284 of the transaction-reverting statements, and correctly matches 96.99% out of 1161 injected changes, achieving an information completeness of 0.952 and a matching fitness of 0.954 (function-level) and 0.604 (trace-level).
Despite its effectiveness, ErrorExplainer currently relies on static analysis of verified Solidity source code. The lifting rules need to be extended to support other languages or blockchains. Applying dynamic execution states to evaluate the triggering conditions in the error context can improve the matching fitness. However, the runtime overhead of this dynamic analysis should be considered.
In future work, we plan to incorporate data-flow analysis to support filtering via guard conditions and extend error-context patterns to recognize inline assembly reverts. We are also exploring LLM prompts that translate the extracted context into natural-language advice. These enhancements will move ErrorExplainer closer to a universal, real-time error-explanation layer for Web3.

Funding

This research received no external funding.

Institutional Review Board Statement

Not applicable.

Informed Consent Statement

Not applicable.

Data Availability Statement

Data are contained within this article.

Conflicts of Interest

The author declares no conflicts of interest.

References

  1. Jang, H.; Han, S.H. User experience framework for understanding user experience in blockchain services. Int. J. Hum.-Comput. Stud. 2022, 158, 102733. [Google Scholar] [CrossRef]
  2. Panicker, Y.; Soremekun, E.; Sun, S.; Chattopadhyay, S. End-user Comprehension of Transfer Risks in Smart Contracts. arXiv 2024, arXiv:2407.11440. [Google Scholar]
  3. Waas, M. Downsizing Contracts to Fight the Contract Size Limit. 2020. Available online: https://ethereum.org/en/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/ (accessed on 25 May 2025).
  4. Vogelsteller, F.; Buterin, V. ERC-20: Token Standard. 2015. Available online: https://eips.ethereum.org/EIPS/eip-20 (accessed on 25 May 2025).
  5. Xia, S.; He, M.; Song, L.; Zhang, Y. SC-Bench: A Large-Scale Dataset for Smart Contract Auditing. 2024. Available online: http://arxiv.org/abs/2410.06176 (accessed on 25 May 2025).
  6. Etherscan. Available online: https://etherscan.io (accessed on 25 May 2025).
  7. Wood, G. Ethereum: A Secure Decentralised Generalised Transaction Ledger. 2014. Available online: https://ethereum.github.io/yellowpaper/paper.pdf (accessed on 25 May 2025).
  8. Team, S.C. Solidity 0.8.25 Documentation: Error Handling. 2024. Available online: https://docs.soliditylang.org/en/v0.8.25/control-structures.html (accessed on 25 May 2025).
  9. Liu, L.; Wei, L.; Zhang, W.; Wen, M.; Liu, Y.; Cheung, S.C. Characterizing transaction-reverting statements in ethereum smart contracts. In Proceedings of the 2021 36th IEEE/ACM International Conference on Automated Software Engineering (ASE), Melbourne, Australia, 15–19 November 2021; IEEE: Piscataway, NJ, USA, 2021; pp. 630–641. [Google Scholar]
  10. Yan, K.; Zhang, X.; Diao, W. Stealing trust: Unraveling blind message attacks in web3 authentication. In Proceedings of the 2024 on ACM SIGSAC Conference on Computer and Communications Security, Salt Lake City, UT, USA, 14–18 October 2024; pp. 555–569. [Google Scholar]
  11. Zelenka, B.; Carchrae, T.; Naumenko, G. ERC-1066: Status Codes. 2018. Available online: https://eips.ethereum.org/EIPS/eip-1066 (accessed on 25 May 2025).
  12. Bond, F.; de Souza, R.R. ERC-838: ABI Specification for REVERT Reason String. 2020. Available online: https://eips.ethereum.org/EIPS/eip-838 (accessed on 25 May 2025).
  13. García, E.; Giordano, F.; Croubois, H. ERC-6093: Custom Errors for Commonly-Used Tokens. 2022. Available online: https://eips.ethereum.org/EIPS/eip-6093 (accessed on 25 May 2025).
  14. Entriken, W.; Shirley, D.; Evans, J.; Sachs, N. ERC-721: Non-Fungible Token Standard. 2018. Available online: https://eips.ethereum.org/EIPS/eip-721 (accessed on 25 May 2025).
  15. Radomski, W.; Cooke, A.; Castonguay, P.; Therien, J.; Binet, E.; Sandford, R. ERC-1155: Multi Token Standard. 2018. Available online: https://eips.ethereum.org/EIPS/eip-1155 (accessed on 25 May 2025).
  16. Zelenka, B.; Cooper, J. ERC-1444: Localized Messaging with Signal-to-Text. 2018. Available online: https://eips.ethereum.org/EIPS/eip-1444 (accessed on 25 May 2025).
  17. Meisami, S.; Bodell, W.E., III. A Comprehensive Survey of Upgradeable Smart Contract Patterns. 2023. Available online: https://arxiv.org/abs/2304.03405 (accessed on 25 May 2025).
  18. Ethereum Foundation. Ethereum JSON-RPC API Specification. 2024. Available online: https://ethereum.org/en/developers/docs/apis/json-rpc/ (accessed on 25 May 2025).
  19. Li, X.; Yang, J.; Chen, J.; Tang, Y.; Gao, X. Characterizing ethereum upgradable smart contracts and their security implications. In Proceedings of the ACM Web Conference 2024, Singapore, 13–17 May 2024; pp. 1847–1858. [Google Scholar]
  20. Palladino, S.; Francisco Giordano, H.C. EIP-1967: Upgradeable Proxy Storage Slots. 2019. Available online: https://eips.ethereum.org/EIPS/eip-1967 (accessed on 25 May 2025).
  21. OpenZeppelin. OpenZeppelin Contract Library. Available online: https://docs.openzeppelin.com/contracts/5.x/ (accessed on 25 May 2025).
  22. Nadolinski, E.; Spagnuolo, F. Proxy Patterns. 2018. Available online: https://blog.openzeppelin.com/proxy-patterns/ (accessed on 25 May 2025).
  23. Crytic. Slither, the Smart Contract Static Analyzer. 2024. Available online: https://github.com/crytic/slither (accessed on 25 May 2025).
  24. Ethereum Foundation. web3.py: A Python Library for Interacting with Ethereum. Available online: https://github.com/ethereum/web3.py (accessed on 25 May 2025).
  25. Liao, Z.; Hao, S.; Nan, Y.; Zheng, Z. SmartState: Detecting state-reverting vulnerabilities in smart contracts via fine-grained state-dependency analysis. In Proceedings of the 32nd ACM SIGSOFT International Symposium on Software Testing and Analysis, Seattle, WA, USA, 17–21 July 2023; pp. 980–991. [Google Scholar]
  26. Jiang, B.; Liu, Y.; Chan, W.K. Contractfuzzer: Fuzzing smart contracts for vulnerability detection. In Proceedings of the 33rd ACM/IEEE International Conference on Automated Software Engineering, Montpellier, France, 3–7 September 2018; pp. 259–269. [Google Scholar]
  27. Mitropoulos, C.; Kechagia, M.; Maschas, C.; Ioannidis, S.; Sarro, F.; Mitropoulos, D. Charting The Evolution of Solidity Error Handling. arXiv 2024, arXiv:2402.03186. [Google Scholar]
  28. Mitropoulos, C.; Kechagia, M.; Maschas, C.; Ioannidis, S.; Sarro, F.; Mitropoulos, D. Broken Agreement: The Evolution of Solidity Error Handling. In Proceedings of the 18th ACM/IEEE International Symposium on Empirical Software Engineering and Measurement, Barcelona, Spain, 24–25 October 2024; pp. 257–268. [Google Scholar]
  29. Luu, L.; Chu, D.H.; Olickel, H.; Saxena, P.; Hobor, A. Making smart contracts smarter. In Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security, Vienna, Austria, 24–28 October 2016; pp. 254–269. [Google Scholar]
  30. Mueller, B. Smashing ethereum smart contracts for fun and real profit. HITB SECCONF Amst. 2018, 9, 4–17. [Google Scholar]
Figure 1. Overview of ErrorExplainer. Two analysis tracks, one over the execution environment and the other over source code, converge to produce an error description showing the failure’s cause.
Figure 1. Overview of ErrorExplainer. Two analysis tracks, one over the execution environment and the other over source code, converge to produce an error description showing the failure’s cause.
Applsci 15 06006 g001
Figure 2. Errors identified vs. ground-truth removals. For every contract pair, ErrorExplainer counts the number of transaction-reverting statements in the original and mutated versions. The difference between the two bars is compared with the exact number of deletions recorded in the mutation log.
Figure 2. Errors identified vs. ground-truth removals. For every contract pair, ErrorExplainer counts the number of transaction-reverting statements in the original and mutated versions. The difference between the two bars is compared with the exact number of deletions recorded in the mutation log.
Applsci 15 06006 g002
Figure 3. Average errors per contract by Solidity version. Bars report mean number of transaction-reverting statements that ErrorExplainer detects in original and mutated versions of every contract, grouped by compiler versions. Solidity versions show rise in error counts.
Figure 3. Average errors per contract by Solidity version. Bars report mean number of transaction-reverting statements that ErrorExplainer detects in original and mutated versions of every contract, grouped by compiler versions. Solidity versions show rise in error counts.
Applsci 15 06006 g003
Figure 4. Relationship between identified errors and lines of code (LOCs) Each point represents one contract. x-axis is LOCs, and y-axis is number of errors detected by ErrorExplainer. Transaction-reverting statements increase almost linearly with LOCs.
Figure 4. Relationship between identified errors and lines of code (LOCs) Each point represents one contract. x-axis is LOCs, and y-axis is number of errors detected by ErrorExplainer. Transaction-reverting statements increase almost linearly with LOCs.
Applsci 15 06006 g004
Figure 5. Information completeness by Solidity version. Completeness is fraction of fields that ErrorExplainer successfully filled. ErrorExplainer sustains 90 % completeness for all compiler versions newer than 0.4.24.
Figure 5. Information completeness by Solidity version. Completeness is fraction of fields that ErrorExplainer successfully filled. ErrorExplainer sustains 90 % completeness for all compiler versions newer than 0.4.24.
Applsci 15 06006 g005
Figure 6. Information completeness vs. lines of code. Contracts are binned by LOCs. Uniformly high values across all versions indicate ErrorExplainer’s static patterns are robust to increasing contract complexity.
Figure 6. Information completeness vs. lines of code. Contracts are binned by LOCs. Uniformly high values across all versions indicate ErrorExplainer’s static patterns are robust to increasing contract complexity.
Applsci 15 06006 g006
Figure 7. Matching fitness of error context by Solidity version. Matching fitness measures the proportion of unique error contexts that ErrorExplainer can distinguish by error outputs. For function-level matching, performance stays above 90% for versions 0.5–0.8, indicating that ErrorExplainer generalizes well to evolving language features. The fitness of trace-level matching is lower, but still above 60% in average, suggesting that ErrorExplainer can still identify the correct error context even under complex call chains.
Figure 7. Matching fitness of error context by Solidity version. Matching fitness measures the proportion of unique error contexts that ErrorExplainer can distinguish by error outputs. For function-level matching, performance stays above 90% for versions 0.5–0.8, indicating that ErrorExplainer generalizes well to evolving language features. The fitness of trace-level matching is lower, but still above 60% in average, suggesting that ErrorExplainer can still identify the correct error context even under complex call chains.
Applsci 15 06006 g007
Figure 8. Matching fitness vs. lines of code. Bars give the mean matching fitness for each LOC bin. The flat trends of function-level matching fitness show that the accuracy of ErrorExplainer is independent of contract length, indicating the approach is suitable for a wide range of smart contracts.
Figure 8. Matching fitness vs. lines of code. Bars give the mean matching fitness for each LOC bin. The flat trends of function-level matching fitness show that the accuracy of ErrorExplainer is independent of contract length, indicating the approach is suitable for a wide range of smart contracts.
Applsci 15 06006 g008
Table 1. Examples of error conditions in the ERC-20 standard.
Table 1. Examples of error conditions in the ERC-20 standard.
FunctionError ConditionDescription
transferInsufficient balance of senderThe sender account does not have enough balance to complete the transfer.
recipient is address(0)Transfers to the zero address are not allowed, preventing token loss.
approvespender is address(0)Approval to the zero address is disallowed to avoid confusion regarding allowance ownership.
Table 2. Returned data to users vs. ErrorExplainer’s output on the failed operation of insufficient balance of the sender.
Table 2. Returned data to users vs. ErrorExplainer’s output on the failed operation of insufficient balance of the sender.
Returned Data to UserErrorExplainer-Extracted Error Context
(binary) 0 x 08 c 379 a 002645524332303 a 207472616 e 0000 Message: “ERC20: transfer amount exceeds balance
 Origin: “_transfer
 Error condition: “senderBalance >= amount
 Code snippet: “require(senderBalance >= amount,);
Table 3. Proxy patterns and storage slots.
Table 3. Proxy patterns and storage slots.
PatternStorage Slot
EIP-19670x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
Transparent Proxy0x5c60da1b00000000000000000000000000000000000000000000000000000000
ZeppelinOS0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3
Table 4. Lifting rules that map each transaction-reverting statement to a normalized error.
Table 4. Lifting rules that map each transaction-reverting statement to a normalized error.
Rule No.Statement PatternNormalized Error
1a require ( cond , str ) { τ : string , ϵ ¯ : Str ( str ) , ϵ : str , ϕ : cond , r }
1b require ( cond , n ( args ) ) { τ : custom ( n ) , ϵ ¯ : Custom ( n , args ) , ϵ : n , ϕ : cond , r }
1c require ( cond ) { τ : , ϵ ¯ : , ϵ : , ϕ : cond , r }
2 assert ( ϕ ) { τ : custom ( Panic ) , ϵ ¯ : Custom ( Panic , 0 x 01 ) , ϵ : assertion failed , ϕ , r }
3a revert ( str ) { τ : string , ϵ ¯ : Str ( str ) , ϵ : str , ϕ : B , r }
3b revert ( n ( args ) ) { τ : custom ( n ) , ϵ ¯ : Custom ( n , args ) , ϵ : n , ϕ : B , r }
3c revert ( ) { τ : , ϵ ¯ : , ϵ : , ϕ : B , r }
4 throw { τ : , ϵ ¯ : , ϵ : , ϕ : B , r }
Table 5. Structured error description constructed by ErrorExplainer.
Table 5. Structured error description constructed by ErrorExplainer.
FieldDescriptionMatched Parameter
Error MessageHuman-readable string that explains what went wrong and why. e ^ . ϵ
OriginEnclosing component where the normalized error is defined. Origin names carry semantic cues (e.g., onlyOwner) to understand the error. f | e ^ N f
Error ConditionBoolean guard condition that triggers the revert. e ^ . ϕ
Source Code SnippetCode excerpt around the transaction-reverting statement, useful for users or tools (e.g., LLMs). e ^ .r
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.

Share and Cite

MDPI and ACS Style

Lee, J. ErrorExplainer: Automated Extraction of Error Contexts from Smart Contracts. Appl. Sci. 2025, 15, 6006. https://doi.org/10.3390/app15116006

AMA Style

Lee J. ErrorExplainer: Automated Extraction of Error Contexts from Smart Contracts. Applied Sciences. 2025; 15(11):6006. https://doi.org/10.3390/app15116006

Chicago/Turabian Style

Lee, JongHyup. 2025. "ErrorExplainer: Automated Extraction of Error Contexts from Smart Contracts" Applied Sciences 15, no. 11: 6006. https://doi.org/10.3390/app15116006

APA Style

Lee, J. (2025). ErrorExplainer: Automated Extraction of Error Contexts from Smart Contracts. Applied Sciences, 15(11), 6006. https://doi.org/10.3390/app15116006

Note that from the first issue of 2016, this journal uses article numbers instead of page numbers. See further details here.

Article Metrics

Back to TopTop