solidity进阶第三课——Call

call是address类型的低级成员函数,它用来与其他合约交互。它的返回值为(boll,data),分别对应call是否成功以及目标函数的返回值。

1.call是solidity官方推荐通过触发fallback或receive函数发送ETH的方法。

2.当我们不知道对方合约源代码或ABI,就没法生成合约变量;这是我们可以通过call调用对方合约的函数

call的使用格式:

目标合约地址.call(二进制编码);
abi.encodeWithSignature("函数签名", 逗号分隔的具体参数)

函数签名为“函数名(逗号分隔的参数类型)”。例如

abi.encodeWithSignature("f(uint256,address)", _x, _addr)

另外call在调用合约时可以指定交易发送的ETH数额和gas

目标合约地址.call{value:发送数额, gas:gas数额}(二进制编码);

从代码来看:

contract OtherContract {
    uint256 private _x = 0; // 状态变量x
    // 收到eth的事件,记录amount和gas
    event Log(uint amount, uint gas);
    
    fallback() external payable{}

    // 返回合约ETH余额
    function getBalance() view public returns(uint) {
        return address(this).balance;
    }

    // 可以调整状态变量_x的函数,并且可以往合约转ETH (payable)
    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,一个在收到ETH时触发的事件Log,三个函数:

getBalance():返回合约ETH余额

setX():external payable函数,可以设置x的值,并向合约发送ETH

getX():读取x的值

利用call调用目标函数

1.Response事件:利用call合约调用目标合约函数。要定义Response事件,输出call返回success和data,可以方便我们返回值。

event Response(bool success, bytes data);

2.调用setX函数

我们定义callSetX函数来调用目标合约的setX(),转入msg.value数额的ETH,并释放Response事件输出successdata

function callSetX(address payable _addr, uint256 x) public payable {// call setX(),同时可以发送ETH
    (bool success, bytes memory data) = _addr.call{value: msg.value}(
        abi.encodeWithSignature("setX(uint256)", x)
    );

    emit Response(success, data); //释放事件
}

接下来我们调用callSetX把状态变量_x改为5,参数为OtherContract地址和5,由于目标函数setX()没有返回值,因此Response事件输出的data0x,也就是空。

3.调用getX函数

下面我们调用getX()函数,它将返回目标合约_x的值,类型为uint256。我们可以利用abi.decode来解码call的返回值data,并读出数值。

function callGetX(address _addr) external returns(uint256){// call getX()
    (bool success, bytes memory data) = _addr.call(
        abi.encodeWithSignature("getX()")
    );

    emit Response(success, data); //释放事件
    return abi.decode(data, (uint256));
}

经过abi.decode,最终返回值为5。

4.调用不纯在的函数

function callNonExist(address _addr) external{ // call getX()
    (bool success, bytes memory data) = _addr.call(
        abi.encodeWithSignature("foo(uint256)")
    );

    emit Response(success, data); //释放事件
}

我们call了不存在的foo函数。call仍能执行成功,并返回success,但其实调用的目标合约fallback函数。

猜你喜欢

转载自blog.csdn.net/qq_52708261/article/details/127115014