# Solidity: `call` vs `delegatecall`

By [frimoldi.eth](https://paragraph.com/@frimoldi) · 2022-01-17

---

I came across this topic while reading the phenomenal “Mastering Ethereum” and thought it was worth writing a small post about it.

From the book:

> Solidity offers some even more “low-level” functions for calling other contracts. These correspond directly to EVM opcodes of the same name and allow us to construct a contract-to-contract call manually.

These 2 functions are `call` and `delegatecall` and the main difference is that the latter doesn’t change the `msg` context at all.

Let’s see a quick example to illustrate this difference:

    pragma solidity ^0.8.10;
    
    contract Called {
      event callEvent(address sender, address origin, address from);
      function callMe() public {
        emit callEvent(msg.sender, tx.origin, address(this));
      }
    }
    
    contract Caller {
      function makeCalls(address _contractAddress) public {   address(_contractAddress).call(abi.encodeWithSignature("callMe()"));
      address(_contractAddress).delegatecall(abi.encodeWithSignature("callMe()"));
      }
    }
    

In the example above `Caller` interacts with `Called`’s `callMe` function in 2 different ways: one using `call`, another one using `delegatecall`.

`callMe` will emit a `callEvent` every time it’s called so we can inspect what the context (`msg`, `tx` and `this`) looks like in both scenarios.

In order to test this out, I created a simple script in [Hardhat](https://hardhat.org) to compile both contracts, perform the calls and inspect the events to see how they look:

    $> mkdir call_tests && cd call_tests
    $> npx hardhat
    

`scripts/makeCall.js` 👇🏽

      const hre = require('hardhat');
    
      const main = async () => {
        const LibraryFactory = await hre.ethers.getContractFactory('CalledLibrary');
        const library = await LibraryFactory.deploy();
        const CallerFactory = await hre.ethers.getContractFactory('Caller', {
          libraries: {
            CalledLibrary: library.address,
          },
        });
        const CalledFactory = await hre.ethers.getContractFactory('Called');
    
        const caller = await CallerFactory.deploy();
        const called = await CalledFactory.deploy();
    
        const tx = await caller.makeCalls(called.address);
        const res = await tx.wait();
    
        const eventAbi = [
          'event callEvent(address sender, address origin, address from)',
        ];
        const iface = new hre.ethers.utils.Interface(eventAbi);
    
        const signer = await hre.ethers.getSigner();
    
        console.log(`EOA address: ${signer.address}`);
        console.log(`Caller contract address: ${caller.address}`);
        console.log(`Called contract address: ${called.address}`);
    
        res.events.map(event => console.log(iface.parseLog(event)));
      };
    
      main();
    

The script above will deploy both `Caller` and `Called` contracts and then it will call `makeCalls` function from `Caller`.

After waiting for the transaction to be confirmed, it logs the events that were fired and 3 addresses: the account that sent the transaction, and the contracts’. This will allow us to inspect the context of each call.

To run the script:

    $> npx hardhat run scripts/makeCalls.js
    

which will print something like this (I trimmed the output and addresses to make it more readable):

    EOA address: 0xf39F...2266
    Caller contract address: 0xe7f1...512
    Called contract address: 0x9fE4...6e0
    
    LogDescription {
      ...,
      args: [
        ...,
        sender: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512',
        origin: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
        from: '0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0'
      ]
    }
    LogDescription {
      ...,
      args: [
        '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
        '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
        '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512',
        sender: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
        origin: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
        from: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512'
      ]
    }
    

Ok, let’s see what happened.

Both event logs. displayed above were fired from the same contract, `Called`. BUT, as you can see, the context is quite different.

The first one was fired after `Caller` contract executed `Called`’s `callMe()` function, by using `call` .

In this case:

1.  `sender` is the `Caller` contract.
    
2.  `origin` is the account who sent the transaction to execute `Caller.makeCalls`.
    
3.  `from` is the `Called` contract.
    

This is all what you might be expecting. The origin is always the EOA, `msg.sender` is the address from where a particular function is being called, and `this` (`from`, in the logs) is the contract you’re referring too.

Let’s see how the other event looks like, then:

1.  `sender` is the EOA!
    
2.  `origin` is also the EOA!
    
3.  `from` is the `Caller` contract, instead of `Called` (the contract which is actually emitting the event).
    

What happened?

What happened is that when you call another contract’s function using `delegatecall` it actually inherits the execution context of the contract who is performing the call, in this case `Caller`.

The context will behave as if you’ve copied and pasted the `callMe()` function into `Caller`’s contract.

Conclusion
----------

*   `call` and `delegatecall` call are flexible but also dangerous ways of interacting with other contracts, we must use them with caution. They’re both “blind” calls into a function and they can expose your contract to security risks.
    
*   the main difference between them is that while `call` just executes the function **in the context of the contract it was defined**, `delegatecall` inherits the execution context, meaning that the function will behave as it was defined in the contract that’s using `delegatecall`.

---

*Originally published on [frimoldi.eth](https://paragraph.com/@frimoldi/solidity-call-vs-delegatecall)*
