本文介绍了智能合约之间的相互调用,并通过代码示例展示了如何实现合约间的通信,解释了 call
函数的使用、ABI编码、以及函数返回值的处理。
到目前为止,我们所做的一切都是直接调用智能合约。但智能合约之间也能够互相通信,这不仅是可能的,实际上也是可取的。
让我们来看一个简单的示例。
contract ExampleContract {
function askTheMeaningOfLife(address source)
public
returns (uint256) {
(bool ok, bytes memory result) = source.call(
abi.encodeWithSignature("meaningOfLifeAndAllExistence()")
);
require(ok, "call failed");
return abi.decode(result, (uint256));
}
}
contract AnotherContract {
function meaningOfLifeAndAllExistence()
public
pure
returns (uint256) {
return 42;
}
}
你可以通过以下方式查看它的实际效果。
因为我们已经回顾了元组、abi 编码和bytes memory,这里唯一令人惊讶的部分是call,以及askTheMeaningOfLife() 不是一个 view 函数。
为什么 askTheMeaningOfLife() 不是 view 函数?如果你尝试用 view 修饰符编译它,它将无法编译。
View 函数是只读的。当你调用任意智能合约的函数时,你无法知道它是否是只读的。因此,Solidity 不允许你将调用其他智能合约的函数指定为 view。
此外,尽管我们可以看到AnotherContract中的meaningOfLifeAndAllExistence返回了一个 uint256,但在一般情况下是无法知道的。它可能返回一个字符串。
函数总是返回 abi 编码的字节。Remix 如何知道将字符串格式化为字符串并将数字格式化为数字?在背后,它执行了我们在这里所做的abi.decode操作。
元组中的bool ok部分是什么?调用其他智能合约的函数可能会失败,例如如果函数 revert。为了知道外部调用是否 revert,返回了一个布尔值。在这个实现中,调用函数 askTheMeaningOfLifeAndAllExistence 也会 revert,但这并不是必须的。
这里有一个有趣的问题。如果你调用一个不存在的智能合约会发生什么?
尝试用 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db 作为参数调用 askTheMeaningOfLife(address source)。
不要偷懒,在上面的代码中试试看!
它会 revert,但这并不是因为地址不存在,而是因为你试图解码空数据。如果我们注释掉解码部分,那么当我们调用一个不存在的地址时,函数将不再 revert。
当你在 Remix 中打开交易下拉菜单时,你会看到 revert 的解释。
contract ExampleContract {
function askTheMeaningOfLife(address source)
public
returns (uint256) {
(bool ok, bytes memory result) = source.call(
abi.encodeWithSignature("meaningOfLifeAndAllExistence()")
);
require(ok, "call failed");
//return abi.decode(result, (uint256));
return 0;
}
}
如果另一个合约需要参数怎么办?以下是如何处理的代码。
contract ExampleContract {
function callAdd(address source, uint256 x, uint256 y)
public
returns (uint256) {
(bool ok, bytes memory result) = source.call(
abi.encodeWithSignature("add(uint256,uint256)", x, y)
);
require(ok, "call failed");
uint256 sum = abi.decode(result, (uint256));
return sum;
}
}
contract Calc {
function add(uint256 x, uint256 y)
public
returns (uint256) {
return x + y;
}
}
要注意不要在 "add(uint256,uint256)" 中加入空格。
准备好将其付诸实践了吗?
练习问题
查看 Solidity 训练营以了解更多关于智能合约开发和代币标准的内容。
- 原文链接: rareskills.io/learn-soli...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!