10

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?

1
  • 1
    You need to abi-encode them, and then append the result at the end of the bytecode, before passing it to the create function. Jan 5, 2020 at 18:52

3 Answers 3

13

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);
    }
}
4

You need to abi-encode the input arguments, and then append the result at the end of the bytecode before passing it to the create function.

Suppose you have input arguments arg1, arg2 and arg3.

I believe that you can more or less achieve that by changing this:

bytes memory bytecode = _bytecode;

To this:

bytes memory bytecode = abi.encode(_bytecode, arg1, arg2, arg3);

I haven't tested it, so feel free to do it and report back...

4
  • I tested it and it didn't work for me. Maybe there is something wrong with how I am giving the bytecode to the create instruction
    – Bobface
    Jan 5, 2020 at 19:17
  • I have researched a bit more and changed the code a little bit. I have edited my original question with the new code. It still does not work unfortunately.
    – Bobface
    Jan 5, 2020 at 19:48
  • @goodvibration the mistake in this code is that the constructor arguments have to be encoded using abi.encode, but then the final result has to be concatenated with the bytecode using abi.encodePacked. Apr 20, 2023 at 18:45
  • It might be a good idea to use bytes.concat instead of abi.encodePa cked. Apr 20, 2023 at 18:54
1

You have to encode arguments with abi.encode and bytes with abi.encodePacked. Compiles with Solidity 0.4.0.

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

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.