# Potential Vulnerabilities in EVM Implementations: Overlooked DelegateCall in Precompiled Contracts

{% hint style="info" %}
[**Book an audit with Zokyo**](https://www.zokyo.io/)
{% endhint %}

Blockchain technology has rapidly evolved over the years, and with it, the desire for improved efficiency and functionality has grown. In pursuit of these goals, several projects have ventured to implement their versions of the Ethereum Virtual Machine (EVM) and introduced custom precompiled contracts to enhance performance. However, while these innovations are commendable, a recurring oversight has emerged, which may pose significant security risks.

#### Understanding the Basics

Before delving into the potential vulnerabilities, it's crucial to understand the fundamental concepts:

1. **EVM**: Ethereum's runtime environment, ensuring consistent smart contract execution across all network nodes.
2. **Precompiled Contracts**: These are contracts whose functionality is hard-coded into the blockchain nodes. They're designed to perform specific functions more efficiently than a standard smart contract written in Solidity could. Given their hard-coded nature, they're less flexible than regular contracts but can be much faster and less gas-intensive.
3. **DelegateCall**: A unique functionality in Ethereum smart contracts. It allows a contract to execute the code of another contract while preserving its own state. In simple terms, Contract A can "borrow" the logic of Contract B without changing Contract A's data.

#### The Overlooked DelegateCall

The DelegateCall function has proven to be a double-edged sword. While it can be handy for contract upgrades and logic reuse, it can also introduce vulnerabilities if not appropriately managed. This is especially true for projects that introduce custom precompiled contracts without adequately considering the implications of DelegateCall.

Here's the crux of the issue: When new EVM implementations create custom precompiled contracts, they inherently trust that these contracts are safe since they're hardcoded. But if these precompiled contracts are made accessible via DelegateCall from other contracts, and the EVM implementation hasn't been designed with this in mind, unforeseen behaviors might emerge.

#### The Off-chain Dilemma

The security concerns don't stop at the blockchain's edge. Many blockchain projects incorporate off-chain systems to improve scalability and efficiency. These systems, designed to work seamlessly with on-chain components, often rely on the predictability and security of the on-chain environment.

If a new EVM implementation's precompiled contracts are not designed to handle DelegateCall properly, malicious actors might exploit this oversight, triggering unpredictable behaviors in the associated off-chain systems. Since off-chain systems don't benefit from the same consensus and immutability mechanisms as on-chain processes, vulnerabilities here can have far-reaching implications.

### Extended Example: The Misleading DelegateCall

Let's delve into an illustrative scenario to capture the described vulnerability in the presence of `msg.value` and `payable`.

Imagine a blockchain ecosystem with two main precompiled contracts - `DepositContract` and `EventLogContract`.

```
// DepositContract.sol
pragma solidity ^0.8.0;

contract DepositContract {
    EventLogContract eventLog = new EventLogContract();

    function acceptEther() public payable {
        // Logic based on the deposited ether
        eventLog.emitDepositEvent(msg.value);
    }
}

// EventLogContract.sol
pragma solidity ^0.8.0;

contract EventLogContract {
    event DepositMade(uint256 amount);

    function emitDepositEvent(uint256 amount) public {
        emit DepositMade(amount);
    }
}
```

Typically, users would send ether to the `DepositContract` using the `acceptEther` function. Based on the `msg.value`, the contract then calls `EventLogContract` to emit an event specifying the deposited ether amount. Off-chain systems, listening to these events, would then credit users on Layer 2, given the ether has been locked on Layer 1.

However, let's consider the scenario where a malicious smart contract uses DelegateCall to exploit this setup:

```
// MaliciousContract.sol
pragma solidity ^0.8.0;

contract MaliciousContract {
    DepositContract dc;

    constructor(address _dc) {
        dc = DepositContract(_dc);
    }

    function exploit() public payable {
        bytes4 methodId = bytes4(keccak256("acceptEther()"));
        (bool success,) = address(dc).delegatecall{value: msg.value}(abi.encodeWithSelector(methodId));
        require(success);
    }
}
```

Understanding the exploit:

1. The malicious actor deploys `MaliciousContract` providing the address of the `DepositContract`.
2. The actor then invokes the `exploit` function of the `MaliciousContract`, sending along some ether.
3. Inside the `exploit` function, a DelegateCall is made to `DepositContract's` `acceptEther` function. Given it's a DelegateCall, the `msg.value` remains the amount sent by the attacker, but the ether is not actually transferred to the `DepositContract`.
4. The logic of `acceptEther` is borrowed, and it misleadingly calls the `emitDepositEvent` of `EventLogContract` emitting an event that `msg.value` ether has been deposited.
5. Off-chain systems, which are programmed to credit users based on these events, might be tricked into crediting the malicious user on Layer 2 without any actual deposit on Layer 1.

Outcome: The vulnerability exposes the DelegateCall feature's potential misuse, especially when combined with `msg.value`. Custom precompiled contracts and the off-chain systems listening to their events must be designed with a deep understanding and caution against such manipulations.

{% hint style="info" %}
Any questions on the material so far? Ask Omar Inuwa:

[LinkedIn](https://www.linkedin.com/in/omar-inuwa/), [Twitter](https://twitter.com/OmarInuwa1)
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/tutorial-12-delegatecall-vulnerabilities-in-precompiled-contracts/potential-vulnerabilities-in-evm-implementations-overlooked-delegatecall-in-precompiled-contracts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
