I'm working on a Foundry project, and I'm encountering issues with compiler versions when trying to deploy Uniswap V3 core and periphery contracts in a test contract(i.e. UniswapTest
shown below). The test contract uses solidity 0.8, but v3-core and v3-periphery use solidity 0.7.6
:
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;
pragma abicoder v2;
import { StdCheats } from "forge-std/StdCheats.sol";
import { IUniswapV3Factory } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
import { UniswapV3Factory } from "@uniswap/v3-core/contracts/UniswapV3Factory.sol";
import { INonfungiblePositionManager } from "@uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol";
import { NonfungiblePositionManager } from "@uniswap/v3-periphery/contracts/NonfungiblePositionManager.sol";
contract UniswapTest is StdCheats {
// Uniswap V3 contracts
IUniswapV3Factory internal uniswapV3Factory;
INonfungiblePositionManager internal nonfungiblePositionManager;
function setUp() public virtual {
uniswapV3Factory = new UniswapV3Factory();
nonfungiblePositionManager = new NonfungiblePositionManager(address(uniswapV3Factory), wethAddress);
}
function test_Uniswap() external {
// ... test uniswap
}
}
Attempting to forge compile
results the following truncated compilation error:
Discovered incompatible solidity versions in following
: test/Uniswap.t.sol (>=0.8.0) imports:
lib/v3-core/contracts/UniswapV3Factory.sol (=0.7.6)
it continues to list all other Uniswap.t.sol imports some of which are compatible with >=0.8.0 and some which are not as is the case with the UniswapV3Factory import above
Additionally if pragma solidity >=0.8.0 <0.9.0;
is used instead of pragma solidity >=0.8.0;
for the Uniswap.t.sol
file this results in the following compiler error:
Encountered invalid solc version in test/U.t.sol: Failed to parse solidity version >=0.8.0 <0.9.0: expected comma after patch version number, found '<'
How can I deploy contracts that require a solidity version that is incompatible with the test contract's solidity version?
This question is somewhat related to this one, however it does not have a satisfactory answer.
Best Answer
Instead of trying to import contracts that are incompatible with your test contract's version and then attempting to deploy those contracts using the
new
keyword, you can instead use the StdCheats#deployCode() function. If you want to deploy contract/s from an external library this way you'll have to first import those contract/s into one of your project files so that foundry compiles and generates the artifacts for these contracts in the output directory(i.e. the./out
folder by default). For example you can add these imports in a./test/mocks/Uniswap.sol
file and after compiling should observe the artifacts for these contracts in the./out
folder:Now in your test file you can deploy these contracts as follows:
However you may not want to deploy bytecode generated by foundry(given the configured compiler & optimizer settings) but instead deploy a specific bytecode for a contract for a reason such as the following:
In the context of Uniswap the
v3-periphery
repo has aPoolAddress
library with aPOOL_INIT_CODE_HASH
constant which is the keccak256 hash of theUniswapV3Pool
contract creation bytecode defined inv3-core
, and thePoolAddress
library is a dependency of many periphery contracts includingNonfungiblePositionManager
, so in order to have the periphery contracts function in your local foundry environment you'll want to deploy the exactUniswapV3Factory
bytecode(which contains theUniswapV3Pool
creation bytecode within it). The factory bytecode can be generated by runninghardhat compile
on theUniswap/v3-core
repo and should be visible in the./artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json
file. You can then copy and paste thebytecode
in to aPrecompiles
contract defined as follows:You can then deploy the
UniswapV3Factory
(with the exact bytecode as Uniswap's V3 Factory deployments) in your test contract as follows:NB:
NonfungibleTokenPositionDescriptor
contract which theNonfungiblePositionManager
contract requires in it's constructor parameters. This is for simplicity of the example(since it's a minor dependency), but also theNonfungibleTokenPositionDescriptor
contract has to be linked to theNFTDescriptor
library and there's currently no way to programmatically(i.e. using solidity) link a library to a contract usingStdCheats#deployCode()
in foundry.