all files / contracts/utils/ Cloneable.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 122 123 124 125 126 127 128 129 130 131                                                                                                                                        15×                   101×               124×                             15×         15× 15×                       101×         101× 99×      
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.6;
 
import "./../interfaces/utils/ICloneable.sol";
 
/**
 * @title Factory for arbitrary code deployment using the "CREATE" and "CREATE2" opcodes
 */
abstract contract Cloneable is ICloneable {
 
    /***************************************
    GLOBAL VARIABLES
    ***************************************/
 
    bytes private constant MINIMAL_PROXY_INIT_CODE_PREFIX =
        hex"3d602d80600a3d3981f3_363d3d373d3d3d363d73";
    bytes private constant MINIMAL_PROXY_INIT_CODE_SUFFIX =
        hex"5af43d82803e903d91602b57fd5bf3";
 
    /***************************************
    VIEW FUNCTIONS
    ***************************************/
 
    /**
     * @notice calculate the deployment address for a given target and salt
     * @param salt input for deterministic address calculation
     * @return deployment address
     */
    function calculateMinimalProxyDeploymentAddress(bytes32 salt) public view override returns (address) {
        return
            _calculateDeploymentAddress(
                keccak256(_generateMinimalProxyInitCode()),
                salt
            );
    }
 
    /***************************************
    HELPER FUNCTIONS
    ***************************************/
 
    /**
     * @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) internal view returns (address) {
        return
            address(
                uint160(
                    uint256(
                        keccak256(
                            abi.encodePacked(
                                hex"ff",
                                address(this),
                                salt,
                                initCodeHash
                            )
                        )
                    )
                )
            );
    }
 
    /**
     * @notice deploy an EIP1167 minimal proxy using "CREATE" opcode
     * @dev reverts if deployment is not successful
     * @return minimalProxy address of deployed proxy
     */
    function _deployMinimalProxy() internal returns (address minimalProxy) {
        return _deploy(_generateMinimalProxyInitCode());
    }
 
    /**
     * @notice deploy an EIP1167 minimal proxy using "CREATE2" opcode
     * @dev reverts if deployment is not successful (likely because salt has already been used)
     * @param salt input for deterministic address calculation
     * @return minimalProxy address of deployed proxy
     */
    function _deployMinimalProxy(bytes32 salt) internal returns (address minimalProxy) {
        return _deploy(_generateMinimalProxyInitCode(), salt);
    }
 
    /**
     * @notice concatenate elements to form EIP1167 minimal proxy initialization code
     * @return bytes memory initialization code
     */
    function _generateMinimalProxyInitCode() internal view returns (bytes memory) {
        return
            abi.encodePacked(
                MINIMAL_PROXY_INIT_CODE_PREFIX,
                address(this),
                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), "Cloneable: 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), "Cloneable: failed deployment");
        emit ContractDeployed(deployment);
    }
}