Create2: Failed on deploy when using Create2 library

I am trying to use the deploy function in the Create2.sol library contract. I am getting the Create2: Failed on deploy revert.

:computer: Environment

Using buidler framework. v1.3.2
Using OZ contracts v3.0.1
Using buidler/truffle5 plugin v1.3.1

:memo:Details

I’m not entirely sure why its failing to deploy, the stack traces show it failing on L35 of the Create2.sol file.

:1234: Code to reproduce

The code for the test:

contract("Registry and Factory Contract", (accounts) => {
    // ACCOUNTS
    const Alice = accounts[0];

    let factory, tokenU, tokenS, base, quote, expiry;

    before(async () => {
        factory = await Factory.new(Alice);
        tokenU = await newERC20("TEST DAI", "DAI", MILLION_ETHER);
        tokenS = await newWeth();
        base = toWei("200");
        quote = toWei("1");
        expiry = "1690868800"; // May 30, 2020, 8PM UTC
    });

    describe("Registry", () => {
        it("should deploy the contract", async () => {
            await factory.deploy(
                tokenU.address,
                tokenS.address,
                base,
                quote,
                expiry
            );
        });
    });
});

The code for the factory contract:

import { Option, SafeMath } from "../../primitives/Option.sol";
import "../../interfaces/IFactory.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol";

contract Factory is IFactory, Ownable {
    using SafeMath for uint;

    constructor(address registry) public { transferOwnership(registry); }

    function deploy(address tokenU, address tokenS, uint base, uint quote, uint expiry)
        external
        override
        onlyOwner
        returns (address option)
    {
        bytes memory bytecode = type(Option).creationCode;
        bytes32 salt = keccak256(abi.encodePacked(tokenU, tokenS, base, quote, expiry));
        option = Create2.deploy(uint(0), salt, bytecode);
    }
}

1 Like

Hi @alexander,

Welcome to the community forum :wave:

If you use a constructor, this is part of the creation code and will impact the CREATE2 deployment address. See Getting the most out of CREATE2 for more details.

A simple example is as follows, with the Vault contract using an Initializer:

Vault.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "@openzeppelin/upgrades/contracts/Initializable.sol";

contract Vault is Initializable {
    address payable public owner;

    function initialize(address payable _owner) public initializer {
        owner = _owner;
    }

    function withdraw() public {
        require(owner == msg.sender, "Vault: Not owner");
        owner.transfer(address(this).balance);
    }
}

VaultFactory.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "./Vault.sol";
import "@openzeppelin/contracts/utils/Create2.sol";

contract VaultFactory {
    event VaultCreated(address vault);

    function deployVault(bytes32 salt, address payable owner) public {
        address vaultAddress;

        vaultAddress = Create2.deploy(0, salt, type(Vault).creationCode);
        Vault(vaultAddress).initialize(owner);

        emit VaultCreated(vaultAddress);
    }

    function computeAddress(bytes32 salt) public view returns (address) {
        return
            Create2.computeAddress(salt, keccak256(type(Vault).creationCode));
    }
}

Deploy VaultFactory

$ npx oz deploy
✓ Compiled contracts with solc 0.6.10 (commit.00c0fcaf)
Compilation warnings:
@openzeppelin/upgrades/contracts/Initializable.sol: Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.

? Choose the kind of deployment regular
? Pick a network development
? Pick a contract to deploy VaultFactory
✓ Deployed instance of VaultFactory
0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab

Compute address (for salt 0x42)

$ npx oz call
? Pick a network development
? Pick an instance VaultFactory at 0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab
? Select which function computeAddress(salt: bytes32)
? salt: bytes32: 0x42
✓ Method 'computeAddress(bytes32)' returned: 0xEdbC0b28Ac53390ccd1b987d6348bE97C93c4f53
0xEdbC0b28Ac53390ccd1b987d6348bE97C93c4f53

Deploy (for salt (0x42)

$ npx oz send-tx
? Pick a network development
? Pick an instance VaultFactory at 0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab
? Select which function deployVault(salt: bytes32, owner: address)
? salt: bytes32: 0x42
? owner: address: 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
✓ Transaction successful. Transaction hash: 0x6956a48e6748cd90a51cd578924c63fac36274443e64f4681e5f791b3f3a0769
Events emitted:
 - VaultCreated(0xEdbC0b28Ac53390ccd1b987d6348bE97C93c4f53)

Hi @alexander,

Checking that you were able to resolve?