如何判断目标合约是否实现了某个方法
0x01 碰到的问题
比如下面的代码: 我们想从 store 合约里通过调用 getValue 方法来获取数据。但问题是,我们并不能确定 store 合约一定实现了 getValue 方法。很典型的一种情况是,我们需要将 StoreReader 不同的环境,不同的环境都有自己的 store 实现,一些比较老的 store 实例是没有 getValue 方法的。如果某个环境的 store 合约没有 getValue 实现,这个调用可能就会失败,并会导致其它相关联的业务操作失败。
contract StoreReader {
address store;
function readStoreValue() external view returns (uint256) {
return StoreInterface(store).getValue();
}
}
0x02 解决思路
-
升级 store 合约 研究发现, store 合约是不可升级的,升级 store 合约,因为着要对这个合约进行整体替换。因为 store 里面存储的还有其它各种状态变量,替换合约要把这些状态变量的值一个不差的迁移过去,还是有一定风险的。
- 不同的 StoreReader 实现 我们可以尝试不同的环境实现不同的 StoreReader, 用不同的方式来实现 readStoreValue 这个方法。但问题是其它合约对 StoreReader 也有静态依赖,有些合约是继承自 StoreReader 的,改一发而动全身。
-
staticcall 最终想起了 staticcall 调用,这种调用当发生调用失败时并不会把交椅 revert,而是返回 bool 类型的状态,这样我们就能动态判断目标合约 store 是否实现 getValue 方法了。 示例代码如下:
function readStoreValue() external view returns (uint256) { (bool success, bytes memory rtValue) = store.staticcall(abi.encodeWithSignature("getValue()")); if (success) { return (abi.decode(rtValue, (uint256))); } else { // return another value } }
需要注意的是,staticcall 返回的数据都是 bytes 类型,我们需要使用 abi.decode 对bytes 数据进行进一步的解析。
0x03 后记
为啥不用 ERC165? 如果是全新的设计,是可以考虑 ERC165 的,现在是想着对现有代码做最小程度的改动和最大程度的兼容。
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
上一篇:进阶篇-Trait(特性) 下一篇:进阶篇-泛型数据类型
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。