forge-multi-version icon indicating copy to clipboard operation
forge-multi-version copied to clipboard

Using forge with multiple solc versions

Using forge with multiple solc versions

This is a proof of concept to enable multi-version Solidity projects with Foundry.

This example uses Solidity 0.6.12 and 0.8.14, but in theory it could work for any two or more versions.

Rationale

  • Use Foundry built-in profiles for different Solidity versions. Use the default profile for the "main" version (0.8.14 in this case).
  • Have separate src directories for each version.
  • Have separate lib directories for each version, but allow the non-default versions to pull compatible dependencies from the default one.
  • Test files and Solidity scripts go into the src directories and not in separate test and script ones.

Usage

Compile the non-default versions first:

FOUNDRY_PROFILE=0_6_x forge build

Compile the default version last:

forge build

⚠️ WARNING: forge will overwrite the compiled files in out/ for whichever contracts that were compiled with FOUNDRY_PROFILE=0_6_x with the compiled files using the default profile. In other words, any contracts that were accessible with the 0.6.x compiler will be overwritten by the default profile using Solidity 0.8.x if the commands are run in the order above. Keep that in mind if you are using this approach to deploy contracts, you might end up submitting the bytecode generated by a different compiler version than what you intended.


To reference contracts from compiled with versions, use the getCode() cheat code.

pragma solidity ^0.8.14;

import "forge-std/Test.sol";

contract MyTest is Test {
    Contract myContract = new Contract();

    function testDeployContractWithAnotherVersion() public {
        address anotherAddress = deployCode("Contract6.sol:Contract6");

        // Different compiler versions will produce different bytecodes
        assertTrue(keccak256(address(myContract).code) != keccak256(anotherAddress.code)); // [PASS]
    }
}