Remix

無法解釋執行時錯誤

  • November 30, 2020

當我在 require 語句中使用變數 minimum

require(msg.value >= minimum, "Below Minimum");

我在 Remix 中收到以下錯誤。但是,如果我用 0 而不是 minimum 對 require 語句進行硬編碼,則一切正常。為什麼?

交易到 SendContractEther.sendEtherToContract 錯誤:VM 錯誤:還原。revert 事務已恢復到初始狀態。注意:如果您發送值並且您發送的值應該小於您目前的餘額,則呼叫的函式應該是應付的。調試事務以獲取更多資訊。

我正在從合約 SendContractEther 向合約 King 發送乙太幣。

感謝您對此行為的解釋。

// SPDX-License-Identifier: MIT

pragma solidity 0.7.4;

contract King {

 uint public minimum;
 address payable public owner;

 constructor() payable {
   owner = msg.sender;  
   minimum = 0;
 }

 receive () external payable {
   
   require(msg.value >= minimum, "Below Minimum");
   owner.transfer(msg.value);
 
 }

}
// SPDX-License-Identifier: MIT

pragma solidity 0.7.4;

contract SendContractEther {
   
   address payable public contractAddress ;
   
   // Assign the address of the Contract
   constructor(address payable _contractAddress) payable {
       contractAddress = _contractAddress;
   }
   
   function sendEtherToContract() external payable {
       
       contractAddress.transfer(address(this).balance);
       
   }
}

這個問題問得好!

由於從另一個合約(即,不是從外部擁有的賬戶)將 ETH 轉移到合約而執行的功能receive和執行時的 gas-stipend 為2300。fallback

在你的情況下:

require(msg.value >= minimum, "Below Minimum");
owner.transfer(msg.value);
  • 讀取儲存變數的成本minimum是 800 gas
  • 讀取儲存變數的成本owner是 800 gas
  • 通過執行外部函式呼叫的成本transfer至少為 800 gas(取決於轉移的數量,以及雙方的餘額)

評估表達式msg.value >= minimum(以及讀取局部變數msg.value本身)所需的氣體可以忽略不計,但正如您所見,即使沒有它,您也已經超過了氣體津貼,至少使用 2400 氣體。

minimum因此,用硬編碼替換儲存變數0可能會讓你遠遠低於 gas-stipend(使用大約 1600 gas)並解決問題。

您可以通過將 ETH 從外部擁有的賬戶轉移到該合約來驗證這一點,該賬戶不適用任何 gas-stipend,並看到它成功完成,儘管使用了儲存變數minimum(前提是您轉移的金額等於或大於minimum)。

或者,您可以重命名函式receive,然後直接從另一個合約呼叫它:

contract King {
   ...

   function test() external payable {
       require(msg.value >= minimum, "Below Minimum");
       owner.transfer(msg.value);
   }
}

contract SendContractEther {
   ...
   
   function sendEtherToContract() external payable {
       King(contractAddress).test{value: address(this).balance}();
   }
}

由於這裡沒有gas-stipend,因此執行sendEtherToContract應該成功完成。

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