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