Hey, a very warm welcome from my side in this decentralized application development cheatsheet.π
In this cheatsheet, I'll follow the complete begineer steps to develop, compile, migrate the smart contract and then use it in frontend framework. Finally, we'll deploy our decentralized application to the web.π
- Setting Backend API & Metamask
- Create an App with Backend API
- Download Truffle
- Create a Truffle project
- Install HDWalletProvider
- Write your Contract
- Configure your Project
- Compile your Smart Contract
- Setting migration for contract deployment
- Deploying contract to blockchain "Ropsten Test Network in my case"
- Install web3
- Initializing method to interact with Smart Contract
- Calling and Sending method to Interact
In order for a software and/or application to interact with the blockchain (i.e. read data and/or send transactions to the network), it must connect to an blockchain node. For this purpose, every blockchain client implements the JSON-RPC specification. It's bit technical i know but having a surface knowledge really helps.π
If you want to use a specific programming language to connect with an Ethereum node, roll your own solution but several convenience libraries exist within the ecosystem that make this much easier like really much easier. Here are some lists of Backend API's.
-
Step 1: Create your Alchemy account
You will need an Alchemy account in order to deploy and make requests to your smart contract. If you don't already have one, you can sign up for free here:https://dashboard.alchemyapi.io/signup/
-
Step 2: Create a Metamask Account
Metamask is used to manage your Ethereum account address. When you are creating an account, or if you already have an account, make sure to switch over to the "Ropsten Test Network" in the upper right. You can find the extension for metamask here.
Once you've created an Alchemy account, you can generate an API key by creating an app.π
- Navigate to the `Create App` page in your Alchemy Dashboard by hovering over `Apps` in the nav bar and clicking `Create App`,
- Name your app `Your App Name`, offer a short description, select `Staging` for the Environment, and choose `Ropsten` for your network,
-
Click `Create app` and thats it! Your app should appear in the table below
Truffle is a development environment, testing network, and asset pipeline for Ethereum that we will use to build, compile, and deploy our smart contract. To download Truffle, you can install NodeJS and paste the following command in your terminal:
npm install -g truffle
Make sure you install Node.js in your system first.π
-
Create a new directory for your Truffle project:
mkdir project-name
cd project-name
-
Get boilerplate files for creating and deploying smart contracts by "intializing":
truffle init
Once this operation is completed, you'll now have a project structure with the following items:
Truffle HDWallet provider is an easy way to configure network connection to ethereum through a provider like Alchemy, Infura. You can install it using the following command:
npm install @truffle/hdwallet-provider
Open up the project folder in your favorite editor. Smart contracts are written in a language called Solidityπ».
-
Navigate to the "contracts" folder and create a new file called
ContractName.sol
. Now that you've created file write your desired contract.
The next step is to edit your truffle-config.js
file to use HDWalletProvider
and provide all the necessary configuration for deploying to ropsten.
-
First, define the
HDWalletProvider
object in your configuration file. Add this line at the top of yourtruffle-config.js
file:
const HDWalletProvider = require("@truffle/hdwallet-provider");
-
Next, provide a reference to your mnemonic or seed phrase from Metamask. to get your seed reference from Metamask follow these instructions. Once you have your mnemonic, we recommend storing it safely in an environment file (we will also add our API key here).
First, install the dotenv package.
npm install dotenv --save
Next add the following line to yourtruffle-config.js
file.
require('dotenv').config()
Then create a.env
file at the root directory of your application and add your mnmeonic and Backend API key(In my case Alchemy API) to it:
API_KEY = "your-backend-api-key"
MNEMONIC = "your-metamask-seed-reference"
Finally add the new environment variables to ourtruffle-config.js
file:
const { API_KEY, MNEMONIC } = process.env;
Add the ropsten network to the module.exports intruffle-config.js
and your config file must look like this:
const HDWalletProvider = require("@truffle/hdwallet-provider");
require('dotenv').config()
const { API_KEY, MNEMONIC } = process.env;
module.exports = {
networks: {
development: {
host: "localhost",
port: 8545, // Ganache GUI & CUI uses diff. port i.e. 7545 or 8545
network_id: "\*", // Match any network id
gas: 5000000
},
ropsten: {
provider: function () {
return new HDWalletProvider(MNEMONIC, API_KEY)
},
network_id: 3
}
},
compilers: {
solc: {
settings: {
optimizer: {
enabled: true, // Default: false
runs: 200 // Default: 200
},
}
}
}
}
To compile a Truffle project, navigate to the root of the directory where the project is located and then type the following command:
truffle compile
Navigate to migrations/
, then add 2_deploy_contracts.js
where we'll add the config to deploy the contract.
const YourContract = artifacts.require("YourContract");
module.exports = function (deployer) {
deployer.deploy(YourContract);
};
In order to deploy our smart contract to the Ethereum network, we will use truffle's migrations which are JavaScript files that help you deploy contracts to the Ethereum network.
To run your migrations, run the following:
truffle migrate --network ropsten
You should then see a response that looks similar to the following:
# Starting migrations...
> Network name: 'ropsten'
> Network id: 3
> Block gas limit: 8000000 (0x7a1200)
# 1_initial_migration.js
Deploying 'Migrations'
---
> transaction hash: 0x61a6c81aaf5be5329c8572ac8de8f9d27064d75f5184f2389f66212b91c9736e
> Blocks: 1 Seconds: 12
> contract address: 0x341662A4BD97bf8542bB0d815F99aff47dB2Fc42
> block number: 8903909
> block timestamp: 1603052580
> account: 0x610Ae88399fc1687FA7530Aac28eC2539c7d6d63
> balance: 4.98766424
> gas used: 168286 (0x2915e)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00336572 ETH
> Saving migration to chain.
> Saving artifacts
---
> Total cost: 0.00336572 ETH
# 2_deploy_contracts.js
Deploying 'HelloWorld'
---
> transaction hash: 0x1312f26f70bd444a25790215c56aa4d87a56bc40d141f216df0661ddc3df42bb
> Blocks: 2 Seconds: 32
> contract address: 0x70c86b8d660eBd0adef24E9ACcb389BFb6611B2b
> block number: 8903912
> block timestamp: 1603052602
> account: 0x610Ae88399fc1687FA7530Aac28eC2539c7d6d63
> balance: 4.98206016
> gas used: 237925 (0x3a165)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.0047585 ETH
> Saving migration to chain.
> Saving artifacts
---
> Total cost: 0.0047585 ETH
# Summary
> Total deployments: 2
> Final cost: 0.00812422 ETH
Once this is finished without errors you will have deployed the contract, check it out on https://ropsten.etherscan.io/ by searching for your transaction hash
or contract address
!! π
If you head over to your Alchemy dashboard and click on the app details for your app you can see that there are requests flowing through. These requests are made in order to fulfill the deployment of your smart contract.
We need install a web3 package in order to interact with the Ethereum blockchain. We'll be using `Alchemy web3` in this example, however, there are a handful of other `web3 providers` you can choose from.
For the fronend part, I usually use React.js. So, initialize the React project in your parent directory by:
npx create-react-app app-name
Now, change the directory to react app by:
cd app-name
Now, install the web3 package here by:
npm install @alch/alchemy-web3 web3
Hurray, you've made to the almost end of making dapp.π
Now, open your App.js
inside src/
folder and clear out the unwanted things inside the <div className="App">
. It should look like:
import React from "react"
default function App(){
return <div className="App"></div>
}
The following steps are strictly important so follow patiently.
- Copy the
build/
folder from parent directory then paste inside theapp-name/src/
. - Now add the json file in
App.js
by adding line at the top of file:import contract from "./build/contracts/YourContract.json";
- Import web3 in your
App.js
in top line by:
import Web3 from "web3";
import { createAlchemyWeb3 } from "@alch/alchemy-web3";
- Import hook to your app
update
import React from 'react
byimport React, { useState, useEffect } from "react";
- Initialize the basic state variables that is required to intialize the method for contract.
const [account, setAccount] = useState("");
const [newContract, setNewContract] = useState(null);
const [loading, setLoading] = useState(true);
- Since, Interaction to ethereum blockchain is done through wallet, we need to make sure the wallet is installed in your browser so add the following code inside the function and above the return.
async function loadWeb3() {
var { ethereum, web3 } = window;
if (ethereum) {
await ethereum.request({ method: "eth_requestAccounts" });
ethereum.autoRefreshOnNetworkChange = false;
} else if (web3) {
web3 = new Web3(web3.currentProvider);
} else {
window.alert("Consider using metamask or web3 compatible browser(Mist).");
}
// get ethereum accounts
const accounts = await ethereum.request({ method: "eth_accounts" });
setAccount(accounts[0]);
}
You might see other resources where the wallet are being connected differently, but few things deprecated earlier and soon going to be ended. So this is new and stable way.
- Fill the empty states with contract and wallet address by adding following code.
async function loadBlockchainData() {
// setup contract
const API_KEY =
"add the api key from alchemmy api";
const alchWeb3 = createAlchemyWeb3(API_KEY);
const contractAddress = "your contract address here where the contract is deployed";
const ethContract = new alchWeb3.eth.Contract(
contract.abi,
contractAddress
);
setNewContract(ethContract);
setLoading(false);
}
Things to note here:
- Never share your API key to anyone so always use
.env
file to store api key and mnemonic code. - Add the API in the
API_KEY
above and add contract address which you can find from Etherscan by searching thetx hash
or your public address by which you deployed the contract.
Finally add the final code to get your base ready for the dapp.
useEffect(() => {
(async function fetchData() {
await loadWeb3();
await loadBlockchainData();
})();
}, []);
Your final code must look like this
import React, { useState, useEffect } from "react";
import Web3 from "web3";
import { createAlchemyWeb3 } from "@alch/alchemy-web3";
import contract from "./build/contracts/YourContract.json";
export default function App() {
const [account, setAccount] = useState("");
const [users, setusers] = useState([]);
const [newContract, setNewContract] = useState(
null
);
const [loading, setLoading] = useState(true);
async function loadWeb3() {
var { ethereum, web3 } = window;
if (ethereum) {
await ethereum.request({ method: "eth_requestAccounts" });
ethereum.autoRefreshOnNetworkChange = false;
} else if (web3) {
web3 = new Web3(web3.currentProvider);
} else {
window.alert("Consider using metamask or web3 compatible browser(Mist).");
}
// get ethereum accounts
const accounts = await ethereum.request({ method: "eth_accounts" });
setAccount(accounts[0]);
}
async function loadBlockchainData() {
// setup contract
const API_KEY =
"add the api key from alchemmy api";
const alchWeb3 = createAlchemyWeb3(API_KEY);
const contractAddress = "your contract address here where the contract is deployed";
const ethContract = new alchWeb3.eth.Contract(
contract.abi,
contractAddress
);
setNewContract(ethContract);
setLoading(false);
}
useEffect(() => {
(async function fetchData() {
await loadWeb3();
await loadBlockchainData();
})();
}, []);
return (
<div className="App"></div>
);
}
Sighss, Finally our base has completed it's just a matter of few lines of code to interact with methods.π
There are two ways to interact with contract through api i.e. call() and send() which is similar to post request and get request in REST API.
- If I had to retrive something from contract the code would be
const getData = async () => {
setLoading(true);
const data = await YourContract.methods
.methodName()
.call();
setLoading(false);
return data;
}
where methodName() can be function, variables, numbers but should be public in Smart Contract.
- If I has to push something to contract the code would be
const setData = async (data) => {
setLoading(true);
const data = await YourContract.methods
.methodName(data)
.send({ from: account });
setLoading(false);
}
Now the metamask will popup saying if you want to confirm or reject the request.
1. Don't forget to fork the repo,
2. Star if you really liked the work. β