# 合约四种 call 区别

By [NO ONE](https://paragraph.com/@no-one) · 2022-09-29

---

`CALL|CALLCODE|DELEGATECALL|STATICCALL`

四种调用的区别

CALL & STATICCALL
-----------------

CALL 调用的上下文环境是被调用合约的环境，修改的是被调用合约的 state，调用者函数不能为 view。

![CALL ContractB](https://storage.googleapis.com/papyrus_images/5b64bbfe8f579f38efffb5201ee6c5293609c22f5aa7621c351cf215840bf269.png)

CALL ContractB

STATICCALL 只能调用不修改 state 的函数（pure view 修饰的函数），调用者函数可以为 view。

![STATICCALL ContractB](https://storage.googleapis.com/papyrus_images/b8ae06593cc5664c15dae332fc7adab13be9ce1f5ce3ca9d0347034b8eeffee3.png)

STATICCALL ContractB

    // SPDX-License-Identifier: GPL-3.0
    
    pragma solidity ^0.8.0;
    
    // 调用者
    contract ContractA {
    
        uint256 x;
    
        function add(uint256 _num) public {
            x = x + _num;
        }
    
        function getX() external view returns(uint256) {
            return x;
        }
    
    }
    
    // 被调用者
    contract ContractB {
    
        function call(address _addr, uint256 _num) external {
            bytes memory data = abi.encodeWithSignature("add(uint256)", _num);
            (bool result, ) = _addr.call(data);
            require(result, "transaction failed");
        }
    
        function staticcall(address _addr) external view returns(uint256) {
            bytes memory data = abi.encodeWithSignature("getX()");
            (bool result, bytes memory returnNum) = _addr.staticcall(data);
            require(result, "transaction failed");
            return abi.decode(returnNum, (uint256));
        }
    
    }
    

CALLCODE & DELEGATECALL
-----------------------

`CALLCODE`已被`DELEGATECALL`取代，区别就是 `msg.sender`不同。`DELEGATECALL`会一直使用原始调用者的地址，而`CALLCODE`不会。

![](https://storage.googleapis.com/papyrus_images/b8bea25db4e151a259c6b20d9bda974c4e091e113432f2af85ec42ad2ae50ee2.png)

委托调用的上下文环境是调用者合约的环境，也就是说`msg.sender`是用户。通常用在可升级的代理合约中。

---

*Originally published on [NO ONE](https://paragraph.com/@no-one/call)*
