Factory-Based Smart Contracts

In order to:

  • Save Smart Contract space;

  • Have the assurance to interact with 100% genuine SmartContracts;

  • Easily Smart Contract code update;

  • Easy search system of similar Smart Contract through events

We usually use a Model - Factory pattern to fuse flexibility and security together.

The Model always contains all the Business Logic of the Smart Contract. It does not have a constructor, but an optional initialization method.

The Factory has the logic to reference the original model and to clone it keeping track of all the instances through events. The initialization method is general purpose in order to make the model updateable.

pragma solidity ^0.7.0;
pragma abicoder v2;

contract Model {

	address public factory;
	
	function init() {
		require(factory == address(0), "Init already called!");
		//This links the Model directly to the Factory
		factory = msg.sender;
		
		/*
		 * Other init stuff
		 */
	}
}

pragma solidity ^0.7.0;
pragma abicoder v2;

contract Factory {

	address public model;
	address public doubleProxy;
	
    event ModelDeployed(address indexed instanceAddress, address indexed sender, bytes initResultData);

    constructor(address _doubleProxy, address _model) {
        doubleProxy = _doubleProxy;
		model = _model;
    }

    function setDoubleProxy(address _doubleProxy) public byDFO {
        doubleProxy = _doubleProxy;
    }

	//Model can be changed only by authorization (Proposal)
    function setModel(address _model) public byDFO {
        model = _model;
    }

	//Clones the bytecode of the Model and calls the model initialization method.
	//In order to maintain the Factory totally model independant, initialization data must be passed as ABI-Encoded parameters
	//E.G. in this case, data is equal to bytes4(keccak256("init()")), which corresponds to the init() method of the actual Model.
	//This method will work even if the Model and its initialization method changes
    function deploy(bytes memory data) public returns (address contractAddress, bytes memory initResultData) {
        initResultData = _call(contractAddress = _clone(model), data);
        emit ModelDeployed(contractAddress, msg.sender, initResultData);
    }

    function _clone(address original) private returns (address copy) {
        assembly {
            mstore(
                0,
                or(
                    0x5880730000000000000000000000000000000000000000803b80938091923cF3,
                    mul(original, 0x1000000000000000000)
                )
            )
            copy := create(0, 0, 32)
            switch extcodesize(copy)
                case 0 {
                    invalid()
                }
        }
    }

    function _call(address location, bytes memory payload) private returns(bytes memory returnData) {
        assembly {
            let result := call(gas(), location, 0, add(payload, 0x20), mload(payload), 0, 0)
            let size := returndatasize()
            returnData := mload(0x40)
            mstore(returnData, size)
            let returnDataPayloadStart := add(returnData, 0x20)
            returndatacopy(returnDataPayloadStart, 0, size)
            mstore(0x40, add(returnDataPayloadStart, size))
            switch result case 0 {revert(returnDataPayloadStart, size)}
        }
    }

    modifier byDFO() {
        require(IMVDFunctionalitiesManager(IMVDProxy(IDoubleProxy(doubleProxy).proxy()).getMVDFunctionalitiesManagerAddress()).isAuthorizedFunctionality(msg.sender), "Unauthorized.");
        _;
    }
}

Below are some use cases of Factory contracts developed and used by Ethos:

Last updated