Solidity
委託呼叫失敗
我有這個第二層
delegatecall
(對已經執行過委託呼叫的合約的委託呼叫),即使在檢查了它可能失敗的所有主要原因(儲存佈局、uint 別名、契約等)之後,它仍然會繼續失敗。當我從 切換
delegatecall
到 時call
,它執行完美(但我需要委託呼叫)。我將麻煩的函式簡化為一個簡單的
getHi()
/getHello()
(無參數),console.log
在體內帶有 a ,但它仍然失敗。這是所涉及的契約的簡要摘要,以顯示基本設置:(我不會對第一份契約太費心。它只是一個重定向呼叫的代理)
contract Diamond { AppStorage s; fallback() external payable { LibDiamond.DiamondStorage storage ds; bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; assembly { ds.slot := position } address facet = ds.facets[msg.sig]; require(facet != address(0), "Diamond: Function does not exist"); assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } }
contract FacetX { AppStorage s; using SafeERC20 for IERC20; function getHi() public { console.log(s.facetY); //-----> logs the address of FacetY (bool success, ) = s.facetY.delegatecall( //-----> with `call`, runs smoothly abi.encodeWithSignature('getHello()') ); require(success, 'failed'); //-----> fails with this error } }
contract FacetY { AppStorage s; using SafeERC20 for IERC20; function getHello() public view { console.log('hello world'); //-----> never gets logged } }
AppStorage
只是一個結構,所有狀態變數都在我在每個契約上導入的單獨文件中。就像是:struct AppStorage { address facetY; address usdt; ... }
它們在其他地方定義沒有問題。這就是為什麼要
s.facetY
記錄 FacetY 的地址。
解決方案:
delegatecall
前鋒msg.value
(除了msg.sender
)。我在發送 Ether 時呼叫了代理,即使我的函式本身不處理 Ether,我仍然需要將它們標記為
payable
(第二個和第三個合約中的兩個函式)。否則,tx 將失敗。因此,通過添加
payable
andgetHi()
,getHello()
問題得到了解決。