I have a UUPSUpgradeable
factory contract that is creating a new ERC1967Proxy
clone of a UUPSUpgradeable
implementation contract, but the constructor call fails:
interface IFoo {
/// @notice Contract initialization logic
function initialize(
address _arg1,
address payable _arg2,
uint256 _arg3
) external returns (bool);
}
contract FooV1 is
Initializable,
OwnableUpgradeable,
ReentrancyGuardUpgradeable,
UUPSUpgradeable,
IFoo
{
/// @notice Contract constructor logic
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(
address _arg1,
address payable _arg2,
uint256 _arg3
) external initializer returns(bool) {
__Ownable_init();
__UUPSUpgradeable_init();
// ...
return true;
}
// ...
}
contract FooFacV1 is
Initializable,
OwnableUpgradeable,
UUPSUpgradeable
{
address payable public template; // deployed FooV1 proxy
function createNew(
address _arg1,
address payable _arg2,
uint256 _arg3
) public returns (address) {
address clone = address(
new ERC1967Proxy(
template,
abi.encodeWithSelector(
IFoo(template).initialize.selector,
_arg1,
_arg2,
_arg3
)
)
);
Looking at the stack trace, it seems that the call to initialize
is failing:
Error: VM Exception while processing transaction: reverted with reason string 'Address: low-level delegate call failed'
at ERC1967Proxy._setImplementation (@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol:40)
at ERC1967Proxy.verifyCallResultFromTarget (@openzeppelin/contracts/utils/Address.sol:209)
at ERC1967Proxy.functionDelegateCall (@openzeppelin/contracts/utils/Address.sol:186)
at ERC1967Proxy.functionDelegateCall (@openzeppelin/contracts/utils/Address.sol:171)
at ERC1967Proxy._upgradeToAndCall (@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol:62)
at ERC1967Proxy.constructor (@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:23)
...
What's the correct way to do this?