Solidity极简入门|第二十二讲:Call

22-08-24 10:00
阅读本文需 8 分钟
总结 AI 总结
看总结 收起
原文标题:《 Solidity 极简入门: 22. Call 》
原文作者:0xAA     


我最近在重新学 solidity,巩固一下细节,也写一个「Solidity 极简入门」,供小白们使用(编程大佬可以另找教程),每周更新 1-3 讲。


所有代码和教程开源在 github: github.com/AmazingAng/WTFSolidity


我们曾在第 17 讲:发送 ETH那一讲介绍过利用 call 来发送 ETH,这一讲我们将介绍如何利用它调用合约。


Call


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


call 是 solidity 官方推荐的通过触发 fallback 或 receive 函数发送 ETH 的方法。不推荐用 call 来调用另一个合约,因为当你调用不安全合约的函数时,你就把主动权交给了它。推荐的方法仍是声明合约变量后调用函数,见第 19 讲:调用其他合约。当我们不知道对方合约的源代码或 ABI,就没法生成合约变量;这时,我们仍可以通过 call 调用对方合约的函数。


call 的使用规则


call 的使用规则如下:



其中二进制编码利用结构化编码函数 abi.encodeWithSignature 获得:



函数签名为"函数名(逗号分隔的参数类型)"。例如 abi.encodeWithSignature("f(uint256,address)", _x, _addr)。


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



看起来有点复杂,下面我们举个 call 应用的例子。


目标合约


我们先写一个简单的目标合约 OtherContract 并部署,代码与第 19 讲中基本相同,只是多了 fallback 函数。



这个合约包含一个状态变量 x,一个事件 Log 在收到 ETH 时触发,三个函数:


getBalance(): 返回合约 ETH 余额。setX(): external payable 函数,可以设置 x 的值,并向合约发送 ETH。getX(): 读取 x 的值。


利用 call 调用目标合约


1. Response 事件


我们写一个 Call 合约来调用目标合约函数。首先先写一个定义 Response 事件,输出 call 返回的 success 和 data,方便我们观察返回值。



2. 调用 setX 函数


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



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


3. 调用 getX 函数


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



从 Response 事件的输出,我们可以看到 data 为 0x0000000000000000000000000000000000000000000000000000000000000005。而经过 abi.decode,最终返回值为 5。


4. 调用不存在的函数


如果我们给 call 输入的函数不存在于目标合约,那么目标合约的 fallback 函数会被触发。



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


总结


这一讲,我们介绍了如何用 call 这一低级函数来调用其他合约。call 不是调用合约的推荐方法,因为不安全。但他能让我们在不知道源代码和 ABI 的情况下调用目标合约,很有用。


原文链接
举报 纠错/举报
选择文库
新增文库
取消
完成
新增文库
仅自己可见
公开
保存
纠错/举报
提交