# 调用其他合约

By [startha](https://paragraph.com/@starha) · 2023-10-12

---

[调用已部署合约](https://github.com/starthapro/starha_solidity/blob/main/20_CallContract/readme.md#%E8%B0%83%E7%94%A8%E5%B7%B2%E9%83%A8%E7%BD%B2%E5%90%88%E7%BA%A6)
------------------------------------------------------------------------------------------------------------------------------------------------------------

在solidity中，一个合约可以调用另一个合约的函数，这在构建赋值的DApp时非常有用。本教程将会介绍如何在已知合约代码（或接口）和地址的情况下，调用已部署的合约。

[目标合约](https://github.com/starthapro/starha_solidity/blob/main/20_CallContract/readme.md#%E7%9B%AE%E6%A0%87%E5%90%88%E7%BA%A6)
------------------------------------------------------------------------------------------------------------------------------

我们先写一个简单的合约`OtherContract`，用于被其他合约调用。

        contract OtherContract {
    
            uint private _x = 0; //状态变量x
    
            //收到eth事件，记录amount和gas
            event Log(uint amount, uint gas); 
    
            //返回合约eth余额
            function getBalance() public view returns(uint) {
                return address(this).balance;
            }
    
            //可以调佣状态变量_x的函数，并且可以网合约转eth
            function setX(uint256 x) external payable {
                _x =  x;
                //如果转入eth，则释放Log事件
                if(msg. value > 0) {
                    emit Log(msg.value,gasleft());
                }
            }
    
            //读取x
            function getX() external view returns(uint x) {
                x = _x;
            }
        }
    

这个合约包括一个状态变量`_x`，一个事件`Log`在收到ETH时触发，三个函数：

*   `getBalance()`：返回合约ETH余额。
    
*   `setX()`：设置`x`的值，并向合约发送ETH。
    
*   `get()`：读取`_x`的值。
    

[调用OtherContract合约](https://github.com/starthapro/starha_solidity/blob/main/20_CallContract/readme.md#%E8%B0%83%E7%94%A8othercontract%E5%90%88%E7%BA%A6)
--------------------------------------------------------------------------------------------------------------------------------------------------------

我们可以利用合约地址和合约代码（或接口）来创建合约引用：`_Name(_Address)`，其中`_Name`是合约名，应与合约代码或接口中标注的合约名保持一直，`_Address`是合约地址。然后用合约的引用来调用函数：`_Name(_Address).f()`，其中`f()`是要调用的函数。

下面我们介绍4个调用合约的例子，在remix中编译合约后，分别部署`OtherContract`和`CallContract`：

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

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

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

### [1\. 传入合约地址](https://github.com/starthapro/starha_solidity/blob/main/20_CallContract/readme.md#1-%E4%BC%A0%E5%85%A5%E5%90%88%E7%BA%A6%E5%9C%B0%E5%9D%80)

我们可以做函数里传入目标合约地址，生成目标合约的引用，然后调用目标函数。以调用`OtherContract`合约的`setX`函数为例，我们在新合约中写一个`callSetX`函数，传入已部署好的`OtherContract`合约地址`_Address`和`setX`的参数。

        function callSetX(address _address, uint256 x) external {
            OtherContract(_address).setX(x);
        }
    

赋值`OtherContract`合约的地址，填入`callSetX`函数的参数中，成功调用后，调用`OtherContract`合约中的`getX`验证`x`变为123。

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

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

### 2\. [传入合约变量](https://github.com/starthapro/starha_solidity/blob/main/20_CallContract/readme.md#%E4%BC%A0%E5%85%A5%E5%90%88%E7%BA%A6%E5%8F%98%E9%87%8F)

我们可以直接在函数里传入合约的引用，只需要把上面参数的`address`类型改为目标合约名，比如`OtherContract`。下面例子实现了调用目标合约的`getX()`函数。

**注意**该函数参数`OtherContract _Address`底层类型仍然是`address`，生成`ABI`中，调用`callGetX`时传入的参数都是`address`类型

        function callGetX(OtherContract _address) external view returns(uint x) {
            x = _address.getX();
        }
    

赋值`OtherContract`合约的地址，填入`callGetX`函数的参数中，调用后成功获取`x`的值

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

### [3\. 创建合约变量](https://github.com/starthapro/starha_solidity/blob/main/20_CallContract/readme.md#3-%E5%88%9B%E5%BB%BA%E5%90%88%E7%BA%A6%E5%8F%98%E9%87%8F)

我们可以创建合约变量，然后通过它来调用目标函数。下面例子，我们给变量`oc`存储了`OtherContract`合约的引用：

        function callGetX2(address _address) external view returns(uint x){
            OtherContract oc = OtherContract(_address);
            x = oc.getX();
        }
    

复制`OtherContract`合约的地址，填入`callGetX2`函数的参数中，调用后成功获取`x`的值

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

### [4\. 调用合约并发送](https://github.com/starthapro/starha_solidity/blob/main/20_CallContract/readme.md#4-%E8%B0%83%E7%94%A8%E5%90%88%E7%BA%A6%E5%B9%B6%E5%8F%91%E9%80%81eth)`ETH`

如果目标合约的函数是`payable`的，那么我们可以通过调用它来给合约转账：`_Name(_Address).f{value: _Value}()`，其中`_Name`是合约名，`_Address`是合约地址，`f`是目标函数名，`_Value`是要转的`ETH`数额（以`wei`为单位）。

`OtherContract`合约的`setX`函数是`payable`的，在下面这个例子中我们通过调用`setX`来往目标合约转账。

        function setXTransferETH(address otherContract, uint256 x) payable external{
            OtherContract(otherContract).setX{value: msg.value}(x);
        }
    

复制`OtherContract`合约的地址，填入`setXTransferETH`函数的参数中，并转入2ETH

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

转账后，我们可以通过`Log`事件和`getBalance()`函数观察目标合约`ETH`余额的变化。

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

---

*Originally published on [startha](https://paragraph.com/@starha/t7qzXaBiuLpo41TaK89H)*
