Создайте ваш первый dApp и смарт-контракт
Добрый день, читатели Хабра, представляю перевод статьи по разработке dApp. Приятного чтения.
Мир онлайн-технологий быстро переходит к веб 3.0 (перевод этой статьи можете найти здесь). Похоже, что люди устали от централизованных систем, где их цифровая конфиденциальность ежедневно нарушается огромными организациями. Также хочется найти решение этой проблемы, и веб 3.0, похоже, на данный момент является ответом.
Эта статья в блоге не предназначена для освещения ноу-хау блокчейна и децентрализованных систем. Вместо этого он предназначен для тех, кто хотел бы создать онлайн-решения для пользователей, клиентов и покупателей, чтобы гарантировать им лучшую конфиденциальность и безопасность их данных.
Прояснив это, в данной статье я собираюсь показать вам азбуку того, как создать децентрализованное приложение с нуля и настроить среду разработки. Ниже перечислены некоторые темы, которые мы рассмотрим.
Инструменты
Настройка инструментов
Написание кода
Инструменты
b. Ganache
d. Metamask
e. React 17.0.2
Чтобы перейти к делу, я хотел бы вкратце рассказать о вышеупомянутых инструментах.
Первый из них, 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-операций.
На этом в данной статье все. Весь проект можно найти в репозитории.
Ниже приведены профили в социальных сетях, если захотите связаться с автором статьи.