The world of Web technology is rapidly transiting to Web 3.0, people seem to be tired of centralized platforms, and digital privacy is being attacked and sold off by large organizations every day. Therefore, a solution is needed, and Web 3.0 seems to be the best answer for now. This article is not intended to provide expertise in blockchain and decentralized systems, but to show how to build real world DApps using React, Solidity and web3.js.

Project address: github.com/QuintionTan…

An overview of the tool

Here are some of the tools you’ll use in this article.

  • Smart Contract Tools: Truffle Framework, which provides a set of tools for developing Ethereum smart contracts. It provides tools for smart contract management, deployment and migration, network management, development console, and more.
  • Ethereum test chain: Ganache, a personal blockchain, a locally developed blockchain that can be used to mimic all the behavior of the public blockchain.
  • Write smart Contract Language: Solidity, an object-oriented high-level language for implementing smart contracts.
  • Blockchain wallet plugin: MetaMask. This article will use the MetaMask Google extension, which enables the browser to connect to the test Ethereum blockchain network.
  • Front-end development framework: React
  • Web3js: A JavaScript library that allows communication with the Ethereum blockchain. It turns the React application into a blockchain-enabled application.

Environment to prepare

First, download according to the Truffle Framework, using the following command:

npm install -g truffle
Copy the code

Next, download and install Ganache. After successful installation, you can quickly build a local ETH network. The interface is as follows:

npm install ganache --global
Copy the code

After installation, run the following name to start a local ETH network:

ganache
Copy the code

Start the network and generate some account addresses and private keys for testing, as follows:

Available Accounts
==================
(0) 0xA57F1010d3BC4Acf6572c42B794B67dAf35B84f2 (1000 ETH)
(1) 0x60A73B46Ea815160c83CC3F89D855a4B8b6f21b5 (1000 ETH)
(2) 0x518B8c54ff5CA623707FB9Ca78B738425972EDdE (1000 ETH)
(3) 0x555024474B387842B8089489658d62c2Fc2D012F (1000 ETH)
(4) 0x302C59aE6F9456d74afB3Ca965b5f2123Fa58fbB (1000 ETH)
(5) 0xE0016171057C950A0E101f5affdAF01e8F5afd1f (1000 ETH)
(6) 0xC7cC6407DA22b630BEE2a8a3c304DA635eC4d9CD (1000 ETH)
(7) 0x06DCa7D808748F663D22BacC85555140D98Ee7fC (1000 ETH)
(8) 0xb1A3749c08b8440D3a45612A1d8864826d68549c (1000 ETH)
(9) 0xcF9E30D63a4970e938328470f7756c372afC8bBE (1000 ETH)

Private Keys
==================
(0) 0xcfac544a9947d80e3b37b00efad50a7ea3efab6ca51dd0808cad58f4ad9ebaae
(1) 0xecd3ae8ea7b36b7acc522ca790ae0660986f0615d73704bb4ceb03138cf9144a
(2) 0x7fa1926a2b8b2d98cc54bc9c9baf99035f7e5db1f23938a0b37a1ad8d106ce57
(3) 0xa313ceb995434887f5335813c4df01ab631b72de179044a04547e3c1142a8b46
(4) 0x2d2b70124764d8e4dd6b78a4f2cb689c27f1d42d89d2d416d9e5ad0797455fab
(5) 0x2ecdffb4009281b434f7c2e0bcc94751fb45c8667f7201ec3566e0ef79c6d82b
(6) 0x0b6ea61e43c6963cff2a4f5d0806bbd08cd99abcf5a61f92cadbecbf1bca4da3
(7) 0xfe15c45eca17dd6d67d4c044e7d4ea2740d729b76085de163143bcd19699fd9e
(8) 0xb01f9a7059c685e843339839e3398a556a74d890817cde4c09ed61828c2c08ae
(9) 0x952c883b05da76f58e30ce7fa4ed98cf8479313a1c1667c0c2d2aa10c66fea31
Copy the code

Next, you need to install using Metamask. Add the Metamask extension to Google Chrome and import the above account to look like this:

