truffle
truffle copied to clipboard
Provide a way to obtain dependency artifacts
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);
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!
FWIW I think #1095 is pretty migrations specific but there might be some overlap. I like that syntax too.
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 Nice!! I can't believe I hadn't seen this. Very cool. We can close this issue then.
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
@frangio
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.
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!
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.
@eggplantzzz Yes that's exactly it.
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!
@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!
+1 to mrice32. I am experiencing the same error on a Windows box where I am importing from ../node_modules/
+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?
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 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);
Hmm, I should take a look. Thanks!
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!
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.
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?
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.
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
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).
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 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.