Solidity

未能將乙太幣從父合約轉移到子合約

  • December 29, 2020

我創建了一個契約工廠(父契約)來創建一個子契約。在父合約中,有一個功能,通過輸入子合約地址,將父合約的餘額轉移到子合約。我發現當接收函式是普通的(接收函式中沒有其他動作)時,傳輸會成功。當我添加其他操作(例如更改狀態變數)時,事務將失敗並顯示錯誤:

transact to ContractFactory.pay errored: VM error: revert. revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.

這是合約程式碼:

pragma solidity >=0.6.0 <0.8.0;

contract ContractFactory {
   address[] contractsAddress;
   mapping(address => Contract) private contracts;
   
   function createContract(uint price) public {
       Contract newContract = new Contract(msg.sender, price);
       contractsAddress.push(address(newContract));
       contracts[address(newContract)] = newContract;
   }
   
   receive() external payable{
   }
   
   function pay(address payable contractAddress) public payable{
       contractAddress.transfer(address(this).balance);
   }
   
   function getAllContractsAddress() view public returns(address[] memory) {
       return contractsAddress;
   }
}

contract Contract {
   enum Status {Unavailable, Available}
   Status public contractStatus;
   
   address payable public contractOwner;
   address payable public buyer;
   
   uint public price;
   
   event Occupy(address _occupant);
   
   constructor(address payable _contractOwner, uint _price) {
       contractOwner = _contractOwner;
       price = _price;
       contractStatus = Status.Available;
   }
   
   modifier onlyWhenAvailable {
       require(contractStatus == Status.Available);
       _;
   }
   
   modifier notOwner {
       require(msg.sender != contractOwner);
       _;
   }
   
   modifier payEnoughAmount {
       uint priceInEther = price * 1 ether;
       require(msg.value >= priceInEther);
       _;
   }
   
   receive() external payable onlyWhenAvailable notOwner payEnoughAmount {
       contractStatus = Status.Unavailable;
       buyer = msg.sender;
   }
}

你需要改變:

contractAddress.transfer(address(this).balance);

到:

contractAddress.call{value: address(this).balance}("");

為什麼?因為在使用方法時transfer()send()被呼叫的合約只能使用 2300 gas,這顯然不足以更新狀態。這就是為什麼當receive合約方法Contract為空並且不更新被呼叫合約的狀態時您的函式成功的原因。

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