如何判断目标合约是否实现了某个方法

  • Ashton
  • 更新于 2023-03-02 20:19
  • 阅读 1801

0x01碰到的问题比如下面的代码:我们想从store合约里通过调用getValue方法来获取数据。但问题是,我们并不能确定store合约一定实现了getValue方法。很典型的一种情况是,我们需要将StoreReader不同的环境,不同的环境都有自己的store实现,一

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 解决思路

  1. 升级 store 合约 研究发现, store 合约是不可升级的,升级 store 合约,因为着要对这个合约进行整体替换。因为 store 里面存储的还有其它各种状态变量,替换合约要把这些状态变量的值一个不差的迁移过去,还是有一定风险的。

    1. 不同的 StoreReader 实现 我们可以尝试不同的环境实现不同的 StoreReader, 用不同的方式来实现 readStoreValue 这个方法。但问题是其它合约对 StoreReader 也有静态依赖,有些合约是继承自 StoreReader 的,改一发而动全身。
  2. 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 的,现在是想着对现有代码做最小程度的改动和最大程度的兼容。

点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Ashton
Ashton
0x53b3...c54F
专注于 EVM 和比特币生态的区块链开发者