how to deal with contract versions and test smart contracts for upgrade compatibility

I try to use OpenZeppelin SDK to make my contracts upgradeable using the SimpleProxy approach. I need to test my contracts for upgrade compatibility (e.g prevent mistakes about unstructured storage during upgrading the contracts to a new version). According to OpenZeppelin docs, I can write these types of tests by something like this

const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');

const Box = artifacts.require('Box');
const BoxV2 = artifacts.require('BoxV2');

describe('upgrades', () => {
  it('works', async () => {
    const box = await deployProxy(Box, [42]);
    const box2 = await upgradeProxy(box.address, BoxV2);

    const value = await box2.value();
    assert.equal(value.toString(), '42');
  });
});

But in the above code, I must import both versions and this means I need to add the version number to the end of the contract's name and create a copy whenever I want to upgrade the contract. But what if I want to only modify the old contract and use a version control system like git?

If this is not possible, how to deal with these versions and files? when I want to upgrade a contract, need to update all of the imports and parent contracts for every child contract? If I want to put the latest version of each contract in a separate directory, do I need to update all import paths whenever upgrading a contract?

Sorry for my bad English.

Hi, welcome to the community! :wave:

It seems like you are using Truffle to have a test, and you want to compile some contracts with two different compiler versions, maybe you can change your truffle config like following:

module.exports = {
  compilers: {
    solc: {
      version: β€œpragma”
    }
  },
  // … the rest of your config goes here
};

For more details, please check
https://trufflesuite.com/blog/take-a-dive-into-truffle-5/#pragma-compilation

1 Like

You can seperate the two contracts if you have two solidity versions

I think you have misunderstood. My question is about contract versions (using proxy contract pattern and open zeppelin upgrade) for improvement or bug fixing in the future, not solidity version!
Assume I have this directory structure and AnotherContract inherits MyContract:

Contracts/
β”œβ”€ old_versions/
β”‚  β”œβ”€ MyContractV1.sol
β”‚  β”œβ”€ AnotherContractV1.sol
β”œβ”€ MyContractV2.sol
β”œβ”€ AnotherContractV2.sol

So I must import MyContractV2.sol in AnotherContractV2.sol file:

import "./MyContractV2.sol";

If I want to change AnotherContractV2.sol, I must make a copy from AnotherContractV2.sol and rename it to AnotherContractV3.sol. Also, move AnotherContractV2.sol to old_versions dir. The new directory structure is:

Contracts/
β”œβ”€ old_versions/
β”‚  β”œβ”€ MyContractV1.sol
β”‚  β”œβ”€ AnotherContractV1.sol
β”‚  β”œβ”€ AnotherContractV2.sol
β”œβ”€ MyContractV2.sol
β”œβ”€ AnotherContractV3.sol

Because of this, I need to update import paths.
If I want AnotherContractV2.sol to be still valid and compilable, the import path in this file must be updated to:

import "../MyContractV2.sol";

Upgrading MyContractV2.sol to MyContractV3.sol in the future needs even more code changing. This makes an extra effort for upgrading contracts to a new version, especially in bigger projects.

If I won't add a version number to the end of file names and keep only the last versions like this directory structure:

Contracts/
β”œβ”€ MyContract.sol
β”œβ”€ AnotherContract.sol

it means, I have no older versions and can't test upgrade compatibility in my test files. (In tests I need to deploy an old version, and upgrade it to the new version)

Ohhhhh, my bad, sorry for this.

I do not have a better solution, I use the same way like you mentioned above:

Contracts/
β”œβ”€ old_versions/
β”‚  β”œβ”€ MyContractV1.sol
β”‚  β”œβ”€ AnotherContractV1.sol
β”‚  β”œβ”€ AnotherContractV2.sol
β”œβ”€ MyContractV2.sol
β”œβ”€ AnotherContractV3.sol

And yes, it is a little hard to maintain, but it is clear.

If you do not want to change imported path, maybe you can keep all the files in the same directory:

Contracts/
β”œβ”€ MyContractV1.sol
β”œβ”€ AnotherContractV1.sol
β”œβ”€ AnotherContractV2.sol
β”œβ”€ MyContractV2.sol
β”œβ”€ AnotherContractV3.sol

But it is not clear.