The subsequent development process will not use the Ganache terminal to build the development blockchain network, but its client.

Begin to build

The preparatory work of dApp has been set up, and the smart contract is written next. Open a terminal and create a folder in the project folder using the following command:

mkdir blockchain
Copy the code

Now create another contract folder in the blockchain folder using the following command:

cd blockchain
mkdir contracts
cd contracts
Copy the code

Run the following command to create a Truffle project so that you can develop smart contracts:

truffle init
Copy the code

Using the command above, you should get the following output:

Init successful, sweet!

Try our scaffold commands to get started:
  $ truffle create contract YourContractName # scaffold a contract
  $ truffle create test YourTestName         # scaffold a test

http://trufflesuite.com/docs
Copy the code

Open the project folder and you can see the following folder and file structure:

  • contractsIn the folder, the smart contract will be written.
  • migrationsIn the folder, the newly created smart contract will be migrated.
  • testFolder, typically used to write test cases to test smart contracts.
  • truffle-config.jsThe file contains all the configuration for the Truffle project.

Now write smart contracts, create a new file in the contracts folder and name it contacts.sol, and write the following code to it:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
Copy the code

This is always the first line in the smart contract file to specify the version of solidity. Now let’s write the code to make our first smart contract Contacts:

contract Contacts {
  
}
Copy the code

Now define a status variable to track the number of contacts in the smart contract as follows:

Pragma solidity > = 0.4.22 < 0.9.0; contract Contacts { uint public count = 0; // State variables}Copy the code

This is a special variable, and any data written to it will be stored in the blockchain store. The code uses a special modifier keyword, public, to define a variable that allows access outside the smart contract and is initially assigned a value of 0. Now you have a state variable, and you have a value in it. Now go to the front end and try to access this public state variable first.

Run the following command in the Blockchain directory to create a response application:

npx create-react-app contacts
Copy the code

Next go to the project directory and add dependencies:

cd contacts
yarn add web3
Copy the code

If you use create-react-app version >=5, you may encounter build problems because the latest create-react-app version does not include polyfill for NodeJS. The problem needs to be solved as follows:

yarn add --dev react-app-rewired crypto-browserify stream-browserify assert stream-http https-browserify os-browserify url buffer
Copy the code

Then create the file config-overrides. Js in the project root directory and add the following code:

const webpack = require("webpack");

module.exports = function override(config) {
    const fallback = config.resolve.fallback || {};
    Object.assign(fallback, {
        crypto: require.resolve("crypto-browserify"),
        stream: require.resolve("stream-browserify"),
        assert: require.resolve("assert"),
        http: require.resolve("stream-http"),
        https: require.resolve("https-browserify"),
        os: require.resolve("os-browserify"),
        url: require.resolve("url"),
    });
    config.resolve.fallback = fallback;
    config.plugins = (config.plugins || []).concat([
        new webpack.ProvidePlugin({
            process: "process/browser",
            Buffer: ["buffer", "Buffer"],
        }),
    ]);
    return config;
};
Copy the code

Finally modify package.json startup mode:

"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
}
Copy the code

As you can see above, add web3.js as a dependency for the project and resolve the above issues to make the React application created interact with the smart contract created above.

All the code will be written in the app.js file as follows:

import { useEffect, useState } from "react"; import Web3 from "web3"; function App() { const [account, setAccount] = useState(); / / set the number of state variables useEffect (() = > {async function load () {const web3 = new web3 (web3. GivenProvider | | "http://localhost:7545" ); const accounts = await web3.eth.requestAccounts(); setAccount(accounts[0]); } load(); } []); Return <div> Current account: {account}</div>; } export default App;Copy the code

In order to successfully run the application locally, you need to adjust some configuration on the back end, go back to the contracts folder, open the truffle-config.js file and add the following properties:

Module. exports = {networks: {development: {host: "127.0.0.1", port: 7545, network_id: "*",},}, compilers: {solc: interface interface, interface interface, interface interface, interface interface, interface interface, interface interface, interface interface, interface interface, interface interface { optimizer: { enabled: true, runs: 200, }, }, }, };Copy the code

