Создание реального приложения dApp с помощью React, Solidity и Web3.js

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Создайте ваш первый dApp и смарт-контракт

Добрый день, читатели Хабра, представляю перевод статьи по разработке dApp. Приятного чтения.

Мир онлайн-технологий быстро переходит к веб 3.0 (перевод этой статьи можете найти здесь). Похоже, что люди устали от централизованных систем, где их цифровая конфиденциальность ежедневно нарушается огромными организациями. Также хочется найти решение этой проблемы, и веб 3.0, похоже, на данный момент является ответом.
Эта статья в блоге не предназначена для освещения ноу-хау блокчейна и децентрализованных систем. Вместо этого он предназначен для тех, кто хотел бы создать онлайн-решения для пользователей, клиентов и покупателей, чтобы гарантировать им лучшую конфиденциальность и безопасность их данных.
Прояснив это, в данной статье я собираюсь показать вам азбуку того, как создать децентрализованное приложение с нуля и настроить среду разработки. Ниже перечислены некоторые темы, которые мы рассмотрим.

  1. Инструменты

  2. Настройка инструментов

  3. Написание кода

Инструменты

a. Truffle Framework

b. Ganache

c. Solidity 0.8.10

d. Metamask

e. React 17.0.2

f. Web3.js 1.6.1

Чтобы перейти к делу, я хотел бы вкратце рассказать о вышеупомянутых инструментах.
Первый из них, Truffle Framework, предлагает набор инструментов для разработки смарт-контрактов Ethereum. Он предлагает такие инструменты, как управление смарт-контрактами, развертывание и миграция, управление сетью, консоль разработки и т.д.
Ganache - это персональный блокчейн, который представляет собой локальный блокчейн для разработки, который можно использовать для имитации поведения публичного блокчейна.
Solidity - объектно-ориентированный язык высокого уровня для реализации смарт-контрактов. Узнать больше о Solidity можно тут.
Большинство браузеров в настоящее время не позволяют нам подключаться к сети блокчейн, поэтому я бы использовал расширение Metamask chrome, которое позволит нам подключить наш браузер chrome к сети блокчейн.
Для разработки пользовательского интерфейса или фронт-энда мы будем использовать библиотеку React, которая является одной из наиболее широко используемых библиотек JavaScript среди фронт-эндовых сообществ.
Web3.js - это библиотека JavaScript, которая позволяет нам общаться с блокчейном Ethereum. Она превращает наше приложение React в приложение с поддержкой блокчейна.

Настройка инструментов

Теперь, когда я кратко рассказал о наборе инструментов, которые будут использоваться в этой статье блога, пришло время разобраться и настроить инструменты.
Прежде всего, я хотел бы, чтобы вы скачали Truffle Framework и установили его с помощью следующей команды:

npm install -g truffle

Затем загрузите и установите Ganache. Когда вы это сделаете и откроете его, то увидите следующее окно:

Далее нам понадобится Metamask.
Добавьте расширение Metamask в свой google chrome и перейдите к экрану, на котором появится что-то вроде следующего. Для того чтобы настроить Metamask, пожалуйста, посмотрите эту статью.

Написание кода

Теперь, когда инструменты настроены, перейдем к следующему шагу - написанию смарт-контрактов. Для этого откройте терминал и создайте папку в папке projects с помощью следующей команды:

mkdir blockchain

Теперь создайте папку внутри папки blockchain с помощью следующих команд:

cd blockchain

mkdir contracts

cd contracts

Теперь выполните приведенную ниже команду для создания проекта truffle, который позволит нам разрабатывать смарт-контракты:

truffle init

Выполнив вышеуказанную команду, вы должны получить результат, как показано ниже:

Теперь откройте ваш проект truffle в вашем любимом текстовом редакторе. Я собираюсь использовать Sublime Text. Вы должны увидеть следующую структуру папок и файлов:

В папке contracts мы будем писать наши смарт-контракты.
В папке migrations мы будем мигрировать наши вновь созданные смарт-контракты.
В папке test мы обычно пишем тесты для проверки нашего смарт-контракта, однако это выходит за рамки данной статьи, поэтому мы не будем углубляться в эту тему. Я бы настоятельно рекомендовал писать тесты для ваших смарт-контрактов перед их развертыванием на публичных узлах блокчейна.
Файл truffle-config.js содержит всю конфигурацию проекта truffle.
Теперь давайте напишем наш смарт-контракт. Создайте новый файл и назовите его contacts.sol в папке contracts. Теперь откройте этот файл и напишите в нем следующий код:

pragma solidity >=0.4.22 <0.9.0;

Это всегда должна быть первая строка в файле смарт-контракта. Этим мы указываем версию Solidity.
Теперь давайте создадим наш первый смарт-контракт:

