hardhat icon indicating copy to clipboard operation
hardhat copied to clipboard

Target location for compiling imported library

Open abarmat opened this issue 4 years ago • 16 comments

Is it possible to map an imported library to a particular location as a compilation option in the hardhat config? I'm thinking something like:

    mappings: {
      '@openzeppelin/contracts/token/ERC20/IERC20.sol': 'Path/To/@openzeppelin/contracts/token/ERC20/IERC20.sol'
    },

abarmat avatar Nov 11 '20 23:11 abarmat

Hey @abarmat,

Not right now, but I'm curious to know more about your use-case. Is it to change the version of the library?

alcuadrado avatar Nov 11 '20 23:11 alcuadrado

I have this setup:

  1. Most of the contracts in a project using pragma solidity 0.7.x
  2. One particular contract needs to be compiled with 0.6.x and is importing files from a library that uses 0.6.x
  3. Both 1) and 2) imports @openzeppelin/contracts interfaces that use pragma 0.7.x

hardhat.config.ts setup with multiple compilers, one of 0.7.x and one for 0.6.x

Compilation of 1) works. Compilation of 2) fails because of imported interfaces not matching the solc version used to compile the contract.

I wondered if I could redefine those interfaces to be pragma >= 0.6.x < 0.8.x to be used by both 1) and 2)

abarmat avatar Nov 12 '20 02:11 abarmat

I don't think I understand.

Your remapped OZ file (Path/To/@openzeppelin/contracts/token/ERC20/IERC20.sol) would be the same IERC20.sol file but modified to have a compatible pragma, right? In that case, why don't you just import that?

Maybe a more detailed example would make it clearer.

fvictorio avatar Nov 12 '20 15:11 fvictorio

The issue I have is that the contract that is compiled using the 0.6.x version is importing a set of contracts through NPM all using the @openzeppelin/contracts/token/ERC20/IERC20.sol import. I can't change those imports without copying the contracts to my own repo and replacing them.

Example

- ContractA (0.7)
- ContractB (0.7)
    @openzeppelin/contracts/token/ERC20/IERC20.sol (0.7)
- ContractC (0.6)
    @ext-library/contracts/Contract.sol (0.6)
         @openzeppelin/contracts/token/ERC20/IERC20.sol (0.7)

As in my repo's package.json I'm installing @openzeppelin/contracts with pragma 0.7, when trying to compile ContractC it is failing as both imports read from the same target.

I was looking to do a remapping of IERC20.sol with a local version that does pragma >=0.6 < 0.8;

abarmat avatar Nov 12 '20 18:11 abarmat

Oh, I see.

I think it's unlikely we add this to the core of hardhat, but it would be interesting to make it easier to do this via a plugin (it probably can be done right now, but it seems cumbersome). I think the thing to do here is to allow the user to override the file resolution mechanism, so anyone can plug in how something like @openzeppelin/contracts/token/ERC20/IERC20.sol is resolved to a file.

fvictorio avatar Nov 12 '20 19:11 fvictorio

Yes, like when you define prefix=target in solc. I don't think this is a common use case but found this specific need while doing an integration. I solved it with a pre-compile task that replaces the imported file, I'll look into a plugin type solution.

Thank you.

abarmat avatar Nov 12 '20 19:11 abarmat

Just wanted to add that when using solc directly you can even add context to a remapping which would let you substitute that particular version of IERC20.sol only in Contract.sol while keeping the other files unaffected:

{
    ...
    "settings":
    {
        "remappings": ["@ext-library/contracts/Contract.sol:@openzeppelin/contracts/token/ERC20/IERC20.sol=Path/To/@openzeppelin/contracts/token/ERC20/IERC20.sol"],
    }
}

See Import Remapping in the docs.

It's already supported in Standard JSON so letting user specify remappings in his Hardhat config should be straighforward. The problem is that remappings affect import resolution which means that Hardhat would have to parse them and properly take them into account in the code that locates imported files on disk. The use case described in this issue is pretty niche so I can understand the team not wanting to complicate the code by adding this feature.

cameel avatar Jun 27 '21 00:06 cameel

