Package Management via EthPM
EthPM is the new Package Registry for Ethereum. It follows the ERC190 spec for publishing and consuming smart contract packages, and has gained wide support from many diverse Ethereum development tools. To show our support, we've integrated the Ethereum Package Registry directly into Truffle.
Installing a package
Installing a package from EthPM is nearly as easy as installing a package via NPM. You can simply run the following command:
$ truffle install <package name>
You can also install a package at a specific version:
$ truffle install <package name>@<version>
Like NPM, EthPM versions follow semver. You can find a list of all available packages at the Ethereum Package Registry.
Installing Dependencies
Your project can define an ethpm.json
file that among other things can pin your project to specific dependencies and versions. To install all dependencies listed in the ethpm.json
file, run:
$ truffle install
For more details on the ethpm.json
file, see the package configuration below.
Consuming installed contracts
Installed packages will be placed in the installed_contracts
directory within your project folder. If no installed_contracts
directory exists it'll be created for you. You should treat this folder like you treat the node_modules
folder with NPM -- that is, you shouldn't edit the contents inside unless you know what you're doing. :)
Installed packages can be consumed within your tests, migrations and solidity contract files by import
'ing or require
'ing that package and contract by name. For example, the following Solidity contract would import the owned.sol
file from the owned
package:
pragma solidity ^0.4.2;
import "owned/owned.sol";
contract MyContract is owned {
// ...
}
Similarly, the following migration file would use the ENS.sol
contract from the ens
package:
File: ./migrations/2_deploy_contracts.js
var ENS = artifacts.require("ens/ENS");
var MyContract = artifacts.require("MyContract");
module.exports = function(deployer) {
// Only deploy ENS if there's not already an address already.
// i.e., don't deploy if we're using the canonical ENS address,
// but do deploy it if we're on a test network and ENS doesn't exist.
deployer.deploy(ENS, {overwrite: false}).then(function() {
return deployer.deploy(MyContract, ENS.address);
});
};
Note that in the migration above, we consume the ens
package and deploy the ENS contract conditionally based on whether or not ENS already has an address set. This is a fancy trick provided to you by the deployer that makes it much easier to write migrations dependent on the the existence of network artifacts. In this case, if we were running our migrations on the Ropsten network, this migration wouldn't deploy the ENS
contract because (at the time of this writing) Ropsten is where the canonical ENS
contract exists -- we wouldn't want to deploy our own. But if we were running our migrations against a different network, or a test network perhaps, then we'd want to deploy the ENS
contract so that we have a dependency contract to work with.
Publishing your own package
Publishing your own package is as straightforward as installing, but like NPM, requires a bit more configuration.
Ropsten, Ropsten, Ropsten
The Ethereum Package Registry currently exists on the Ropsten test network. To publish to the registry, we need to set up our own Ropsten configuration because we'll be making transactions that need to be signed.
In this example, we'll use Infura for publishing packages along with the truffle-hdwallet-provider
NPM module and a 12-word hd-wallet mnemonic that represents our Ethereum address on the Ropsten network. First, install the truffle-hdwallet-provider
via NPM within your project directory:
$ npm install truffle-hdwallet-provider --save
Then edit your configuration to add the ropsten
network using your 12-word mnemonic:
File: truffle.js
var HDWalletProvider = require("truffle-hdwallet-provider");
// 12-word mnemonic
var mnemonic = "opinion destroy betray ...";
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*" // Match any network id
},
ropsten: {
provider: new HDWalletProvider(mnemonic, "https://ropsten.infura.io/"),
network_id: 3 // official id of the ropsten network
}
}
};
Package configuration
Like NPM, configuration options for EthPM go in a separate JSON file called ethpm.json
. This file sits alongside your Truffle configuration and gives Truffle all the information it needs to publish your package. You can see a full list of available options in the Configuration section.
File: ethpm.json
{
"package_name": "adder",
"version": "0.0.3",
"description": "Simple contract to add two numbers",
"authors": [
"Tim Coulter <tim.coulter@consensys.net>"
],
"keywords": [
"ethereum",
"addition"
],
"dependencies": {
"owned": "^0.0.1"
},
"license": "MIT"
}
Command
After you have your configuration settled, publishing is a snap:
$ truffle publish
You'll see output similar to that below, with confirmation that your package was published successfully.
$ truffle publish
Gathering contracts...
Finding publishable artifacts...
Uploading sources and publishing to registry...
+ adder@0.0.3
Before publishing
When using a network like the default develop
network that's configured to match any Ethereum client (like Ganache or Truffle Develop), you're bound to have network artifacts lying around that you don't want published. Before publishing your package, consider running the following command to remove any extraneous network artifacts:
$ truffle networks --clean
See the command reference for more information.