- Published on
How to Connect an Ethereum dApp UI to an Existing Deployed Contract
- Authors
- Name
- Yair Mark
- @yairmark
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.
Problem - How Do We Link the UI/Server to Existing Contracts
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
andtransactionHash
fields for the network id you want.
- Specifically note the
In your UI you now need to symlink to
contracts
inside the savedbuild
directory.
In the above:
- The network id of
3
is Ropsten. The closer the number is to1
the closer it is to Ethereum mainnet so1
should be mainnet. - The network id of
5777
is Ganache. - You may have more or less
network
objects in your array depending on what yourtruffle-config.js
looks like.- You should have the same number of
networks
as you have in yourtruffle-config.js
. - For the sake of your UI you only need the network that you intend the UI to connect to.
- You should have the same number of
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.
- This will give you a fresh new
- Go to the
networks
section of the contract/s you need and change theaddress
andtransactionHash
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.
- Ensure that you use the correct contract address corresponding to the correct network number e.g.
- Save this
build
directory with the modified files somewhere. - Symlink the
build/contracts
folder into yourui/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 -