实例验证下call,delegatecall,两种方式下msg.sender和数据storage存储位置的区别

合约A

pragma solidity ^0.8.19;

contract A {
    address public temp1;
    uint256 public temp2;

    function three_call(address addr) public {
        (bool success, bytes memory result) = addr.call(
            abi.encodeWithSignature("test()")
        ); // 1
        require(success, "The call to B contract failed");
    }

    function three_delegatecall(address addr) public {
        (bool success, bytes memory result) = addr.delegatecall(
            abi.encodeWithSignature("test()")
        ); // 2
        require(success, "The delegatecall to B contract failed");
    }
}

合约B

pragma solidity ^0.8.19;

contract B {
    address public temp1;
    uint256 public temp2;

    function test() public  {
        temp1 = msg.sender;
        temp2 = 100;
    }
}

call 测试

B合约地址:0x086866663330344C7D1C51Bf19FF981AF3cB5782
A合约地址:0x05715D87C062B9685DD877d307b584bAbec964Ed
交易发起地址:0x6BC0E9C6a939f8f6d3413091738665aD1D7d2776

执行前数据

A B
temp1 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000
temp2 0 0

A合约执行three_call,参数为B合约地址
执行后数据

A B
temp1 0x0000000000000000000000000000000000000000 0x05715D87C062B9685DD877d307b584bAbec964Ed
temp2 0 100

delegatecall 测试

B合约地址:0x27153EDA2E085534811b040f6062f6528D6B80a1
A合约地址:0xd3C23F354Ca2160E6dC168564AB8954146cF35C9
交易发起地址:0x6BC0E9C6a939f8f6d3413091738665aD1D7d2776

执行前数据

A B
temp1 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000
temp2 0 0

A合约执行three_delegatecall,参数为B合约地址
执行后数据

A B
temp1 address: 0x6BC0E9C6a939f8f6d3413091738665aD1D7d2776 0x0000000000000000000000000000000000000000
temp2 100 0

总结

  • A发起地址->B合约call->C合约
    msg.sender为B合约地址,非原始A发起地址,数据保存在C合约中
  • A地址->B合约delegatecall->C合约
    msg.sender为A发起地址,数据保存在B合约中

注意

callcode 已经在solidity 0.5+废弃,被delegatecall取代,故不做分析测试

TypeError: "callcode" has been deprecated in favour of "delegatecall".

参考
https://hicoldcat.com/posts/web3/senior-track-5/