Solidity

委託呼叫失敗

  • April 2, 2022

我有這個第二層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 將失敗。

因此,通過添加payableand getHi()getHello()問題得到了解決。

引用自:https://ethereum.stackexchange.com/questions/125217