Preventing unwanted delegate call
Tags: solidity, ethereum, beginners, web3
Published: 2022-01-01 04:46:27

## Sources

[DelegateCall: Calling Another Contract Function in Solidity](https://medium.com/coinmonks/delegatecall-calling-another-contract-function-in-solidity-b579f804178c)

[Difference between CALL, CALLCODE and DELEGATECALL](https://ethereum.stackexchange.com/questions/3667/difference-between-call-callcode-and-delegatecall)

[Solidity call() and delegateCall()](https://ethereum.stackexchange.com/questions/103830/solidity-call-and-delegatecall)

[How to prevent the code of my contract being used in a CALLCODE?](https://ethereum.stackexchange.com/questions/69551/how-to-prevent-the-code-of-my-contract-being-used-in-a-callcode)

---

## Overview

When `delegatecall` used in caller contract to target contract,

- target contract executes its logic
- context(storage) is on caller contract

![Overview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wm0glt8z3ptw99zhivz8.png)
 

As EVM saves filed variable to storage in a slot order, if we use `delegatecall` , we should set the order of variables in same order.

![Variable orders matter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57o9ranqkzf6cu25ynte.png)
 

---

## Preventing unwanted Delegate call

> This method is from [Uniswap v3’s NoDelegateCall.sol](https://github.com/Uniswap/v3-core/blob/main/contracts/NoDelegateCall.sol).
> 

The core is to compare between the original address of contract(`originalAdress`) and new address that executes `delegatecall` (`newAdress`).

### 1. How it works

```solidity
pragma solidity >0.8.0;

contract Receiver {
    string greeting = "Hello";
    address private immutable originalAdress;
    event Greeting(string greeting, address originalAdress, address newAddress);

    constructor() {
        // Immutables are computed in the init code of the contract, and then inlined into the deployed bytecode.
        // In other words, this variable won't change when it's checked at runtime.
        originalAdress = address(this);
    }  
    function greet() external  {
        address newAddress = address(this);
        emit Greeting(greeting, originalAdress, newAddress);
    }
}

contract Sender {
    string greeting = "Hi";
    
    function delegatedGreeting(address _contract) external {
        (bool success,) = _contract.delegatecall(
            abi.encodeWithSignature("greet()")
        );
    }
    
    function callGreeting(address _contract) external {
        (bool success,) = _contract.call(
            abi.encodeWithSignature("greet()")
        );
    }
}
```

- `Sender` contract address : 0xaE036c65C649172b43ef7156b009c6221B596B8b
- `Reciever` contract address : 0xcD6a42782d230D7c13A74ddec5dD140e55499Df9

### `origianalAddress`

This variable is initialized in constructor of `Reciever` contract and fixed to `Reciever` contract address whether `Sender` executes `call` or `delegatecall`. It cannot be modified because of `immutable` keyword. 

### `newAddress`

This variable is assigned to `address(this)` inside the function `greet` . As `address(this)` refers the contract which the function is executing, it’s value varies when it’s triggered by `call` and `delegatecall` . 

- `call`
    
    Using `call` function, the contract that is executed is `Reciever` . So, `newAddress` is same to `orginalAddress` . 
    
- `delegatecall`
    
    But, using `delegatecall`, the contract that is actually executed is `Sender` . So, `newAddress` stores the value of `Sender` contract address, which is different to `originalAddress`.
    

### 2. 50% Success(revert issue)

```solidity
pragma solidity >0.8.0;

contract Receiver {
    string greeting = "Hello";
    address private immutable original;
    event Greeting(string greeting, address original, address addressThis);

    constructor() {
        // Immutables are computed in the init code of the contract, and then inlined into the deployed bytecode.
        // In other words, this variable won't change when it's checked at runtime.
        original = address(this);
    }

    /// @dev Private method is used instead of inlining into modifier because modifiers are copied into each method,
    ///     and the use of immutable means the address bytes are copied in every place the modifier is used.
    function checkNotDelegateCall() private view {
        require(address(this) == original);
    }

    /// @notice Prevents delegatecall into the modified method
    modifier noDelegateCall() {
        checkNotDelegateCall();
        _;
    }
    
    function greet() external noDelegateCall {
        emit Greeting(greeting, original, address(this));
    }
}

contract Sender {
    string greeting = "Hi";
    
    function delegatedGreeting(address _contract) external {
        (bool success,) = _contract.delegatecall(
            abi.encodeWithSignature("greet()")
        );
    }
    
    function callGreeting(address _contract) external {
        (bool success,) = _contract.call(
            abi.encodeWithSignature("greet()")
        );
    }
}
```

![Empty event](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uv11y28vsmbll852vwrh.png)
 

I implemented `noDelegateCall` modifier to check the difference between `original` variable and `address(this)`  inside function `greet` . The problem was that although the emitted event was empty, `delegatecall` wasn’t reverted. So I tried to make it revert...

### 3. Why doesn’t `delegatedcall` revert?

[solidity delegatecall prevention doesn't works](https://stackoverflow.com/questions/70531091/solidity-delegatecall-prevention-doesnt-works/70531436#70531436)

> When low-level `delegatecall` reverts, it doesn’t automatically revert main transaction. Instead It returns `false` as the first return value.
> 

So, to make `delegatecall` revert, we should check if the first return value `success` is true. 

```solidity
function delegatedGreeting(address _contract) external {
	(bool success,) = _contract.delegatecall(
		abi.encodeWithSignature("greet()")
	);
	require(success == true, "delegatecall failed");
}
```

### 4. 100% Success

```solidity
pragma solidity >0.8.0;

contract Receiver {
    string greeting = "Hello";
    address private immutable original;
    event Greeting(string greeting, address original, address addressThis);

    constructor() {
        // Immutables are computed in the init code of the contract, and then inlined into the deployed bytecode.
        // In other words, this variable won't change when it's checked at runtime.
        original = address(this);
    }

    /// @dev Private method is used instead of inlining into modifier because modifiers are copied into each method,
    ///     and the use of immutable means the address bytes are copied in every place the modifier is used.
    function checkNotDelegateCall() private view {
        require(address(this) == original);
    }

    /// @notice Prevents delegatecall into the modified method
    modifier noDelegateCall() {
        checkNotDelegateCall();
        _;
    }
    
    function greet() external noDelegateCall {
        emit Greeting(greeting, original, address(this));
    }
}

contract Sender {
    string greeting = "Hi";
    
    function delegatedGreeting(address _contract) external {
        (bool success,) = _contract.delegatecall(
            abi.encodeWithSignature("greet()")
        );
        require(success == true, "Delegation failed!");
    }
    
    function callGreeting(address _contract) external {
        (bool success,) = _contract.call(
            abi.encodeWithSignature("greet()")
        );
        require(success == true, "Call failed!");
    }
}
```