truffle icon indicating copy to clipboard operation
truffle copied to clipboard

Provide a way to obtain dependency artifacts

Open frangio opened this issue 6 years ago • 25 comments

If someone wants to deploy a contract provided in OpenZeppelin they currently have to somehow put it in a place where Truffle will compile it. A common hack is to create an Imports.sol file in the project with contents import 'openzeppelin-solidity/contracts/...';. This is not ideal. OpenZeppelin should provide the artifacts in the npm package and Truffle should be able to create a contract abstraction from those artifacts.

This is an ugly API just to get a picture of the potential usage:

const ERC721Token = artifacts.dependency('openzeppelin-solidity').require('ERC721Token');

await ERC721Token.new(name, symbol);

frangio avatar Aug 31 '18 22:08 frangio

I believe @cag has been working on this on-and-off over at #1085

I'll leave this open for now because I'd like to consider that syntax, it's neat!

gnidan avatar Aug 31 '18 22:08 gnidan

FWIW I think #1095 is pretty migrations specific but there might be some overlap. I like that syntax too.

cgewecke avatar Aug 31 '18 23:08 cgewecke

Ah yes, that is neat, though I'd like to remark that there is already a syntax which is (somewhat) documented in the Truffle docs here:

var ENS = artifacts.require("ens/ENS");

and here:

var SimpleNameRegistry = artifacts.require("example-truffle-library/SimpleNameRegistry");

@frangio I think you should be able to take advantage of this immediately by simply publishing the build artifacts as part of the ZOS packages. Since openzeppelin-solidity is an unscoped package, this should work right now with the official release.

@gnidan @cgewecke There's overlap in that #1085 also has a changeset for truffle-resolver which enables the existing syntax for scoped packages on NPM (so, artifacts.require('@scope/pkg/Contract')).

cag avatar Sep 03 '18 15:09 cag

@cag Nice!! I can't believe I hadn't seen this. Very cool. We can close this issue then.

frangio avatar Sep 03 '18 22:09 frangio

this should be re-opened its not working if you didnt first import the artifacts in solidity it only works if you have the artifact in your local build/contracts i'm trying to use an external package contracts in tests and the following doesnt work:

artifacts.require("openzeppelin-solidity/TokenTimelock")

the error returned is:

Error: Could not find artifacts for openzeppelin-solidity/TokenTimelock from any sources

sirpy avatar Mar 08 '20 14:03 sirpy

@frangio

sirpy avatar May 13 '20 18:05 sirpy

This indeed does not seem fixed. I recall it had worked when I closed this issue, but I cannot get it to work now. The documentation link that was shared by @cag is actually for package management by EthPM, and the issue we observe is with NPM. The same section in the docs for NPM packages says that one should manually require the JSON file and build the contract.

frangio avatar May 13 '20 19:05 frangio

Hey @frangio, we're considering this issue and wanted to ask for a little more clarification. Is the case we are talking about where:

  • an npm package includes the built JSON files
  • your project does not import any of the Solidity sources

???

Let me know and we'll try and see what we can do. Thanks!

eggplantzzz avatar Jun 10 '20 18:06 eggplantzzz

Is the case we are talking about where:

  • an npm package includes the built JSON files
  • your project does not import any of the Solidity sources

Yeah, that's what it worked for originally IIRC. I've not used this pattern for a while though, since I tend to need contract instances available on local development chains, but there was a time I believe this did work.

cag avatar Jun 10 '20 18:06 cag

@eggplantzzz Yes that's exactly it.

frangio avatar Jun 10 '20 19:06 frangio

It sounds like this may be an issue with org-scoped packages. Looks like we have enough information here to investigate, so we will look into it!

fainashalts avatar Jun 17 '20 18:06 fainashalts

@eggplantzzz I've tested against the most recent release, and I don't think this correctly resolves node_modules directories in all cases. Please correct me if I'm wrong, but I think this works in the case where truffle is called from a directory where the path to the contract artifact is ./node_modules/@project/package/build/contracts/Contract.json. However, it seems that it does not work if the path to the contract artifact is located at ../node_modules/@project/package/build/contracts/Contract.json. Is this desired? We use a monorepo managed by lerna and the package we'd like to access is stored in the node_modules directory under root.

Thanks for all your work around this feature -- much appreciated!

mrice32 avatar Jul 21 '20 21:07 mrice32

+1 to mrice32. I am experiencing the same error on a Windows box where I am importing from ../node_modules/

NicWickman avatar Apr 05 '21 02:04 NicWickman

+1. Trying to import IUniswapV3Pool and still unable to do this. Variations i've tried so far

const IUniswapV3Pool = artifacts.require('@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool');
const IUniswapV3Pool = artifacts.require('@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json');
const IUniswapV3Pool = artifacts.require('node_modules/@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json');
const IUniswapV3Pool = artifacts.require('node_modules/@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool');
const IUniswapV3Pool = artifacts.require('node_modules/@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json');
const IUniswapV3Pool = artifacts.require('./node_modules/@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json');
const IUniswapV3Pool = artifacts.require('./node_modules/@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool');

