# Understanding Delegatecall

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

Solidity, Ethereum's smart contract programming language, provides several low-level functions to interact with other contracts. One of the most powerful, yet potentially confusing, is the `delegatecall`. This article breaks down the intricacies of `delegatecall`, illustrating how it works and the use-cases and potential pitfalls associated with it.

### What is `delegatecall`?

At its core, `delegatecall` is a type of function call in Solidity that invokes a method in another contract without changing the context of the call. Specifically, it calls a function from another contract using the storage of the calling contract. This means that while the code of the called contract is executed, all storage writes, reads, and state changes will apply to the calling contract.

While the concept of `delegatecall` might seem abstract, a hands-on example can make it clearer.

**Example:**

Imagine two contracts, `StorageContract` and `LogicContract`.

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

contract StorageContract {
    uint256 public data;

    function setData(uint256 _data) public {
        data = _data;
    }

    function executeLogic(address logicAddress, bytes memory _data) public {
        (bool success,) = logicAddress.delegatecall(_data);
        require(success);
    }
}

// LogicContract.sol
pragma solidity ^0.8.0;

contract LogicContract {
    function increaseData() public {
        StorageContract sc = StorageContract(msg.sender);
        uint256 currentData = sc.data();
        sc.setData(currentData + 1);
    }
}
```

Here, `StorageContract` has a state variable `data` and a method to set that data. It also has an `executeLogic` method that uses `delegatecall` to execute some logic contained in another contract, which we intend to be `LogicContract`.

`LogicContract` has a method `increaseData` that reads the current data from `StorageContract` and increments it by one.

When you call the `executeLogic` method of `StorageContract` with the address of `LogicContract` and the call data for `increaseData`, here's what happens:

1. `LogicContract`'s `increaseData` method is invoked via `delegatecall`.
2. Inside `increaseData`, the `msg.sender` remains the address of `StorageContract`. This is crucial. It doesn't change to the address of `LogicContract`.
3. The `increaseData` method fetches the current data from `StorageContract`, increments it, and writes it back to `StorageContract`.

From the outside, it appears as though `StorageContract` simply increased its `data` variable. But in reality, the logic to do so came from `LogicContract`, all thanks to the `delegatecall` functionality.

This separation allows for modular design. If, in the future, you wanted to change the way data is increased (maybe by doubling it instead of incrementing), you could deploy a new logic contract and point the `StorageContract` to use that for its logic, without affecting the actual data stored.

This example visually demonstrates the power and flexibility of `delegatecall` and how, when used correctly, it can allow for dynamic interactions between contracts.

**Extended Example**:

Consider three contracts - `PrimaryContract`, `IntermediateContract`, and `FinalContract`.

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

contract PrimaryContract {
    function triggerChain() public {
        IntermediateContract ic = new IntermediateContract();
        ic.triggerLogic();
    }
}

// IntermediateContract.sol
pragma solidity ^0.8.0;

contract IntermediateContract {
    function triggerLogic() public {
        FinalContract fc = new FinalContract();
        fc.emitEvent();
    }
}

// FinalContract.sol
pragma solidity ^0.8.0;

contract FinalContract {
    event SenderEvent(address sender);

    function emitEvent() public {
        emit SenderEvent(msg.sender);
    }
}
```

**Chain of Actions**:

1. **Initial Call**: Bob's EOA (Externally Owned Account) calls the `triggerChain` function of `PrimaryContract`.
2. **DelegateCall in PrimaryContract**: Inside the `triggerChain` function of `PrimaryContract`, there's a DELEGATECALL to the `triggerLogic` function of `IntermediateContract`. Remember, with DELEGATECALL, the code of `triggerLogic` in `IntermediateContract` executes within the context of `PrimaryContract`. So, `msg.sender` remains Bob's EOA.
3. **Regular Call in IntermediateContract's triggerLogic Function**: The `triggerLogic` function in `IntermediateContract` performs a regular call to the `emitEvent` function of `FinalContract`.
4. **Event Emission in FinalContract**: The `emitEvent` function in `FinalContract` emits an event. Given that the `triggerLogic` function from `IntermediateContract` was invoked via DELEGATECALL from `PrimaryContract`, `msg.sender` stays as Bob's EOA. Therefore, when the `emitEvent` function in `FinalContract` is called, `msg.sender` remains Bob's EOA. As a result, the `SenderEvent` emitted in `FinalContract` will capture Bob's EOA as the sender.

**Outcome**: `FinalContract` emits an event with Bob's EOA address as the published data, even though the logic ran across multiple contracts.

Incorporating this example provides a real-world scenario to further understand the behavior of `delegatecall` and its implications on `msg.sender`.

### How does delegatecall differ from other calls?

Solidity provides various inter-contract function call mechanisms, each serving different purposes:

1. **Regular Calls (`this.f()`, `B.f()`):** Executes function `f` in contract `B`. Any state changes happen within contract `B`.
2. **`call`:** A low-level call mechanism where you have more granular control over data sent and gas provided. State changes occur in the called contract.
3. **`delegatecall`:** Executes the code of another contract, but storage writes/reads are made in the calling contract's context.
4. **`staticcall`:** Similar to `delegatecall`, but cannot change state (read-only).

The primary distinction of `delegatecall` is the fact that it allows for the code in another contract to be executed in the context of the calling contract's storage.

### Use-cases for `delegatecall`

1. **Upgradable Contracts:** A common use case is creating upgradable smart contracts. The contract logic (code) is separated from the data storage. When the logic needs to be updated, a new contract is deployed, and the original contract uses `delegatecall` to invoke the new logic while retaining the original storage.
2. **Libraries:** Instead of duplicating code across multiple contracts, functions can be stored in a library and invoked using `delegatecall`, saving gas.

### Pitfalls and Dangers

1. **Storage Layout Mismatch:** The biggest risk of using `delegatecall` is a storage collision. Since the called contract uses the storage layout of the calling contract, a mismatch can result in unintended overwrites.
2. **Unintended Side Effects:** A called contract might not be aware of the state variables and structures of the calling contract, leading to unintended side effects.
3. **Increased Attack Surface:** `delegatecall` increases the attack surface of a contract since bugs or vulnerabilities in the called contract can affect the calling contract.
4. **Precompiled Contract Vulnerabilities:** If the delegatecall interacts with precompiled contracts, certain vulnerabilities specific to those precompiled contracts can be exploited.

### Best Practices

1. **Storage Consistency:** Ensure that the storage layout of both contracts is consistent. When updating contracts, always append new state variables; don't change the order of existing ones.
2. **Clear Documentation:** Document the contracts and their interactions meticulously.
3. **Thorough Testing:** Extensively test all interactions, especially when using `delegatecall`.
4. **Avoid Complexity:** If possible, avoid making things overly complicated. The more complex the interactions, the higher the chance for errors.

### Conclusion

`delegatecall` is a powerful feature in Solidity, enabling dynamic contract interactions and upgradability. However, its power comes with increased responsibility. Developers must ensure they understand its workings deeply and employ rigorous testing and security practices to prevent potential pitfalls.

{% 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/understanding-delegatecall.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.