pragma solidity >=0.4.22 <0.9.0;

contract Contacts {
  
}

Мы можем написать смарт-контракт, используя ключевое слово contract, за которым следует название контракта, в данном случае Contacts.
Теперь, чтобы отслеживать количество контактов внутри нашего смарт-контракта, мы создадим переменную состояния.

pragma solidity >=0.4.22 <0.9.0;

contract Contacts {
  uint public count = 0; // state variable
}

Это специальная переменная, и любые данные, которые мы записываем в эту переменную, будут храниться в хранилище блокчейна. Мы используем специальное ключевое слово-модификатор, т.е. public, чтобы иметь доступ к этой переменной за пределами смарт-контракта. Затем мы присваиваем этой переменной значение 0.
Теперь у нас есть переменная состояния, и в ней есть значение. Давайте перейдем к фронт-энду и попробуем сначала получить доступ к этой публичной переменной состояния. С помощью этого подхода мы установим связь между приложением React и нашим смарт-контрактом.
Выполните следующие команды в папке blockchain, чтобы создать приложение React.

npx create-react-app contacts

cd contacts

если используете yarn

yarn add web3

если используете npm

npm install web3

Как вы можете видеть, мы также добавили web3.js в качестве зависимости для этого проекта, чтобы наше приложение react взаимодействовало с нашим смарт-контрактом.
Теперь откройте папку contacts в вашем любимом редакторе. Я использую Sublime Text.
Мы не будем настраивать структуру папок и реализовывать сложную архитектуру, потому что это выходит за рамки данной статьи в блоге.
Мы напишем весь наш код в файле App.js. Поэтому откройте этот файл в редакторе.
Напишите приведенный ниже код в файле App.js:

import { useEffect, useState } from 'react';
import Web3 from 'web3';

function App() {
  return (
    <div>
    </div>
  );
}

export default App;

Мы импортируем пару хуков из React и Web3 из Web3.js. Теперь создадим переменную состояния, как показано ниже:

import { useEffect, useState } from 'react';
import Web3 from 'web3';

function App() {
  const [account, setAccount] = useState(); // state variable to set account.
  return (
    <div>
    </div>
  );
}

export default App;

Теперь внутри хука useEffect мы создадим наш смарт-контракт, как показано ниже:

import { useEffect, useState } from 'react';
import Web3 from 'web3';

function App() {
  const [account, setAccount] = useState(); // state variable to set account.
  
  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>
       Your account is: {account}
     </div>
   );
}

export default App;

Теперь, чтобы успешно запустить эту клиентскую часть, нам нужно сделать несколько шагов в бэкенде. Давайте вернемся в папку contracts. Во-первых, откройте файл truffle-config.js и добавьте следующие свойства:

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*"
    }
  },
  compilers: {
    solc: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  }
}

Теперь внутри папки migrations создайте новый файл и назовите его 2_deploy_contracts.js и вставьте приведенный ниже код:


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

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

Теперь в терминале введите приведенный ниже код для миграции вашего контракта:

truffle migrate

Вы должны увидеть результат, подобный приведенному ниже:

Теперь вернитесь в папку фронт-энда (папка contracts) и выполните приведенную ниже команду для запуска приложения:

yarn start

или

npm start

Это откроет ваше приложение React в браузере и запустит Metamask для взаимодействия с вашей блокчейн-сетью. Вы должны увидеть экран, как показано ниже:

В открывшемся окне нажмите кнопку Next, и перед вами откроется следующее окно.

Теперь нажмите кнопку Connect. После этого в вашем браузере должно появиться сообщение с номером вашего счета, как показано ниже:

Теперь, когда мы успешно подключились к нашему смарт-контракту и получили идентификатор счета. Давайте приступим к созданию новой функции внутри нашего смарт-контракта для получения списка контактов и передачи его на фронт-энд, чтобы отобразить их на экране.
Вернемся в папку contracts, откроем файл Contracts.sol и добавим следующую функцию.

pragma solidity >=0.4.22 <0.9.0;

contract Contacts {
  uint public count = 0; // state variable
  
  struct Contact {
    uint id;
    string name;
    string phone;
  }
  
  constructor() public {
    createContact('Zafar Saleem', '123123123');
  }
  
  mapping(uint => Contact) public contacts;
  
  function createContact(string memory _name, string memory _phone) public {
    count++;
    contacts[count] = Contact(count, _name, _phone);
  }
}

Теперь снова мигрируйте этот контракт, поскольку мы внесли в него изменения, так как смарт-контракты иммутабельны.

truffle migrate

Теперь давайте вернемся к фронт-энду, то есть к папке contacts. Создайте новый файл config.js внутри папки src/ и вставьте в него приведенный ниже код.

