Solidity

當孩子擁有時如何使用工廠模式?

  • September 5, 2022

我試圖推斷工廠如何呼叫 EOA 擁有的子契約。

這個項目的目標是製作一個 StoreFactory 合約,允許任何人部署他們自己的 Store 合約。部署商店的商家應該是所有者,並且應該是唯一可以從購買中提取 ETH 的人。以下是我試圖修復以啟用此流程的一些虛擬碼。

經過一番研究,我相信我需要使用delegatecall,但我不確定。

商店工廠:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "./Store.sol";

contract StoreFactory {
   uint256 id;
   mapping(uint256 => Store) storeMapping;
   
   function createStore() public {
       Store store = new Store();
       store.transferOwnership(msg.sender());
       storeMapping[id] = child;
       id++;
   }

   function depositEth(uint256 _id) public {
       storeMapping[_id].depositEth();
   }

   function withdrawEth(uint256 _id) public {
       storeMapping[_id].withdrawEth();
   }
}

儲存(子)契約:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "openzeppelin-contracts/contracts/access/Ownable.sol";

contract Store is Ownable {

   function depositEth() public payable {}

   function withdrawEth() public onlyOwner {
       uint amount = address(this).balance;
       (bool success, ) = msg.sender.call{value: amount}("");
       require(success, "Failed to send Ether");
   }
   
}

如果工廠正在打電話,那麼創建商店的原始 EOA 帳戶如何提取資金?這就是我想要完成的。

為什麼要 msg.sender 成為子合約的所有者?還有,誰 msg.sender 應該在這裡?是您(如協議的設計者)還是使用者?如果是你,我建議你不要那樣做,讓工廠擁有孩子。如果它是使用者,那麼您仍然可以這樣做,但希望他們也成為契約所有者是有意義的。

在這種情況下,您可以執行以下操作:

工廠 :

// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "./Child.sol";


contract ChildFactory {
   uint256 id;
   mapping(uint256 => Child) childMapping;
   
   function createChild() public {
       Child child = new Child(address(this));
       child.transferOwnership(msg.sender);
       childMapping[id] = child;
       id++;
   }

   function depositEth(uint256 _id) public {
       childMapping[_id].depositEth();
   }

   function withdrawEth(uint256 _id) public {
       require(msg.sender == childMapping[_id].owner());
       childMapping[_id].factoryWithdrawEth(msg.sender);
   }
}

孩子 :

// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "openzeppelin-contracts/contracts/access/Ownable.sol";

contract Child is Ownable {

   address factory;

   constructor(address _factory) {
       factory = _factory;
   }
   
   function depositEth() public payable {}

   function ownerWithdraw() public onlyOwner {
       _withdrawEth(msg.sender);
   }

   function factoryWithdrawEth(address to)  public {
       require(msg.sender == factory);
       _withdrawEth(to);
   }

   function _withdrawEth(address account) internal {
       uint amount = address(this).balance;
       (bool success, ) = payable(account).call{value: amount}("");
       require(success, "Failed to send Ether");
   }
   
}

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