Using storage gaps with `hardhat-upgrades`

Hi there,
I so similar questions on the forum, but did not find a solution yet.

I have to upgrade storage layout in my contract(which is already deployed on mainnet)

Current layout

uint256[50] private __gap;

New layout

address private _forwarder;
uint256[49] private __gap;

Command

await upgrades.upgradeProxy(contract.address, ContractV2)

Error

Error: New storage layout is incompatible

contracts/metatx/ERC2771Context.sol:21: Inserted `_forwarder`
  > New variables should be placed after all existing inherited variables

contracts/metatx/ERC2771Context.sol:85: Upgraded `__gap` to an incompatible type
  - Bad array resize from 50 to 49
    Size cannot decrease

Dependencies

  • "@openzeppelin/contracts-upgradeable": "^4.1.0",
  • "@openzeppelin/hardhat-upgrades": "^1.8.2",

As far as I understand hardhat-upgrades does not support it yet.
Is there a way to do this?

Hi @aquiladev. I'm sorry this is not natively supported by the plugin yet. I also don't want to rush to implement this feature for you because it's sensitive and would want to review it and test it thoroughly.

For your particular use case, I would recommend manually modifying the network file under .openzeppelin to include this variable you want to add, as if it had been included in your previous version.

I realize this is a little tricky, if you can share a repository link I can help you figure out the exact change you should make.

I think I've got your point, thanks

Hi @frangio how should i manually modify file .openzeppelin/unknown-31337.json and still have tests run? currently what happens is that the tests first deploy the first version, which resets unknown-31337.json to have __gap be of size 50 and then the test which upgrades fails as it expects it to be 49. any suggestions would be very helpful. thanks

@Mister_Singh An alternative would be to test with a modified copy of your first version for now, where the modified copy already has the variable you want to add.

Support for storage gaps is planned in https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/276

Hi @frangio, and @aquiladev, I got the same issue with truffle upgrades.
Added a new variable as address type, getting this issue. if the plugin does not support it, how can I do it manually?
New variables should be placed after all existing inherited variables
Upgraded __gap to an incompatible type

  • Bad storage gap resize from 46 to 45
    Size decrease must match with corresponding variable inserts

Storage gaps is supported in the Hardhat and Truffle upgrades plugins now. See https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps for how to use them.

@skyclean906 Can you provide an example of how your variables are defined in the old and new versions of your contract? The error indicates that the gap array size was not adjusted correctly in the new version.

Hi @ericglau, Thanks for your quick help.
// Old version
....
uint256[46] private __gap;
// New version
....
address public royaltyRegister;
uint256[45] private __gap;
but I'm also getting the error.
"New variables should be placed after all existing inherited variables"
And the error
Upgraded __gap to an incompatible type

  • Bad storage gap resize from 46 to 45
    Size decrease must match with corresponding variable inserts

I couldn't find a mistake based on this link.

Also, I added a new function, it can affect something?