Cover photo

调用其他合约

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

我们先写一个简单的合约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的值。

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

下面我们介绍4个调用合约的例子,在remix中编译合约后,分别部署OtherContractCallContract

post image
post image
post image

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

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

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

post image
post image

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

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

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

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

post image

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

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

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

post image

如果目标合约的函数是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

post image

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

post image