Search code examples
design-patternsethereumsolidityfactory-patterndecentralized-applications

Solidity - Getting from Factory Pattern to Clone Factory Pattern


Below is an example of a solidity contract that's a factory pattern native approach that's adding crew to the neb starship in the matrix.

What would be the Clone Factory version of this contract?

// SPDX-License-Identifier: MIT
pragma solidity >0.4.23 <0.9.0;

contract NebCrewFactory {

    //Creating an array of neb crew addresses
    NebCrew[] public NebCrewAddresses;

    function addNebCrew() public {

        //Creating a new crew object, you need to pay //for the deployment of this contract everytime - $$$$
        NebCrew nebCrewAddress = new NebCrew();

        //Adding the new crew to our list of crew addresses
        NebCrewAddresses.push(nebCrewAddress);
    }
}

contract NebCrew{

    address public crew;

    constructor() {
        crew = msg.sender;
    }

    function welcomeCrew() public pure returns (string memory _greeting) {
        return "Welcome to the truth...";
    }
}

Solution

  • The clone factory version I am showing uses the OpenZeppelin library here

    // SPDX-License-Identifier: MIT
    pragma solidity >0.4.23 <0.9.0;
    
    import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
    
    contract NebCrewFactory {
    
        //Creating an array of neb crew addresses
        NebCrew[] public NebCrewAddresses;
        address public implementationAddress;
        function addNebCrew() public {
    
            //Creating a new crew object, you need to pay //for the deployment of this contract everytime - $$$$
            NebCrew nebCrewAddress = NewCrew(Clones.clone(implementationAddress));
    
            // since the clone create a proxy, the constructor is redundant and you have to use the initialize function
            nebCrewAddress.initialize(); 
    
            //Adding the new crew to our list of crew addresses
            NebCrewAddresses.push(nebCrewAddress);
        }
    }
    
    contract NebCrew{
    
        address public crew;
    
        initialize() {
            require(crew == address(0), "already initialized");
            crew = msg.sender;
        }
    
        function welcomeCrew() public pure returns (string memory _greeting) {
            return "Welcome to the truth...";
        }
    }
    

    Also unrelated but I thought to mention, it's better to use a map in the factory instead of an array if you can since it might cause a problem in the future