[Ethereum] Passing constructor arguments to the CREATE assembly instruction in solidity

assemblyconstructorcreatesolidity

I have a contract which deploys other contracts by bytecode:

contract DeployContract {
    function deploy(bytes calldata _bytecode) external returns(address addr) {

        bytes memory bytecode = abi.encode(_bytecode, msg.sender);
        assembly {
            addr := create(0, add(bytecode, 0x20), mload(bytecode))
            if iszero(extcodesize(addr)) {
                revert(0, 0)
            }
        }
    }
}

I want to deploy contracts which take an address as argument in their constructor. Appending the address to the bytecode as above does not work. How do I pass the constructor parameter?

Best Answer

This worked for CREATE2. Maybe it also works on CREATE?

abi.encodePacked(bytecode, abi.encode(arg1, arg2))

Example (CREATE2)

pragma solidity ^0.5.11;

contract Wallet {
    address public owner;
    uint public foo;

    constructor(address _owner, uint _foo) public {
        owner = _owner;
        foo = _foo;
    }
}

contract Factory {
    event Deployed(address addr, uint256 salt);

    function getCreationBytecode(address _owner, uint _foo) public pure returns (bytes memory) {
        bytes memory bytecode = type(Wallet).creationCode;

        return abi.encodePacked(bytecode, abi.encode(_owner, _foo));
    }

    // NOTE: call this function with bytecode from getCreationByteCode and a random salt
    function deploy(bytes memory bytecode, uint _salt) public {
        address addr;
        assembly {
            addr := create2(0, add(bytecode, 0x20), mload(bytecode), _salt)

            if iszero(extcodesize(addr)) {
                revert(0, 0)
            }
        }

        emit Deployed(addr, _salt);
    }
}
Related Topic