TransferOwnership when creating a Clone not working ("Ownable: caller is not the owner") - EIP-1167

Hi,

I'm working on a factory and I'm starting to test "@openzeppelin/contracts/proxy/Clones.sol".
My SC is the following one:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "@openzeppelin/contracts/proxy/Clones.sol";
import "./VotingHandler.sol";

contract VotingFactory {
    address immutable votingHandlerImplementation;

    mapping(bytes32 => address) public deployedInstances;

    event NewInstance(address indexed _from, address indexed _contract, bytes32 indexed _votingId);

    constructor() {
        votingHandlerImplementation = address(new VotingHandler());
    }

    function b_A6Q() external {
        bytes32 votingId = keccak256(abi.encodePacked(msg.sender, address(this), block.timestamp));
        
        require(deployedInstances[votingId] == address(0), "Instance already exists");

        address clone = Clones.cloneDeterministic(votingHandlerImplementation, votingId);
        VotingHandler(clone).transferOwnership(msg.sender); // this line isn't working

        emit NewInstance(msg.sender, clone, votingId);
    }
}

VotingHandler is using "@openzeppelin/contracts/access/Ownable.sol"; and don't have a constructor:

// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";

contract VotingHandler is Ownable, Pausable {

...

}

VotingHandler is working perfectly when it's not Clone.

When I want to call "b_A6Q()" from VotingFactory, the line "VotingHandler(clone).transferOwnership(msg.sender);" isn't working and I get a revert with this error: "Reason provided by the contract: "Ownable: caller is not the owner"."

I've followed the following video: https://www.youtube.com/watch?v=3Mw-pMmJ7TA, but I guess I haven't understand something...

How can I properly transferOwnership of the new instance to msg.sender?

Hi @0x_nicolas
can you share any link to deployed contracts?

Btw if you don't have any initializer, the owner() won't be set so it will be 0x..000 by default

Hi @FreezyEx and thank you for your anwser!

I don't have a link to deployed contracts for now (I'm using Remix in local) but I can deployed them to Goerli if it's needed?

I've tried to add a constructor to my VotingHandler with no change (owner is still 0x...000 when using my Factory). But the VotingHandler is working perfectly without the Factory (owner is properly set and all functions are working).
And it's also working fine with a "classic" factory for example:

function b_A6Q() external {
     bytes32 votingId = keccak256(abi.encodePacked(msg.sender, address(this), block.timestamp));
        
     require(deployedInstances[votingId] == address(0), "Instance already exists");

     VotingHandler votingInstance = new VotingHandler();
     votingInstance.transferOwnership(msg.sender);

     emit NewInstance(msg.sender, address(votingInstance), votingId);
}

And as Ownable.sol has a constructor, I don't need to have a constructor in VotingHandler.sol to transferOwnership isn't it?

When you deploy a contract using clone, you can't use a constructor. instead you need to use a initializer.
Check OwnableUpgradable too

1 Like

Thank you @FreezyEx, it perfectly works with OwnableUpgradable! :grinning:

1 Like