Issue with ProxyFactory Implementation using minimal proxy

I am trying to build an implementation of ProxyFactory. I am taking inspiration from the endaoment-contracts here. They have used a ProxyFactory which creates minimal proxies.

The issue I am facing is that my implementation creates the same Factory contract instead of the proxy contract.

import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol";


contract ProxyFactory {

    event ProxyCreated(address proxy);


    function deployMinimal(address _logic, bytes memory _data) public returns (address proxy) {
        // Adapted from https://github.com/optionality/clone-factory/blob/32782f82dfc5a00d103a7e61a17a5dedbd1e8e9d/contracts/CloneFactory.sol
        bytes20 targetBytes = bytes20(_logic);
        assembly {
            let clone := mload(0x40)
            mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(clone, 0x14), targetBytes)
            mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            proxy := create(0, clone, 0x37)
        }

        emit ProxyCreated(address(proxy));

        if(_data.length > 0) {
            (bool success,) = proxy.call(_data);
            require(success);
        }
    }

    
}

My Box Contract is

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

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

contract BoxV2 is UUPSUpgradeable {

    address public owner;
    uint256 public length;
    uint256 public width;
    uint256 public height;

    function initialize(uint256 l, uint256 w, uint256 h) public initializer {
        owner = msg.sender;
        length = l;
        width = w;
        height = h;
    }

    function volume() view public returns (uint256) {
        return length * width * height;
    }

    function _authorizeUpgrade(address newImplementation) internal override virtual {
        require(msg.sender == owner, "Unauthorized Upgrade");
    }

}

And my BoxFactory contract is

import "@openzeppelin/contracts-upgradeable/utils/Create2Upgradeable.sol";
import "./ProxyFactory.sol";

contract BoxFactory is ProxyFactory{
    
    event BoxCreated(address proxy);

    address[] public proxies;

    address public _logic;

    constructor (address logic) {
        _logic = logic;
    }

    function createByDeployingMinimal(uint256 l, uint256 w, uint256 h) public returns (address){
        bytes memory payload = abi.encodeWithSignature(
            "initialize(uint256,uint256,uint256)",
            l,
            w,
            h
        );
        address proxy = deployMinimal(_logic, payload);
        
        emit BoxCreated(proxy);
        
        proxies.push(proxy);
        
        return proxy;
    }


}

I’m using Remix-IDE and I am doing the following steps

  1. Deploying the BoxV2 contract and note down its address
  2. Deploy a BoxFactory using the address above as the _logic parameter.
  3. I can see that there is a new Contract created. When I take the address (from emitted logs) and paste it in the Remix’s “At Address” textbox, it shows me another instance of BoxFactory. I am expecting to see either a Proxy contract or the BoxV2 contract. Is that incorrect?

Regards,

Nevermind. I found the issue. It was the way I was using Remix. So basically in REMIX, you have to choose the contract from the dropdown and then when you specify the address, it will be a proxy to the correct contract.

2 Likes