pragma solidity ^0.5.3; import "./InitializableAdminUpgradeabilityProxy.sol"; import "../cryptography/ECDSA.sol"; contract ProxyFactory { event ProxyCreated(address proxy); bytes32 private contractCodeHash; constructor() public { contractCodeHash = keccak256( type(InitializableAdminUpgradeabilityProxy).creationCode ); } function deployMinimal(address _logic, bytes memory _data) public returns (address proxy) { // Adapted from https://github.com/optionality/clone-factory/blob/32782f82dfc5a00d103a7e61a17a5dedbd1e8e9d/contracts/CloneFactory.sol bytes20 targetBytes = bytes20(_logic); assembly { let clone := mload(0x40) mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(clone, 0x14), targetBytes) mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) proxy := create(0, clone, 0x37) } emit ProxyCreated(address(proxy)); if(_data.length > 0) { (bool success,) = proxy.call(_data); require(success); } } function deploy(uint256 _salt, address _logic, address _admin, bytes memory _data) public returns (address) { return _deployProxy(_salt, _logic, _admin, _data, msg.sender); } function deploySigned(uint256 _salt, address _logic, address _admin, bytes memory _data, bytes memory _signature) public returns (address) { address signer = getSigner(_salt, _logic, _admin, _data, _signature); require(signer != address(0), "Invalid signature"); return _deployProxy(_salt, _logic, _admin, _data, signer); } function getDeploymentAddress(uint256 _salt, address _sender) public view returns (address) { // Adapted from https://github.com/archanova/solidity/blob/08f8f6bedc6e71c24758d20219b7d0749d75919d/contracts/contractCreator/ContractCreator.sol bytes32 salt = _getSalt(_salt, _sender); bytes32 rawAddress = keccak256( abi.encodePacked( bytes1(0xff), address(this), salt, contractCodeHash ) ); return address(bytes20(rawAddress << 96)); } function getSigner(uint256 _salt, address _logic, address _admin, bytes memory _data, bytes memory _signature) public view returns (address) { bytes32 msgHash = OpenZeppelinUpgradesECDSA.toEthSignedMessageHash( keccak256( abi.encodePacked( _salt, _logic, _admin, _data, address(this) ) ) ); return OpenZeppelinUpgradesECDSA.recover(msgHash, _signature); } function _deployProxy(uint256 _salt, address _logic, address _admin, bytes memory _data, address _sender) internal returns (address) { InitializableAdminUpgradeabilityProxy proxy = _createProxy(_salt, _sender); emit ProxyCreated(address(proxy)); proxy.initialize(_logic, _admin, _data); return address(proxy); } function _createProxy(uint256 _salt, address _sender) internal returns (InitializableAdminUpgradeabilityProxy) { address payable addr; bytes memory code = type(InitializableAdminUpgradeabilityProxy).creationCode; bytes32 salt = _getSalt(_salt, _sender); assembly { addr := create2(0, add(code, 0x20), mload(code), salt) if iszero(extcodesize(addr)) { revert(0, 0) } } return InitializableAdminUpgradeabilityProxy(addr); } function _getSalt(uint256 _salt, address _sender) internal pure returns (bytes32) { return keccak256(abi.encodePacked(_salt, _sender)); } }