Common problems developing Ethereum dApps with Metamask

Common problems developing Ethereum dApps with Metamask

After I wrote a tutorial for building an Ethereum DApp with Integrated Web3 Monitoring, I received many questions both publicly and privately. This post collects some of those answers to aid you as you develop Ethereum dApps.

Not connected to a network

First, understand the logic for connecting your DApp to a blockchain network. The example, getWeb3.js implements one of the common patterns for connecting to a web3 network.

It checks to see if there is a web3 object already injected in the global scope. If not, the code tries to connect to truffle’s test network that is running locally at http://127.0.0.1:9545.

In production, many of the users of your dApp may be using Metamask, Mist or other Ethereum client which injects the web3 object automatically and connects to a local or remote Ethereum node.

So if you already have Metamask running, Metamask will already inject a web3 object into the global scope. Since the tutorial example is using truffle’s test network, then you may want to turn off the Metamask extension for now.

Getting the example to work with Metamask

There are two things you need to figure out:

  • What network do you plan to connect to with Metamask? If it is another test network fine. Be sure you have all the data needed.
  • Are your contracts deployed to the network that Metamask will connect to.

Deploy contracts to a different network

In the tutorial example, the contracts are deployed to the truffle development network which is created when you run truffle develop. The node is available at http://127.0.0.1:9545.

If you want to deploy to another network, for example, ganach, then you would need to modify the truffle.js file.

module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!

  networks: {
    ganache: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*"
    },
    development: {
      host: "127.0.0.1",
      port: 9545,
      network_id: "*" // Match any network id
    }
  }
};

You then need to run

truffle compile

truffle migrate --network ganache

Of course, replace the ganache settings with the name and settings of your choice.

How do I find the address of the smart contract I just deployed

There several ways.

First, when you run the migrate command to deploy the contract, the address is shown in the command line output.

Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0xbf9932f55ba158d95f4ed41632cf2558c9ce63a63591e6cf45a5b58db435a598
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Replacing SimpleStorage...
  ... 0xa19fe7f1c68b20bc7c58ad270cee58767248eef7fa7e58ad847855582f8f1212
  SimpleStorage: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
  ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...

Notice, the line for: SimpleStorage: 0x345ca3e014aaf5dca488057592ee47305d9b3e10

Second way: if you open up the JSON artifact at SimpleStorage.json, you’ll see the data regarding the address and network it is deployed to.

  "networks": {
    "4447": {
      "events": {},
      "links": {},
      "address": "0x345ca3e014aaf5dca488057592ee47305d9b3e10",
      "transactionHash": "0xa19fe7f1c68b20bc7c58ad270cee58767248eef7fa7e58ad847855582f8f1212"
    }
  },

Third way, in your dApp code, you can get the address if you have an instance of the deployed contract.

const simpleStorage = contract(SimpleStorageContract)
simpleStorage.setProvider(this.state.web3.currentProvider)

simpleStorage.deployed().then((instance) => {
// now you have the instance of the deployed contract, you can get the address.
  console.log(instance.address)
});

Recipient address is not a contract address

When you switch to a different network, you will need to deploy the contracts to the right network; however, you may get an error like below when you try to run migrate again.

 Attempting to run transaction which calls a contract function, but recipient address 0x8cdaf0cd259887258bc13a92c0a6da92698644c0 is not a contract address

To remedy, delete the JSON files under build/contracts, because these JSON files have meta data regarding where it is deployed to.

Another solution is to try truffle migrate --reset.

I initiated a transaction, but I am not seeing any changes

This can happen after switching network to MetaMask, and connected.

For every transaction that spends ether, Metamask will explicitly ask for user’s permission to allow the transaction. Sometimes the permission popup is hidden. If this happens, open the Metamask popup manually and grant the permission for the transaction.

In the tutorial example, the first transaction is trying to set the storage, which costs gas. If you don’t see the storage being set set to 5, click on Metamask to see if it is waiting for your approval before initiating the first transaction.

Metamask nonce problem: Error: the tx doesn’t have the correct nonce.

If you are developing and testing with Metamask, sometimes you’ll see an error like this:

message:"Error: Error: [ethjs-rpc] rpc error with payload {"id":8318498190067,"jsonrpc":"2.0","params":["0xf88914843b9aca0082f3ff94345ca3e014aaf5dca488057592ee47305d9b3e1080a460fe47b10000000000000000000000000000000000000000000000000000000000000019822d46a0a3ecf94d503161fbbf914c90c0b18fedf86a382b126314d71b5ec11bf0985b92a0468281983291f396cd02c80f4428898e51d258f57548ddf483da08962a02ad22"],"method":"eth_sendRawTransaction"} Error: Error: the tx doesn't have the correct nonce. account has nonce of: 4 tx has nonce of: 20

This is caused when you restart your test network or restarting from another test network. The cached transaction history in Metamask does not match the network’s history.

To fix this issue, open the “settings” tab in Metamask, and click reset for the network.

I changed the web3 provider, but I don’t see events captured by Moesif anymore.

By default, Moesif Browser JS SDK tries to capture data at the XMLHttpRequest layer. If a global web3 object is detected such as the web3 object injected by Metamask or Mist, Moesif will instrument the web3 object.

There are advanced scenarios where you decides to modify the global web3 object such as creating a new web3 object or modifying the underlying provider. A For example, your dApp lets users switch networks or providers.

For these cases you need to pass the new web3 object to Moesif to ensure it’s properly instrumented which can be done via the useWeb3() method.

moesif.useWeb3(myNewWeb3);

In Moesif, I see duplicated events

As mentioned, Moesif Browser JS SDK captures data both via XMLHttpRequest and web3.

This can happen if your underlying provider also uses XMLHttpRequest such as the HTTPProvider. This is ok and expected.

All events captured at the web3 layer have an additional metadata field called _web3 which stores information about which web3 is used.

Moesif is the most advanced API Analytics platform, supporting REST, GraphQL, Web3 Json-RPC and more. Thousands of platform companies leverage Moesif for debugging, monitoring and discovering insights.

Learn More