all files / contracts/utils/ Factory.sol

100% Statements 9/9
75% Branches 3/4
100% Functions 7/7
100% Lines 11/11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121                                        153×                     30×                                           187×                             153×         153× 153×                       30×         30× 29×                                                    
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.6;
 
/**
 * @title Factory for arbitrary code deployment using the "CREATE" and "CREATE2" opcodes
 */
abstract contract Factory {
    bytes private constant MINIMAL_PROXY_INIT_CODE_PREFIX =
        hex"3d602d80600a3d3981f3_363d3d373d3d3d363d73";
    bytes private constant MINIMAL_PROXY_INIT_CODE_SUFFIX =
        hex"5af43d82803e903d91602b57fd5bf3";
 
    event ContractDeployed(address indexed deployment);
 
    /**
     * @notice deploy an EIP1167 minimal proxy using "CREATE" opcode
     * @param target implementation contract to proxy
     * @return minimalProxy address of deployed proxy
     */
    function _deployMinimalProxy(address target) internal returns (address minimalProxy) {
        return _deploy(_generateMinimalProxyInitCode(target));
    }
 
    /**
     * @notice deploy an EIP1167 minimal proxy using "CREATE2" opcode
     * @dev reverts if deployment is not successful (likely because salt has already been used)
     * @param target implementation contract to proxy
     * @param salt input for deterministic address calculation
     * @return minimalProxy address of deployed proxy
     */
    function _deployMinimalProxy(address target, bytes32 salt) internal returns (address minimalProxy) {
        return _deploy(_generateMinimalProxyInitCode(target), salt);
    }
 
    /**
     * @notice calculate the deployment address for a given target and salt
     * @param target implementation contract to proxy
     * @param salt input for deterministic address calculation
     * @return deployment address
     */
    function calculateMinimalProxyDeploymentAddress(address target, bytes32 salt) public view returns (address) {
        return
            calculateDeploymentAddress(
                keccak256(_generateMinimalProxyInitCode(target)),
                salt
            );
    }
 
    /**
     * @notice concatenate elements to form EIP1167 minimal proxy initialization code
     * @param target implementation contract to proxy
     * @return bytes memory initialization code
     */
    function _generateMinimalProxyInitCode(address target) internal pure returns (bytes memory) {
        return
            abi.encodePacked(
                MINIMAL_PROXY_INIT_CODE_PREFIX,
                target,
                MINIMAL_PROXY_INIT_CODE_SUFFIX
            );
    }
 
    /**
     * @notice deploy contract code using "CREATE" opcode
     * @param initCode contract initialization code
     * @return deployment address of deployed contract
     */
    function _deploy(bytes memory initCode) internal returns (address deployment) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let encoded_data := add(0x20, initCode)
            let encoded_size := mload(initCode)
            deployment := create(0, encoded_data, encoded_size)
        }
        Erequire(deployment != address(0), "Factory: failed deployment");
        emit ContractDeployed(deployment);
    }
 
    /**
     * @notice deploy contract code using "CREATE2" opcode
     * @dev reverts if deployment is not successful (likely because salt has already been used)
     * @param initCode contract initialization code
     * @param salt input for deterministic address calculation
     * @return deployment address of deployed contract
     */
    function _deploy(bytes memory initCode, bytes32 salt) internal returns (address deployment) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let encoded_data := add(0x20, initCode)
            let encoded_size := mload(initCode)
            deployment := create2(0, encoded_data, encoded_size, salt)
        }
        require(deployment != address(0), "Factory: failed deployment");
        emit ContractDeployed(deployment);
    }
 
    /**
     * @notice calculate the _deployMetamorphicContract deployment address for a given salt
     * @param initCodeHash hash of contract initialization code
     * @param salt input for deterministic address calculation
     * @return deployment address
     */
    function calculateDeploymentAddress(bytes32 initCodeHash, bytes32 salt) public view returns (address) {
        return
            address(
                uint160(
                    uint256(
                        keccak256(
                            abi.encodePacked(
                                hex"ff",
                                address(this),
                                salt,
                                initCodeHash
                            )
                        )
                    )
                )
            );
    }
}