Contract state and splitting code into different files

I have a question about structuring the files for a contract in general and also about how that would work with the Upgrade pattern, if it is a good idea in the first place…

I’m working on a contract and wanted to separate concerns and re-inherit them into a single contract, but they all access the same state.

So therefore I was wondering if it is not an advisable thing to do to place all the state in the base-most contract and inherit everything else out of that before finally inheriting everything into the final contract.

Is that a bad idea?

If it is’t, would this be a good idea to manage the state for working with the Upgrade pattern?

Would the ZOS tool be able to detect state changes between versions if they were built in that fashion?

1 Like

Hi @realisation,

You can have state variables in whichever contract you choose, but you need to be careful when adding state in upgraded versions.

I suggest having a look at the Modifying Your Contracts section in the documentation:
https://docs.openzeppelin.com/sdk/2.5/writing-contracts#modifying-your-contracts

You may also want to try it out in a test project.
I used the following based on the Base and Child contracts in the documentation.

Base.sol

pragma solidity ^0.5.0;

contract Base {
    uint256 base1;

    function setBase1(uint256 b1) public {
        base1 = b1;
    }
}

Child.sol

pragma solidity ^0.5.0;

import "./Base.sol";

contract Child is Base {
    uint256 child;

    function setChild1(uint256 c) public {
        child = c;
    }
}

Create Child contract

$ npx oz create
Nothing to compile, all contracts are up to date.
? Pick a contract to instantiate Child
? Pick a network development
✓ Added contract Child
✓ Contract Child deployed
All contracts have been deployed
? Do you want to call a function on the instance after creating it? No
✓ Setting everything up to create contract instances
✓ Instance created at 0xD833215cBcc3f914bD1C9ece3EE7BF8B14f841bb
0xD833215cBcc3f914bD1C9ece3EE7BF8B14f841bb

Base.sol upgraded to add state variable

Add state variable to Base which results in base2 using the slot that child had in the previous version.

pragma solidity ^0.5.0;

contract Base {
    uint256 base1;
    uint256 base2;

    function setBase1(uint256 b1) public {
        base1 = b1;
    }

    function setBase2(uint256 b2) public {
        base2 = b2;
    }
}

Upgrade Child contract

OpenZeppelin SDK shows a warning about the new variable being inserted.

$ npx oz upgrade
? Pick a network development
Nothing to compile, all contracts are up to date.
- New variable 'uint256 base2' was inserted in contract Base in contracts/Base.sol:1. You should only add new variables at the end of your contract.
See https://docs.openzeppelin.com/sdk/2.5/writing_contracts.html#modifying-your-contracts for more info.
✓ Contract Child deployed
All contracts have been deployed
? Which instances would you like to upgrade? All instances
✓ Instance upgraded at 0xD833215cBcc3f914bD1C9ece3EE7BF8B14f841bb. Transaction receipt: 0x1516650e3bbcde71df8df91e9b5dd32c7afaf22e8de54718b7b47b8d0553c9f5
✓ Instance at 0xD833215cBcc3f914bD1C9ece3EE7BF8B14f841bb upgraded

So this sounds like a fairly common way of architecting contracts before thinking about the Upgrade pattern?

1 Like

Hi @realisation,

I am not sure which way you are referring to. Do you mind sharing a bit more detail?

I am just talking about the file system architcture ethereum contract source files

1 Like

Hi @realisation,

If the question is, is it ok to put all of the state in the base class, then yes you can. You need to be careful when adding state in upgraded versions as per the documentation: https://docs.openzeppelin.com/sdk/2.5/writing-contracts#modifying-your-contracts