Deploy Proxy contract programmatically from base contract

I am having two contracts A and B.

A.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

import "./B.sol";

contract A {

    mapping(address => address) public ownerToAddress;

    function createB(string memory name, string memory title) public returns(address) {
        B newB = new B(name, title, msg.sender);
        ownerToAddress[msg.sender] = address(newB);
        return address(newB);
    }
}

B.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

contract B {

    string public name;
    string public title;
    address public owner;

    constructor (string memory _name, string memory _title, address _owner) {
        owner = _owner;
        name = _name;
        title = _title;
    }

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    function updateName(string memory _name) public onlyOwner {
        name = _name;
    }
}

Contract A is a base contract which is deployed by us and Contract B is deployed with the help of frontend (button click) by users of the application.

We are able to use 1967 standard for creating proxy contract of A.sol but we're not able to understand how to create proxy contract for B.sol.

Read about this - Creating New Instances From Your Contract Code

But here, although they're using ERC20Upgradeable contract but they're saying to first create it and then inject it. I'm not able to understand how to compare this thing with our contract logic.

1 Like

hi,

actually i still don't get it what you mean but my assumption is that you want to make a proxy contract using A.sol (using method "new") and use B.sol as base contract. and the problem is after contract "newB" is created, you can't modify the name & title as the constructor arguments of its contract.

here's my simple solution:

  1. instead of using constructor at contract B, using initializer.

we can't use constructor because the constructor is only called once wen contract is deployed.

B.sol (modified)

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

import "@openzeppelin/contracts/proxy/utils/Initializable.sol";

/// Contract B is inherit to Initializable.sol
contract B is Initializable {

    string public name;
    string public title;
    address public owner;

    /// Initializer
    function initialize(
        string memory _name,
        string memory _title
    ) external initializer {
        name = _name;
        title = _title;
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    function updateName(string memory _name) public onlyOwner {
        name = _name;
    }
}
  1. made some adjustment on contract A

A.sol (modified)

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

import "./B.sol";

contract A {

    mapping(address => address) public ownerToAddress;

    function createB() public returns(address) {
        B newB = new B();
        /// Edited
        ownerToAddress[address(newB)] = msg.sender;
        return address(newB);
    }
}

i did test on remix:

  1. deploy contract B and then deploy contract A on remix

  2. from contract A: call "createB". here's the output (newB's address):

"address: 0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D"

  1. from contract A: call "ownerToAddress". and the output should be the deployer address.

  2. interacting with contract "newB" by copy and paste the newB's address (above) to "load contract from address" (see the img below) and click the "At Address" button and it should return a new tab of contract newB.

  1. from contract "newB": call initialize.

  2. from contract "newB": call owner. it should return the address who call the initialize function.

  3. from contract "newB": call updateName and then check by call name (getter). make sure it is changed.

that's all. hope it helps your problem.

1 Like

Thanks for the solution.
Btw, we already found about BeaconProxy and decided to go with it. It looks like a great method in which the upgrade part is also easy.

The code which we followed was this - https://gist.github.com/yurenju/ef4c901a48c523ac74bf942b50ab5108

1 Like