Not right now, but I'm curious to know more about your use-case. Is it to change the version of the library?

I thought I'd add since it's been some time since this ticket was opened. With a lot of repos using dapptools/foundry the openzeppelin files are now found in lib.

Dapptools and the vscode plugins defer to remappings.txt so have no problem finding OZ source but hardhat won't look outside of node_modules for the OZ dependencies.

While dapptools is useful for testing in solidity, many of us still prefer our deployments and tasks make use of hardhat. Unfortunately, without the ability to do remapping like solc/dapptools/vs-code plugins do, hardhat and dapptools don't play nice in the same repo.

Only workaround is to copy paste OZ files which is a security anti-pattern (OZ themselves will call you out for "vendoring" files if they see that while auditing you).

merc-0 avatar Mar 17 '22 20:03 merc-0

I secnod @merc-0 's sentiment. I have a use case where I want to run both hardhat and foundry in the same repo, and the foundry code relies on a lib directory, but there is no way to tell hardhat to look in that folder. It would be great if hardhat could parse a remappings file just like foundry does. Here is what the remappings.txt file looks like in the root of the repoistory:

@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
ds-test/=lib/ds-test/src/
solmate/=lib/solmate/src/

br4e avatar Dec 07 '22 17:12 br4e

Hi folks. We are working on a hardhat-foundry plugin (https://github.com/NomicFoundation/hardhat/pull/3275) that should make these pain points go away.

That doesn't really fix the original issue, but hopefully it helps with what seems to be the underlying problem.

I hope we can release it next week. I'll try to remember to comment here when we do but, in case I forget, I recommend you watch our releases to be notified when we publish it.

fvictorio avatar Dec 08 '22 18:12 fvictorio

I don't know if it is related, but what is TASK_COMPILE_TRANSFORM_IMPORT_NAME for ?

I also need a more flexible compilation workflow: we want to import via npm different packages that has source code into one project that complies them all and does the deployment.

adjisb avatar Jun 09 '23 14:06 adjisb

@abarmat I think the jsdoc of the task explains it well, but let me know if you think it can be improved:

/**
 * This task transform the string literal in an import directive.
 * By default it does nothing, but it can be overriden by plugins.
 */

Right now, the only plugin that uses it is hardhat-foundry, which relies on that to have support for remappings.

fvictorio avatar Jun 09 '23 17:06 fvictorio

Our use case is compiling source code that came from other packages (via npm dependencies). This is our current solution. It is a little bit of a hack. Maybe the compilation workflow can be more reusable if the compilation subtasks use arguments instead of using hre.config.* ?

adjisb avatar Jun 14 '23 13:06 adjisb

@adjisb that is a good point. I'm not sure how much we can do that without introducing a breaking change, but I think it's doable. Do you want to open an issue suggesting that?

fvictorio avatar Jun 15 '23 07:06 fvictorio

https://github.com/NomicFoundation/hardhat/issues/4031

adjisb avatar Jun 15 '23 11:06 adjisb

@fvictorio Not sure if the intention of the original post is what I aim for .. or if the solution would be the same.

  • I have an "old" deployed contract A using @openzeppelin/contract v4.1
  • I am writing a new version B using @openzeppelin/contract v5.0 in a new repo (hardhat project)
  • ... as well as a migration contract M to migrated tokens from contract A to B
  • I want to run some integration tests, ideally using the original source in the orginal repo to make sure that I use the deployed code from contract A
  • I used git submodule add repo-A to import contract A code into the new repo and symlink the contract A code into my repo B contracts folder ... similar to this approach https://stackoverflow.com/questions/14831877/git-include-files-from-other-repositories
  • works all fine, but to replicate the exact contract A would still need to link to @openzeppelin/contract v4.1 , not v5 as in the new repo it is embedded into

I have still to look into foundry, but looks like its at least using submodules and may handle this already.

Would it work with hardhat as well, and would it follow an foundry re-mapping if I use the hardhat-foundry plugin

Any (better) idea to implement my approach .. or is there a better way to do that ?

SvenMeyer avatar Nov 13 '23 10:11 SvenMeyer