Deploy contracts to a public network
Note: To deploy OpenZeppelin SDK upgradeable contracts to a public network please use Deploy your contracts to a public network
This guide deploys a simple ERC20 token using OpenZeppelin Contracts.
We will use the Ropsten public test network for this guide, though you could use other public test networks.
Ethereum public test networks include:
- Ropsten (Proof of Work, multi-client, ~ 15 second blocktimes);
- Rinkeby (Proof of Authority, geth client only, 15 second blocktimes);
- Kovan (Proof of Authority, parity client only, 4 second blocktimes);
- Goerli (Proof of Authority, multi-client, 15 second blocktimes)
Setup
We’ll first create a node.js project in a new directory. Head over to a terminal and run:
mkdir my-project
cd my-project
npm init -y
Then install Truffle locally
Note: This guide uses npx to run npm packages locally, though you could install packages such as Truffle globally.
npm i truffle
Let’s now initialize a Truffle project. We will be advised that the directory is non-empty, we want to proceed anyway, so press Y for Yes.
npx truffle init
Install OpenZeppelin Contracts as we are using this for our token
npm i @openzeppelin/contracts
Create Contract
We will create an ERC20 token. See the OpenZeppelin ERC20 documentation for more details.
Save the following simple ERC20 contract to SimpleToken.sol
in the contracts
directory.
pragma solidity ^0.5.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
/**
* @title SimpleToken
* @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
* Note they can later distribute these tokens as they wish using `transfer` and other
* `ERC20` functions.
*/
contract SimpleToken is ERC20, ERC20Detailed {
/**
* @dev Constructor that gives msg.sender all of existing tokens.
*/
constructor () public ERC20Detailed("SimpleToken", "SIM", 18) {
_mint(msg.sender, 1000 * (10 ** uint256(decimals())));
}
}
Create Migrations
Save the following migrations script as 2_deploy_token.js
in the migrations
directory.
const SimpleToken = artifacts.require("SimpleToken");
module.exports = function(deployer) {
deployer.deploy(SimpleToken);
};
Test account
We use mnemonics to generate a 12 word mnemonic. Run the following to generate a mnemonic for testing purposes:
npx mnemonics
Create Infura account
We will use Infura to interact with public Ethereum nodes (if you are not running your own nodes). Infura Core is free to use. Follow the instructions on the Infura website to sign up and create a new project.
Install dotenv
We will use dotenv to store your Infura Project ID and your development mnemonic. Run the following in your project folder to install as a development dependency:
$ npm install --save-dev dotenv
Configure .gitignore
We configure .gitignore to ensure that values in .env
(Infura Project ID and development mnemonic) don’t get accidentally committed to our source code repository. Create a .gitignore
file in your project folder with the following contents:
# Dependency directory
node_modules
# local env variables
.env
# truffle build directory
build
Configure .env
We configure .env
to store our Infura Project ID and development Mnemonic used for testing. Create a .env
file in your project folder with the following contents, using the Infura Project ID and the development Mnemonic you created earlier:
INFURA_PROJECT_ID="ENTER INFURA PROJECT ID"
DEV_MNEMONIC="ENTER 12 WORD SEED PHRASE"
Install HD Wallet Provider
We will use @truffle/hdwallet-provider to sign transactions for addresses derived from a 12 or 24 word mnemonic. Run the following in your project folder to install as a development dependency:
$ npm install --save-dev @truffle/hdwallet-provider
Configure truffle-config.js
Update truffle-config.js
to configure additional networks to connect to. We require dotenv
and @truffle/hdwallet-provider
and then specify the provider for the network using the Infura Project ID and development mnemonic. Your truffle-config.js
should look like the following:
require('dotenv').config();
const HDWalletProvider = require('@truffle/hdwallet-provider');
const infuraProjectId = process.env.INFURA_PROJECT_ID;
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
// Another network with more advanced options...
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send txs from (default: accounts[0])
// websockets: true // Enable EventEmitter interface for web3 (default: false)
// },
// Useful for deploying to a public network.
// NB: It's important to wrap the provider as a function.
ropsten: {
provider: () => new HDWalletProvider(process.env.DEV_MNEMONIC, "https://ropsten.infura.io/v3/" + infuraProjectId),
network_id: 3, // Ropsten's id
gas: 5500000, // Ropsten has a lower block limit than mainnet
confirmations: 2, // # of confs to wait between deployments. (default: 0)
timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
},
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
// version: "0.5.1", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
// enabled: false,
// runs: 200
// },
// evmVersion: "byzantium"
// }
}
}
}
If you want to use an account other than the first account generated by the mnemonic then you can provide the account index (zero based) as the third parameter to HDWalletProvider. See the truffle tutorial for details: https://www.trufflesuite.com/tutorials/using-infura-custom-provider
To expose additional addresses from the same mnemonic set num_addresses
in your config. To change the derivation path to derive addresses set wallet_hdpath
in your config. See the @truffle/hdwallet-provider repository for details.
Fund test account
Add test Ether to the account that you want to use e.g. the default/first account derived from the mnemonic. You can add funds using a faucet (e.g. https://faucet.ropsten.be). If the account doesn’t have enough test Ether when you attempt to deploy, you will get the error deployment failed with error: insufficient funds for gas * price + value
.
You can also import the 12 word seed phrase into MetaMask and then you can request test Ether from the MetaMask faucet. (https://faucet.metamask.io)
Deploy contract
We deploy our contract using Truffle by running truffle migrate
. Specify the network you want to use.
$ npx truffle migrate --network ropsten
Interact
We can interact with our contract using Truffle Console.
$ truffle console --network ropsten
truffle(ropsten)> token = await SimpleToken.deployed()
undefined
truffle(ropsten)> await token.name()
'SimpleToken'
truffle(ropsten)> (await token.totalSupply()).toString()
'1000000000000000000000'
View your transactions on a blockchain explorer
You can view your transactions on a blockchain explorer that supports the network you used. For instance, Etherscan supports Ropsten at https://ropsten.etherscan.io/. You can search Etherscan using the contract address.
You can also verify your smart contract on Etherscan using the following:
My contract can be found here:
https://ropsten.etherscan.io/address/0xF2413EF167058A730D76aAbEA066dd420F6A2AB6#code
That’s it! You now know how to deploy a simple ERC20 token to a public network and interact with it.