You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过其他合约调用EIP-2535的diamondCut?移除函数时调用失败

问题排查与解决方案

核心问题:错误使用delegatecall

你的代码用delegatecall调用钻石合约的diamondCut,但delegatecall的执行上下文是当前合约(ExecuteDiamondCuts),而非目标钻石合约:

  • 钻石合约的diamondCut通常会校验调用者权限(比如是否为合约owner),但delegatecall会让这个校验针对ExecuteDiamondCuts的存储,而非钻石合约的,直接触发权限验证失败。
  • 即便权限没问题,delegatecall会尝试在当前合约的存储中执行钻石合约逻辑,破坏存储结构,必然导致回滚。

修复方式:将delegatecall替换为普通call,同时修正abi.encodeWithSignature中的结构体类型声明(需完整写出FacetCut的结构体类型):

(bool success,) = CONTRACT_ADDRESS.call(
    abi.encodeWithSignature(
        "diamondCut((address,uint8,bytes4[])[],address,bytes)", 
        _facetCuts,
        address(0),
        ""
    )
);
require(success, "Diamond cut failed");

其他潜在问题点

  1. 权限验证:确保ExecuteDiamondCuts合约已被钻石合约授权调用diamondCut(比如由钻石owner给它授权,或钻石的权限规则允许其调用)。
  2. 函数签名校验:确认functionsToRemove中的签名与目标facet中的完全一致,比如uint与uint256是别名,但尽量保持写法统一避免潜在问题。
  3. Facet地址有效性:在循环中添加检查,确保获取到的facet地址不为空,避免无效地址触发回滚:
require(facetWithFn != address(0), "Function not found in any facet");

修复后的完整代码示例

contract ExecuteDiamondCuts {

    address constant CONTRACT_ADDRESS = 0xblahblah; // dummy address
    string[] functionsToRemove;

    constructor() {
        functionsToRemove.push("exampleFunctionA(address)");
        functionsToRemove.push("exampleFunctionB(uint)");
        functionsToRemove.push("exampleFunctionC()");
    }
    
    function cutSomeDiamonds() external {
        IDiamondLoupe _loupe = IDiamondLoupe(CONTRACT_ADDRESS);

        IDiamondCut.FacetCut[] memory _facetCuts = new IDiamondCut.FacetCut[](functionsToRemove.length);

        for (uint i=0; i<functionsToRemove.length; i++) {
            bytes4 selector = bytes4(keccak256(bytes(functionsToRemove[i])));
            address facetWithFn = _loupe.facetAddress(selector);
            require(facetWithFn != address(0), "Function not found");

            bytes4[] memory _fnSelectors = new bytes4[](1);
            _fnSelectors[0] = selector;

            IDiamondCut.FacetCut memory _facetCut = IDiamondCut.FacetCut({
                facetAddress: facetWithFn,
                action: IDiamondCut.FacetCutAction.Remove,
                functionSelectors: _fnSelectors
            });
            _facetCuts[i] = _facetCut;
        }

        (bool success,) = CONTRACT_ADDRESS.call(
            abi.encodeWithSignature(
                "diamondCut((address,uint8,bytes4[])[],address,bytes)", 
                _facetCuts,
                address(0),
                ""
            )
        );
        require(success, "Diamond cut failed");
    }
}

内容的提问来源于stack exchange,提问作者pildra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 20:41:06