export const CONTACT_ADDRESS = '0xfAd567EBdCb36f49F3a509FEDF9e72E3ad75ca59';

export const CONTACT_ABI = [
  {
    "constant": true,
    "inputs": [],
    "name": "count",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function",
    "signature": "0x06661abd"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "contacts",
    "outputs": [
      {
        "name": "id",
        "type": "uint256"
      },
      {
        "name": "name",
        "type": "string"
      },
      {
        "name": "phone",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function",
    "signature": "0xe0f478cb"
  },
  {
    "inputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "constructor",
    "signature": "constructor"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_name",
        "type": "string"
      },
      {
        "name": "_phone",
        "type": "string"
      }
    ],
    "name": "createContact",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function",
    "signature": "0x3dce4920"
  }
];

Теперь импортируйте адрес смарт-контракта и ABI в файл App.js, как показано ниже, а также обновите функцию load следующим кодом:

import { useEffect, useState } from 'react';
import Web3 from 'web3';
import { CONTACT_ABI, CONTACT_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 smart contract using ABI and address.
      const contactList = new web3.eth.Contract(CONTACT_ABI, CONTACT_ADDRESS);
      // set contact list to state variable.
      setContactList(contactList);
      // Then we get total number of contacts for iteration
      const counter = await contactList.methods.count().call();
      // iterate through the amount of time of counter
      for (var i = 1; i <= counter; i++) {
        // call the contacts method to get that particular contact from smart contract
        const contact = await contactList.methods.contacts(i).call();
        // add recently fetched contact to state variable.
        setContacts((contacts) => [...contacts, contact]);
      }
    }
    
    load();
  }, []);
  
  return (
    <div>
      Your account is: {account}
    </div>
  );
}

export default App;

Приведенный выше код получит все контакты из нашего смарт-контракта и установит их в переменную состояния contacts. Код очень хорошо прокомментирован и объяснен.
Теперь давайте отобразим все контакты через тэг ul, как показано ниже.

import { useEffect, useState } from 'react';
import Web3 from 'web3';
import { CONTACT_ABI, CONTACT_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 smart contract using ABI and address.
      const contactList = new web3.eth.Contract(CONTACT_ABI, CONTACT_ADDRESS);
      // set contact list to state variable.
      setContactList(contactList);
      // Then we get total number of contacts for iteration
      const counter = await contactList.methods.count().call();
      // iterate through the amount of time of counter
      for (var i = 1; i <= counter; i++) {
        // call the contacts method to get that particular contact from smart contract
        const contact = await contactList.methods.contacts(i).call();
        // add recently fetched contact to state variable.
        setContacts((contacts) => [...contacts, contact]);
      }
    }
    
    load();
    
  }, []);
  
  return (
    <div>
      Your account is: {account}
      <h1>Contacts</h1>
      <ul>
      {
        Object.keys(contacts).map((contact, index) => (
          <li key={`${contacts[index].name}-${index}`}>
            <h4>{contacts[index].name}</h4>
            <span><b>Phone: </b>{contacts[index].phone}</span>
          </li>
        ))
      }
      </ul>
    </div>
  );
}

export default App;

Как вы можете увидеть обновленный код внутри return - отображает информацию о контакте. Вы должны увидеть что-то вроде следующего:

Если вы видите именно это, то поздравляем, вы только что создали свой первый dApp со смарт-контрактом и веб-приложением, которое взаимодействует с вашим смарт-контрактом на блокчейне.
Теперь, когда вы знаете, как получать информацию из смарт-контракта, продолжайте совершенствовать его, добавляя новые контакты, обновляя их и удаляя с помощью полных CRUD-операций.
На этом в данной статье все. Весь проект можно найти в репозитории.

Ниже приведены профили в социальных сетях, если захотите связаться с автором статьи.

Linkedin | Github | Gitlab | Website

Источник: https://habr.com/ru/post/653679/


Интересные статьи

Интересные статьи

Мои предыдущие статьи были посвящены мониторингу запуска Android-приложений в эксплуатационной среде. После того, как мы разобрались с метриками и сценариями, которые результируют в медленном запуске ...
25 июля, у Вовы и Вани Ильиных, основателей Email Soldiers, день рождения. Мы решили подготовить для них квест и чат-бота, который помогал бы двигаться по квесту.В&n...
При работе с БД вы наверняка прибегали к использованию Python и ODBC. Это хорошие инструменты для работы с большими данными, но они сталкиваются с ограничением производит...
こんにちは, или добрый день по-японски.Как бы не был популярен английский язык, всё же пользователям комфортнее и привычнее в родной языковой среде.Поэтому далее мы пошагово р...
Вебхуки — популярный пример использования FaaS (функция как услуга) платформ. Их можно использовать для многих различных целей, например, для отправки клиентам уведомлени...