Published on

How to Connect an Ethereum dApp UI to an Existing Deployed Contract

Authors

Basic dApp Structure

When working with an Ethereum app like Cryptokitties for example, from a conceptual level there are two parts:

  • The deployed blockchain code AKA smart contracts.
  • The UI / server that interacts with those deployed contracts using some web3 library.

Let us pretend we have the model where we use a UI and not a server to connect to the contracts - we use web3.js.

One issue that is not clear with Truffle is: how do you connect your UI to existing smart contracts without doing a new migration?

Say for example we have one mono repo with both the contract code and the UI as below:

<projectRoot>
             -> contracts
                         -> build
                                 -> contracts
                                             -> Contract1.json
                                             ...
                                             -> ContractN.json
                         -> contracts
                                 -> Contract1.sol
                                 -> ...
                                 -> ContractN.sol
             -> ui
                         -> package.json
                         -> public
                         -> src
                             -> index.js
                             -> App.js
                             ...
                             -> contracts [symlink to '../../contracts/build/contracts']

In the drizzle tutorial they recommend either symlinking to the contracts build directory (e.g. ln -s ../../contracts/build/contracts contracts from inside the ui/src directory) if you are using the same project or to export the contracts in your truffle-config.js as described here.

The problem is once you have migrated your contracts how do you run the UI from anywhere and refer to the same deployed contracts?

Solutions

Option 1 - Save Migration Build Directory

After quite a bit of searching it turns out there is a solution:

  • When you first migrate the contracts using truffle migrate --environment targetEnvironmentName truffle will compile the contracts (under <contractsRoot>/build/contracts) and deploy those.
  • In the compiled contract JSON there will be a networks section that includes something like the below:
  "networks": {
    "3": {
      "events": {},
      "links": {},
      "address": "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d",
      "transactionHash": "0x1cdc7bdb4fedc48379341ef56fcfbc27a8c65723d236463e39b576c862e6fd1e"
    },
    "5777": {
      "events": {},
      "links": {},
      "address": "0xE94327D07Fc17907b4DB788E5aDf2ed424adDff6",
      "transactionHash": "0xe84e8de06546c693a6a9aef255a56ecc5d93f2ee0c2c6fd74bd0d209bff591fb"
    }
  },
  • You need to save the build directory that was generated.

    • Specifically note the address and transactionHash fields for the network id you want.
  • In your UI you now need to symlink to contracts inside the saved build directory.

In the above:

  • The network id of 3 is Ropsten. The closer the number is to 1 the closer it is to Ethereum mainnet so 1 should be mainnet.
  • The network id of 5777 is Ganache.
  • You may have more or less network objects in your array depending on what your truffle-config.js looks like.
    • You should have the same number of networks as you have in your truffle-config.js.
    • For the sake of your UI you only need the network that you intend the UI to connect to.

Now when you run your UI and switch to Ropsten in MetaMask you will be pointing to the correct contract address you originally deployed.

Option 2 - Use Deployed address and transactionHash

If you do not have your build directory from your original migration and your migration process you can then do the following:

  • Run truffle compile.
    • This will give you a fresh new build directory.
    • The networks section will not be exactly correct.
  • Go to the networks section of the contract/s you need and change the address and transactionHash to use the ones from your deployed contracts.
    • Ensure that you use the correct contract address corresponding to the correct network number e.g. 2 is Ropsten.
  • Save this build directory with the modified files somewhere.
  • Symlink the build/contracts folder into your ui/src folder.

Make this Process Less Cumbersome for Dev vs Testnet/Mainnet

To help make this process a bit easier if you use a makefile or something similar in the root of your project you can easily write a script to change the symlink on the fly depending on whether you are deving locally or this is being built for Ropsten or Mainnet. For example with the project structure above I would have a makefile as follows:

symlink-to-ropsten: ## Update the UIs contract symlink to point to the newest Ropsten build
    cd ui/src && (rm contracts || true) && ln -s ../../contracts/deploy/buildRopsten-11-Apr-2019/contracts contracts && cd -
symlink-to-local: ## Update the UIs contract symlink to point to the newest Local build
    cd ui/src && (rm contracts || true) && ln -s ../../contracts/build/contracts contracts && cd -