Any suggestions?

Pzixel avatar Jan 22 '22 12:01 Pzixel

i've spend a couple of hours solving this and the closest I could get was:

const IUniswapV3Pool = artifacts.require('../node_modules/@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol:IUniswapV3Pool');

It still fails since true-case-path can't figure out .., which is the last check before I could get my artifacts.

I'm running this on Windows if it's of any importance


I think I'm back to Imports.sol for a while :(

Pzixel avatar Jan 22 '22 13:01 Pzixel

@Pzixel According to the Truffle documentation, you should be able to use something like:

/ Step 1: Get a contract into my application
var json = require("./build/contracts/MyContract.json");

// Step 2: Turn that contract into an abstraction I can use
var contract = require("@truffle/contract");
var MyContract = contract(json);

// Step 3: Provision the contract with a web3 provider
MyContract.setProvider(new Web3.providers.HttpProvider("http://127.0.0.1:8545"));

// Step 4: Use the contract!
MyContract.deployed().then(function(deployed) {
  return deployed.someFunction();
});

For your use case, something like the following should work:

const uniswapV3PoolJson = require("../node_modules/@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json");
const TruffleContract = require("@truffle/contract");
const uniswapV3PoolContract = TruffleContract(json);

jnsvd avatar Apr 08 '22 12:04 jnsvd

Hmm, I should take a look. Thanks!

Pzixel avatar Apr 08 '22 12:04 Pzixel

Hey everyone, we are doing maintenance and would like to know if people would still be interested in having a solution for the problems outlined above? Let us know and we'll try and get it spec'd out and triaged!

eggplantzzz avatar Jan 26 '23 18:01 eggplantzzz

Well I can only talk for myself but I'd like to have full NPM packages support. I didn't manage to get this working and then abandoned the idea, switching to just copy-pasting required files in projects. It would be nice if it weren't necessary.

Pzixel avatar Jan 26 '23 21:01 Pzixel

Can you please be more specific about what you might expect from a feature that has "fully NPM packages support"? Like, if this feature were implemented, what would be a nice user experience?

eggplantzzz avatar Jan 31 '23 18:01 eggplantzzz

I would imagine it as I write yarn add @uniswap/v3-core in terminal, and once I did it I can use it like this in code:

const IUniswapV3Pool = artifacts.require('@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool');

It didn't work this way the last time I checked, for reasons I've described above. I'm sorry if I'm mistaken and it is working now, but since issue is still opened I thought maybe it didn't get enough attention to be implemented.

Pzixel avatar Jan 31 '23 18:01 Pzixel

So actually if the npm package contains built Truffle artifacts (the JSON files that get created during truffle compile) you should be able to do artifacts.require(<stringContractName>) and it will work! Note that artifacts.require does not ingest Solidity, but rather these JSON files.

One of the things we'd have to deal with for a feature like this is the likely possibility that node_modules is huge. If the request was to compile everything in that folder it would potentially take forever to search through and compile everything. We tossed around a couple of ideas; for example we could allow a user to specify other directories (besides the contracts folder) for Truffle to search for Solidity source files. Right now I'm trying to figure out what a nice UX would be for a feature like this.

eggplantzzz avatar Jan 31 '23 20:01 eggplantzzz

@eggplantzzz

So actually if the npm package contains built Truffle artifacts (the JSON files that get created during truffle compile) you should be able to do artifacts.require(<stringContractName>) and it will work! Note that artifacts.require does not ingest Solidity, but rather these JSON files.

Including JSON files sounds great but it would be nice to specify out-of-project SOL files (as shown above) and include them as if they were part of the package.

One of the things we'd have to deal with for a feature like this is the likely possibility that node_modules is huge. If the request was to compile everything in that folder it would potentially take forever to search through and compile everything. We tossed around a couple of ideas; for example we could allow a user to specify other directories (besides the contracts folder) for Truffle to search for Solidity source files. Right now I'm trying to figure out what a nice UX would be for a feature like this.

But user doesn't specify directories, it does specify path to file, so there is no node_modules scan involved here, just a simple exists(file) check. Since there is no way to currently do it it won't be limiting to anyone if it was a requirement to specify path to file, not just a directory (if it is an option now for some contexts).

Pzixel avatar Jan 31 '23 20:01 Pzixel

I'm sorry, I don't quite follow what you are saying. My point is that if you require an artifact that is in node_modules, Truffle has no way of knowing where it is located in there. artifacts.require takes the contract name and not the path to an artifact as an argument. I'm not sure what happens if you specify a path in there; it might work but that is not the intended api.

eggplantzzz avatar Feb 02 '23 16:02 eggplantzzz

@eggplantzzz hmm, I'm sorry, I was sure it was an intended API which is quite useful when you have contract name clashes, so you can manually resolve which exact contract you do mean. If it's not desirable behavior then indeed I have no way to express what I was looking for.

Pzixel avatar Feb 02 '23 19:02 Pzixel