Then in the migrations folder, create a new file and name it 2_deploy_comes.js as follows:

const Contacts = artifacts.require("./Contacts.sol");

module.exports = function (deployer) {
    deployer.deploy(Contacts);
};
Copy the code

In the terminal, enter the following command to migrate the smart contract:

cd contracts
truffle migrate
Copy the code

You should see the following output:

Go back to the front React folder and run the following command to run the application:

cd contacts
yarn start
Copy the code

This will open the React application in a browser and trigger Metamask to interact with the blockchain network, which should see a screen like this:

Now that you have successfully interacted with the smart contract and retrieved the account ID, go ahead and create a new function in the smart contract to get the contact list and send it to the front end and render them on the view.

// spdx-license-identifier: MIT pragma solidity >=0.4.22 <0.9.0; contract Contacts { uint public count = 0; Struct Contact {uint id; string name; string phone; } constructor() public { createContact('QuintionTang', '18900000000'); } mapping(uint => Contact) public contacts; function createContact(string memory _name, string memory _phone) public { count++; contacts[count] = Contact(count, _name, _phone); }}Copy the code

Now migrate this contract again:

truffle migrate
Copy the code

When you’re done, go back to the front React application, create a new file config.js in the SRC/folder, configure the contract address and contract ABI, This information can be in file blockchain/contracts/build/contracts/Contacts. Found in json, the code is as follows:

export const CONTRACT_ADDRESS = "0xD3329a764935C7AA9B32f162C196E28B4e3310A3"; Export const CONTRACT_ABI = [{inputs: [], payable: false, stateMutability: "nonpayable", type: "constructor", }, { constant: true, inputs: [ { internalType: "uint256", name: "", type: "uint256", }, ], name: "contacts", outputs: [ { internalType: "uint256", name: "id", type: "uint256", }, { internalType: "string", name: "name", type: "string", }, { internalType: "string", name: "phone", type: "string", }, ], payable: false, stateMutability: "view", type: "function", }, { constant: true, inputs: [], name: "count", outputs: [ { internalType: "uint256", name: "", type: "uint256", }, ], payable: false, stateMutability: "view", type: "function", }, { constant: false, inputs: [ { internalType: "string", name: "_name", type: "string", }, { internalType: "string", name: "_phone", type: "string", }, ], name: "createContact", outputs: [], payable: false, stateMutability: "nonpayable", type: "function", }, ];Copy the code

Now import the smart contract address and ABI into the app.js file as shown below, and update the load function with the following code:

import { useEffect, useState } from "react"; import Web3 from "web3"; import { CONTRACT_ABI, CONTRACT_ADDRESS } from "./config"; function App() { const [account, setAccount] = useState(); const [contactList, setContactList] = useState(); const [contacts, setContacts] = useState([]); useEffect(() => { async function load() { const web3 = new Web3( Web3.givenProvider || "http://localhost:7545" ); const accounts = await web3.eth.requestAccounts(); setAccount(accounts[0]); // Instantiate the smart contract with the ABI and address. const contactListByContract = new web3.eth.Contract( CONTRACT_ABI, CONTRACT_ADDRESS ); // Set the contact list to the status variable. setContactList(contactListByContract); / / get the iteration number of contacts const counter = await contactListByContract. The methods, the count (). The call (); For (var I = 1; i <= counter; I++) {/ / call the contacts method derives from the intelligent contract specific contact const contact = await contactListByContract. The methods, the contacts (I). The call (); // Add the recently obtained contact state variable. setContacts((contacts) => [...contacts, contact]); } } load(); } []); Return (<div> current account: {account} <h1> Contact list </h1> <ul> {object.keys (contacts).map((contact, The index) = > (< li key = {` ${contacts [index] name} - ${index} `} > < h4 > {contacts [index] name} < / h4 > < span > < b > phone number:  </b> {contacts[index].phone} </span> </li> ))} </ul> </div> ); } export default App;Copy the code

Start the React application and you’ll see the following:

After the

At this point, a simple dAPP has been implemented.