Beacon proxy pattern, proxy state and initializers

Hey guys,

As described in a previous question I’m looking for a solution to manage a large number of smart contracts and especially upgrading them to include new functionality for all of them. This will also include not only adding new variables calculated by already existing ones but also initializing new variables after upgrading. So far the beacon proxy pattern seems to be the best, since I don’t have to iterate over each single proxy and change its implementation address. But what if I want to introduce a new variable and initalize it?
Here is an example:

pragma solidity >=0.4.22 <0.9.0;

contract BoxV1 {
    uint256 private a;
    uint256 private b;

    function store(uint256 _a, uint256 _b) public {
        a = _a;
        b = _b;
    }

    function add() public view returns (uint256) {
        return a + b;
    }

}

contract BoxV2 {
    uint256 private a;
    uint256 private b;
    uint256 private c;

    function initialize(uint256 _c) public {
        c = _c;
    }

    function store(uint256 _a, uint256 _b) public {
        a = _a;
        b = _b;
    }

    function add() public view returns (uint256) {
        return a + b + c;
    }

}

Both contracts act as implementation contracts and are deployed. So if I deploy a beacon proxy and store some values all is good. If I upgrade the beacon to the new implementation V2 I have to invoke the new initialize method(should only be called once) with a value in order to update the state of my proxy contract. Here are two things which come to my mind:

  1. After updating the beacon I will have again to iterate over all the deployed proxies in order to initialize them and set new values
  2. Since the initialize method should only be called once what will be the pattern for lets say a version 3? Do I add an initilize3 method which can again only be called once?

In general I like the beacon proxy pattern a lot but I think there are some limitations or am I misunderstanding some fundamental concepts?

1 Like

Hi @kiliw,

As state is stored in the proxy, if when you upgrade, you need to initialize state in an upgrade function, then you would need to call the upgrade function for each proxy.

Please note you should protect the upgrade function so that it can only be called once, and if it isn’t called in the same transaction as the upgrade, then it also needs to be protected so that only you can call it.

Whenever you have multiple proxies needing state to be initialized on upgrade then you will have the same problem.

You could look at how you could code this without having to call an upgrade function to initialize state. A trivial example could be as follows, that rather than having to initialize a value c, hardcode the value in the function:

function add() public view returns (uint256) {
   return a + b + 42;
}

To answer your questions:

Yes, you would need to set the state for each proxy

Yes, or something like version2Upgrade