POA Forum

An issue apparently related to create2

Hi everyone,

we are investigating an issue related to CREATE2 and Universal Login (UL) on POA.

Since version 0.3.0 UL use a CREATE2 EVM opcode to deploy a wallet that represents a user (identity). Our code uses UL. Between yesterday and today we made 3 deploys of our dApp using the same code base:

  • on Ropsten it works correctly

  • on Sokol and POA it fails when it deploys a wallet using CREATE2

Here you can see the transaction that fails:
https://blockscout.com/poa/core/tx/0x68343abee171229aa97a1a0b8ac4da8fa717370a581d2c6a854daf16f652bcae/internal_transactions

Below there is the code that executes the deploy and fails on POA.

We are still investigating to understand what goes wrong but if you have any suggestions we would be grateful.

thanks
Michelangelo

contract ProxyCounterfactualFactory is Ownable {
    bytes public initCode;
    using ECDSA for bytes32;

    constructor(bytes memory _initCode) public {
        initCode = _initCode;
    }

    function createContract(address publicKey, bytes memory initializeWithENS, bytes memory signature) public onlyOwner returns(bool success) {
        require(publicKey == getSigner(initializeWithENS, signature), "Invalid signature");
        bytes32 finalSalt = keccak256(abi.encodePacked(publicKey));
        bytes memory _initCode = initCode;
        address contractAddress;
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            contractAddress := create2(0, add(_initCode, 0x20), mload(_initCode), finalSalt)
            if iszero(extcodesize(contractAddress)) {revert(0, 0)}
        }
        // solium-disable-next-line security/no-low-level-calls
        (success, ) = contractAddress.call(initializeWithENS);
        require(success, "Unable to register ENS domain");
        return success;
    }

    function getSigner(bytes memory initializeWithENS, bytes memory signature) public pure returns (address) {
        return keccak256(abi.encodePacked(initializeWithENS)).toEthSignedMessageHash().recover(signature);
    }
}

@michelangelo Thanks for reporting

@phahulin @maxaleks please take a look

Update: I made a simple test with CREATE2 on Sokol and it seems to work.

This is the code:

pragma solidity ^0.5.2;

contract SimpleContract {
    address owner;
    constructor(address _owner) public {
        owner = _owner;
    }

    function setOwner(address _owner) public {
        require(msg.sender == owner, "only owner can change ownership");
        owner = _owner;
    }
}

contract SimpleFactory {
    bytes public initCode;

    constructor() public {
        initCode = abi.encodePacked(type(SimpleContract).creationCode, address(this));
    }

    function createContract(address publicKey) public returns(address) {
        bytes32 finalSalt = keccak256(abi.encodePacked(publicKey));
        bytes memory _initCode = initCode;
        address contractAddress;
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            contractAddress := create2(0, add(_initCode, 0x20), mload(_initCode), finalSalt)
            if iszero(extcodesize(contractAddress)) {revert(0, 0)}
        }

        return contractAddress;
    }
}

Hi @michelangelo!
I’ve just tested create2 on Sokol and POA and it works. I think that something is wrong with your code (or with contract dependencies). Also I’ve noticed that your transaction is a contract creation, not a contract call where the create2 method is called in your code

1 Like

create2 worked for me too - https://blockscout.com/poa/sokol/tx/0xa06c45f550dcc445a9a8895777982564498c2900f8560826038b3cd9af4a4e87/internal_transactions
So it calls Factory contract which in turn creates Account contract via create2
(based on https://github.com/miguelmota/solidity-create2-example)

@maxaleks @phahulin thanks!

Now I am thinking it is an applicative problem.