Contracts can interact in three ways

  1. Call : By directly calling from a contract through a function which will not set the caller's value but sets the callee's value. And sender in this will be the caller only

  2. CallCode : When called through CallCode caller calls the function of the callee and sents its own value (or alter its own value with the called parameters ) but no changes are reflected to the callee's storage. Here also sender is the Caller itself.

  3. DelegateCall : When a third contract calls a delegate call to some function in callee on behalf of the caller and storage changes are made in the caller's value and nothing is reflected in callee's storage .

    Here the sender is no more the caller but the third contract Call Helper

pragma solidity ^0.4.0;

contract Caller {
uint public value;
address public sender;

function callSetValue(address _callee, uint _value) {
    _callee.call(bytes4(sha3("setValue(uint256)")), _value); // Callee's storage is set as given , Caller's is not modified
}

function callcodeSetValue(address _callee, uint _value) {
    _callee.callcode(bytes4(sha3("setValue(uint256)")), _value); // Caller's storage is set, Calee is not modified
}

function delegatecallSetValue(address _callee, uint _value) {
    _callee.delegatecall(bytes4(sha3("setValue(uint256)")), _value); // Caller's storage is set, Callee is not modified
}
}

contract Callee {
uint public value;
address public sender;

function setValue(uint _value) {
    value = _value;
    sender = msg.sender;
    // msg.sender is Caller if invoked by Caller's callcodeSetValue. None of Callee's storage is updated
    // msg.sender is OnlyCaller if invoked by onlyCaller.justCall(). None of Callee's storage is updated

    // the value of "this" is Caller, when invoked by either Caller's callcodeSetValue or CallHelper.justCall()
}
}

contract CallHelper {
    function justCall(Caller _caller, Callee _callee, uint _value) {
        _caller.delegatecallSetValue(_callee, _value);
    }
}

DELEGATECALL basically says that I'm a contract and I'm allowing (delegating) you to do whatever you want to my storageDELEGATECALL is a security risk for the sending contract which needs to trust that the receiving contract will treat the storage well.

DELEGATECALL was a new opcode that was a bug fix for CALLCODE which did not preserve msg.sender and msg.value. If Alice invokes Bob who does DELEGATECALL to Charlie, the msg.sender in the DELEGATECALL is Alice (whereas if CALLCODE was used the msg.sender would be Bob).

Details

When D does CALL on E, the code runs in the context of E: the storage of E is used.

When D does CALLCODE on E, the code runs in the context of D. So imagine that the code of E is in D. Whenever the code writes to storage, it writes to the storage of account D, instead of E.

contract D {
  uint public n;
  address public sender;

  function callSetN(address _e, uint _n) {
    _e.call(bytes4(sha3("setN(uint256)")), _n); // E's storage is set, D is not modified
  }

  function callcodeSetN(address _e, uint _n) {
    _e.callcode(bytes4(sha3("setN(uint256)")), _n); // D's storage is set, E is not modified
  }

  function delegatecallSetN(address _e, uint _n) {
    _e.delegatecall(bytes4(sha3("setN(uint256)")), _n); // D's storage is set, E is not modified
  }
}

contract E {
  uint public n;
  address public sender;

  function setN(uint _n) {
    n = _n;
    sender = msg.sender;
    // msg.sender is D if invoked by D's callcodeSetN. None of E's storage is updated
    // msg.sender is C if invoked by C.foo(). None of E's storage is updated

    // the value of "this" is D, when invoked by either D's callcodeSetN or C.foo()
  }
}

contract C {
    function foo(D _d, E _e, uint _n) {
        _d.delegatecallSetN(_e, _n);
    }
}

When D does CALLCODE on E, msg.sender inside E is D as commented in the code above.

When an account C invokes D, and D does DELEGATECALL on E, msg.sender inside E is C. That is, E has the same msg.sender and msg.value as D.