1

I've deployed a smart contract that inherits a few other contracts, simply:

contract A is B,C,D {}

Now, i have no issue with upgrades when it comes to upgrading A,B,C or D. My question is, what will happen if I add a new inheritance: E?

contract A is B,C,D,E {}

Will i simply be able to upgrade as normal? Where is the storage for E? Will i have to subtract from __gap in D? How would i go about this?

Edit: contract A contains no state variables.

Thank you, K

3
  • Storage for E is "under" D storage (In your case). And there is __gap between all of them to avoid memory collisions in any future updates of those contracts.
    – Sky
    Commented Oct 28, 2022 at 11:52
  • So a new storage is created for D? How does that not collide with storage of A
    – Koray Kaya
    Commented Oct 28, 2022 at 14:08
  • 1
    Well, my contract A has no state variables so seems like im Ok. I tried adding a state variable to A and hardhat instantly gave an error "Error: New storage layout is incompatible". So upgrades are no problem as long as A has no state vars.
    – Koray Kaya
    Commented Oct 28, 2022 at 14:24

2 Answers 2

1

Everything will work as intended.

Do not subtract the __gap

The __gap variable inside Upgradable SmartContracts is there precisely due to the reason you just mentioned (Inheritance)

Example from OpenZeppelin:

/**
 * @dev This empty reserved space is put in place to allow future versions to add new
 * variables without shifting down storage in the inheritance chain.
 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
 */
uint256[50] private __gap;

In short: __gap is there so we could update to the future versions of inherited contracts without their variables colliding (memory collision).

5
  • Hmm, interesting. Although this thread says that a new inheritance gets its slots before the inheriting class (A) and after the last inheritance (D). So E would be squeezed between D and A. Do we really not have to accommodate for these new state variables in E? ethereum.stackexchange.com/questions/63403/…
    – Koray Kaya
    Commented Oct 28, 2022 at 11:53
  • I did look at that thread, and it goes against everything I experienced in my upgradable SmartContracts. I guess the only solution here is to do some serious testing because I can't seem to find good enough documentation. Did you by any chance already try to test this?
    – Sky
    Commented Oct 28, 2022 at 12:12
  • I did try simply upgrading the contract and it worked (locally) with no complaints from hardhat. I'll put the contract through my unit tests next and see if something broke, I'll report back on that.
    – Koray Kaya
    Commented Oct 28, 2022 at 12:33
  • Thanks, I will do some tests too. Because if that thread is correct we should be getting memory collisions left and right.
    – Sky
    Commented Oct 28, 2022 at 12:35
  • Im not really encountering any obvious memory collisions, might actually take some effort to generate a collision. Im also reading up on this, heres something interesting i found in the meantime: "For contracts that use inheritance, the ordering of state variables is determined by the C3-linearized order of contracts starting with the most base-ward contract. If allowed by the above rules, state variables from different contracts do share the same storage slot." source:docs.soliditylang.org/en/v0.8.14/internals/…
    – Koray Kaya
    Commented Oct 28, 2022 at 13:17
1

I had done some extensive testings to I wanted to add another answer to clarify things.

In your first example:

contract A is B, C, D {}

The Storage will be arranged like this:

Storage B;
Storage C;
Storage D;
Storage A;

Now, if you want to Add E to your already written contract (And not cause memory collisions). this is how you go about doing it.

NOTE: A2 should be an empty contract, so it takes no slots. (Just in case), and thus can be discarded as it will have no storage.

Contract A2 is A, E { }

The storage will be arranged like this:

Storage B;
Storage C;
Storage D;
Storage A;
Storage E;

This will make it safe to upgrade.

If you do it the opposite way:

Contract A2 is E, A { }

E will be set on the top, and you will mess up the order of your storage slots.

Storage E;
Storage B;
Storage C;
Storage D;
Storage A;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.