tl;dr: delegatecall runs in the context of the caller contract.
The difference between call and delegatecall in Solidity relates to the execution context:
target.call(funcData):- the function reads/modifies target contract's storage
 msg.senderis the caller contract
target.delegatecall(funcData)- the function reads/modifies caller contract's storage
 msg.senderis the original sender == caller contract'smsg.sender
![[Attachments/call.webp]]
![[Attachments/delegatecall.webp]]
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.24;
import "forge-std/Test.sol";
contract Target {
    address public owner;
    uint256 public value;
    function setOwnerAndValue(uint256 valueArg) public {
        owner = msg.sender;
        value = valueArg;
    }
}
contract Caller {
    address public owner;
    uint256 public value;
    function callSetOwnerAndValue(address target, uint256 valueArg) public {
        (bool success, ) = target.call(abi.encodeWithSignature("setOwnerAndValue(uint256)", valueArg));
        require(success, "call failed");
    }
    function delegatecallSetOwnerAndValue(address target, uint256 valueArg) public {
        (bool success, ) = target.delegatecall(abi.encodeWithSignature("setOwnerAndValue(uint256)", valueArg));
        require(success, "delegatecall failed");
    }
}
contract MyTest is Test {
    address sender = makeAddr("sender");
    Target target;
    Caller caller;
    function setUp() public {
        target = new Target();
        caller = new Caller();
        assertEq(target.owner(), address(0));
        assertEq(target.value(), 0);
        assertEq(caller.owner(), address(0));
        assertEq(caller.value(), 0);
    }
    function test_callSetOwnerAndValue() public {
        vm.prank(sender);
        caller.callSetOwnerAndValue(address(target), 100);
        // call modifies target contract's state, and target contract's msg.sender is caller contract
        assertEq(target.owner(), address(caller));
        assertEq(target.value(), 100);
        // caller contract's state didn't change
        assertEq(caller.owner(), address(0));
        assertEq(caller.value(), 0);
    }
    function test_delegatecallSetOwnerAndValue() public {
        vm.prank(sender);
        caller.delegatecallSetOwnerAndValue(address(target), 200);
        // target contract's state didn't change
        assertEq(target.owner(), address(0));
        assertEq(target.value(), 0);
        // delegatecall runs in the context of caller contract, so msg.sender is sender
        assertEq(caller.owner(), sender);
        assertEq(caller.value(), 200);
    }
}
ref:
https://medium.com/0xmantle/solidity-series-part-3-call-vs-delegatecall-8113b3c76855




