Deploy to a public testnet using ZeppelinOS 2.4

Following on from the Quick Start for ZeppelinOS 2.4

To deploy to a public testnet using Infura (if you aren’t running your own node)
First setup an account with Infura and create a project

Install truffle-hdwallet-provider to sign transactions for addresses derived from a 12 or 24 word mnemonic

npm i -D truffle-hdwallet-provider

Install dotenv to store your Infura Project ID and your development mnemonic.

npm i -D dotenv

network.js

Update network.js to configure HDWalletProvider and Ropsten network

require('dotenv').config();

const HDWalletProvider = require('truffle-hdwallet-provider');
const infuraProjectId = process.env.INFURA_PROJECT_ID;

module.exports = {
  networks: {
    development: {
      protocol: 'http',
      host: 'localhost',
      port: 8545,
      gas: 5000000,
      gasPrice: 5e9,
      networkId: '*',
    },
    ropsten: {
      provider: () => new HDWalletProvider(process.env.DEV_MNEMONIC, "https://ropsten.infura.io/v3/" + infuraProjectId),
      networkId: 3,       // Ropsten's id
    },
  },
};

Note: 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.

.gitignore

Configure .gitignore to ensure that values in .env don’t get accidentally committed.

# Dependency directory
node_modules

# local env variables
.env

# truffle build directory
build

.env

Configure .env with Infura Project ID and Dev Mnemonic

INFURA_PROJECT_ID="ENTER INFURA PROJECT ID"
DEV_MNEMONIC="ENTER 12 WORD SEED PHRASE"

Test Ether

Add test Ether to your account.
If you are using MetaMask you can request Ropsten Ether from the faucet
https://faucet.metamask.io/

If the account doesn’t have enough test Ether you will get the error insufficient funds for gas * price + value when you attempt to deploy

zos create

Deploy using ZeppelinOS interactive commands zos create

my-project$ npx zos create
✓ Compiled contracts with solc 0.5.10 (commit.5a6ea5b1)
? Pick a contract to instantiate Counter
? Pick a network ropsten
✓ Contract Counter deployed
All contracts have been deployed
? Do you want to call a function on the instance after creating it? No
✓ Setting everything up to create contract instances
✓ Instance created at 0xDAf9AE24D8DaFfC0631c7B5E90bA6360E950bE2A
0xDAf9AE24D8DaFfC0631c7B5E90bA6360E950bE2A

Interact with your contract

zos send-tx

my-project$ npx zos send-tx
? Pick a network ropsten
? Pick an instance Counter at 0xDAf9AE24D8DaFfC0631c7B5E90bA6360E950bE2A
? Select which function increase()
✓ Transaction successful. Transaction hash: 0x76b660be18a20f27fdb1697e4f315b5ec87b23c37ca21639514a8e0571c41cd4

zos call

my-project$ npx zos call
? Pick a network ropsten
? Pick an instance Counter at 0xDAf9AE24D8DaFfC0631c7B5E90bA6360E950bE2A
? Select which function value()
✓ Method 'value()' returned: 1
1

View your transactions on Etherscan

Search using your instance of Counter
Mine is 0xDAf9AE24D8DaFfC0631c7B5E90bA6360E950bE2A
https://ropsten.etherscan.io/

3 Likes

Thank you very much for this excellent tutorial, @abcoathup.

However, something is odd with the account, that will be used for deployment.

I have a little example project with a simple Counter contract.

In my .env File, i use the following mnemonics:

tooth spike smile swarm adapt history motion salt outdoor document observe cloth

When I import this mnemonic into MyCrypto (selected Network: Ropsten), the very first address will be 0x9dbFAFB5Edd1D69aCaC1C104C526C4ACDc20F3Ae. I have sent 0.99 ETH onto this address.

zos balance will confirm:

$ zos balance --network ropsten 0x9dbFAFB5Edd1D69aCaC1C104C526C4ACDc20F3Ae
Balance: 0.99 ETH
990000000000000000

But zos push --network ropsten is still running out of Gas.

$ zos push --network ropsten
Nothing to compile, all contracts are up to date.
:heavy_multiplication_x: Validating and deploying contract Counter
Counter deployment failed with error: insufficient funds for gas * price + value

This is my network.config:

require('dotenv').config();

const HDWalletProvider = require('truffle-hdwallet-provider');
const infuraProjectId = process.env.INFURA_PROJECT_ID;

module.exports = {
  networks: {
    development: {
      protocol: 'http',
      host: 'localhost',
      port: 8545,
      gas: 5000000,
      gasPrice: 5e9,
      networkId: '*',
    },
    ropsten: {
      provider: () => new HDWalletProvider(process.env.DEV_MNEMONIC, "https://ropsten.infura.io/v3/" + infuraProjectId),
      networkId: 3,       // Ropsten's id
    },
  },
};

I don’t know, which address is used by zos create but it is definitely not this account that MyCrypto gives me as the very first address from these mnemonics.

How did you solved this?

1 Like

I have found out my issue!

It is caused by incompatibilities in the HD derivation paths between MyCrypto and truffle-hdwallet-provider.

When we import a mnemonic into MyCrypto for Ropsten-Network, it derives the address with the following path: m/44'/1'/0'/0, while truffle-hdwallet-provider constantely is using m/44'/60'/0'/0/ no matter wich network will be used.

Therefor, I get a different address as the first address as it will be used by truffle-hdwallet-provider.

So, when I use also m/44'/60'/0'/0/ for address derivation, I end up with the following address:

0xC0306fe5c3E90025AD56832A4399670be51b3Eec
instead of
0x9dbFAFB5Edd1D69aCaC1C104C526C4ACDc20F3Ae

After I have send Test-Ether to 0xC0306fe5c3E90025AD56832A4399670be51b3Eec on Ropsten, the deployment works fine.

Fortunately the constructor of truffle-hdwallet-provider offers an argument containing the wallet_hdpath. So for using Ropster addresses properly with MyCrypto / MyEtherWallet, the following constructor helps:

ropsten: {
  provider: () => new HDWalletProvider(
    process.env.DEV_MNEMONIC, "https://ropsten.infura.io/v3/" + infuraProjectId, 
        0, 1, true, "m/44'/1'/0'/0/"
    ),
  networkId: 3,       // Ropsten's id
},

0 = start with first address
1 = derive only 1 addresses
true = sharedNonce (default)

“m/44’/1’/0’/0/” = BIP44 derivation path that is used for test networks (across all coins)

For debugging purposes, we can find out the address with the method “getAddresses()”:

const x = new HDWalletProvider(
  process.env.DEV_MNEMONIC, "https://ropsten.infura.io/v3/" + infuraProjectId, 0, 1,
  true, "m/44'/1'/0'/0/"
  )

console.log(x.getAddresses())
3 Likes

Awesome @itinance
Glad you could resolve. truffle-hdwallet-provider and MetaMask use the same derivation path so I hadn’t run into this issue.

1 Like