Основное руководство по созданию децентрализованной платформы электронной коммерции с помощью React и Solidity (часть 1)

Основное руководство по созданию децентрализованной платформы электронной коммерции с помощью React и Solidity (часть 1)

30 марта 2022 г.

Что вы будете создавать, см. [живую демонстрацию] (https://fresher-a5113.web.app/) и [репозиторий GitHub] (https://github.com/Daltonic/freshers) для получения дополнительной информации.


Добавить новый продукт


Оплата эфиром


Чат с продавцом


Введение


Спрос на решения Web3.0 находится на рекордно высоком уровне, но не хватает материалов, чтобы создать армию разработчиков, необходимых для заполнения вакансий. Чтобы помочь другим веб-разработчикам, я создал это руководство, чтобы помочь вам понять, как создать децентрализованную платформу электронной коммерции, которая осуществляет транзакции в эфирах. К концу этого урока вы сможете делать следующее:


  • Создайте приложение для электронной коммерции.

  • Интеграция платежного решения Web3.0.

  • Включить функциональность чата с клиентами.

  • Взаимодействие с базой данных с помощью Firebase v9.

  • Напишите и разверните смарт-контракт Solidity.

  • Смарт-контракт подключения с приложением React.

  • Еще больше.

Это руководство является ЧАСТЬЮ ПЕРВОЙ серии из двух частей, мы начнем с разработки смарт-контракта Solidity. Итак, если вы загорелись этим билдом, то давайте кодить…


Предпосылки


Для ПЕРВОЙ ЧАСТИ этого урока вам понадобятся следующие предметы для сборки вместе со мной;


  • NodeJs установлен на вашем компьютере.

  • Установлен [менеджер пакетов Yarn] (https://classic.yarnpkg.com/en/docs/install#windows-stable).


  • [Ganache] (https://trufflesuite.com/ganache/index.html) установлен.

  • [Git CLI] (https://git-scm.com/download/) установлен.

  • И гибкая решимость учиться.

Установка зависимостей приложения


Чтобы избавить вас от необходимости устанавливать одну зависимость за другой, я подготовил для вас стартовый набор в моем репозитории git. Клонируйте и установите зависимости, следуя инструкциям ниже. И… не забудьте отметить проект звездочкой.


На своем терминале перейдите к местоположению вашего проекта и запустите код ниже:


``` ударить


Убедитесь, что у вас уже установлены указанные выше компоненты!


клон git https://github.com/Daltonic/truffle-starter-kit.git


cd frehsers # Перейдите к новой папке.


yarn install # Устанавливает все зависимости.


Я рекомендую вам использовать vs code для обучения, в нем есть все, что вам нужно для кодирования.


Если вы это сделали, вы молодец, давайте перейдем к следующему шагу…


Кодирование смарт-контракта


Откройте проект в коде VS и перейдите в каталог контрактов, вы увидите существующий контракт с именем Migration.sol.


Создайте новый контракт Solidity с именем Store.sol. Внутри хранилища определите следующие структуры.


// SPDX-идентификатор лицензии: MIT


прочность прагмы ^0,8,4;


договор Магазин {


// Все коды здесь!


Это типичная структура смарт-контракта Solidity, давайте кодировать этот смарт-контракт шаг за шагом.


```javascript


// Определение переменных хранилища


адрес общедоступного неизменяемого storeOwner;


uint256 общедоступный магазинAcc;


строка общедоступного storeName;


uint256 общедоступная неизменяемая платаPercent;


uint256 публичный магазинПродажи;


Это переменные, которые наш смарт-контракт будет использовать для выполнения продаж в магазине. Переменные владелец магазина и процент комиссии являются неизменяемыми, после развертывания смарт-контракта их больше нельзя изменить в ходе программы.


Переменные с типом адреса означают, что они могут содержать только типы данных адреса кошелька. В то время как переменные с uint или uint256 означают целые числа без знака, они могут использоваться для хранения только положительных чисел с десятичными знаками или без них.


```javascript


// Отслеживание количества продаж пользователями


отображение (адрес => uint256) публичных продаж;


Приведенный выше код описывает переменную солидности с типом связи ключ-значение. Он похож на хеш-метод Python тем, что возвращает значение, если аргумент, переданный в параметре, находит совпадение.


```javascript


// Объявление событий внутри каждой продажи


Событие Распродажа(


адрес проиндексированного покупателя,


адрес проиндексирован продавца,


сумма uint256,


uint256 метка времени


событие Снятие(


получатель с индексацией адреса,


сумма uint256,


uint256 метка времени


События полезны для хранения аргументов, переданных в смарт-контракт в сети блокчейн. Это важный компонент для написания профессионального смарт-контракта.


// Структурирование объекта продажи


структура SalesStruct {


адрес покупателя;


адрес продавца;


сумма uint256;


предназначение строки;


uint256 метка времени;


SalesStruct[] продажи;


Мы описываем структуру для сбора данных о продажах в приведенном выше коде. Мы хотим собрать адреса покупателя и продавца, количество переданных эфиров, цель транзакции и время завершения транзакции для каждой продажи, совершенной через наш смарт-контракт. Solidity предоставляет нам метод struct, который лучше всего подходит для обеспечения правильного ввода этих записей.


```javascript


// Инициализация хранилища


конструктор(


строковая память _storeName,


адрес _storeOwner,


uint256 _feePercent


имя_магазина = _имя_магазина;


владелец магазина = _владелец магазина;


платапроцент = _feePercent;


магазин Акк = 0;


Это информация, передаваемая во время развертывания смарт-контракта.


```javascript


// Выполнение платежа за продажу


функция payNow(адрес продавца, цель памяти строки)


общественный


подлежащий уплате


возвращает (логический успех)


// Проверка платежей


require(msg.value > 0, "Эфиры не могут быть равны нулю!");


require(msg.sender != storeOwner, "Продажа запрещена");


// Расчет стоимости и комиссии


комиссия uint256 = (msg.value / 100) * FeePercent;


uint256 cost = msg.value - комиссия;


// Назначение продаж и платежей магазину и владельцу продукта


storeAcc += msg.value;


магазинПродажи += 1;


salesOf[продавец] += 1;


// Обналичивание продавцу


вывести деньги в (владелец магазина, комиссия);


вывестиMoneyTo(продавец, стоимость);


// Запись продаж в смарт-контракт


продажи.толчок (


SalesStruct(msg.sender, продавец, стоимость, цель, block.timestamp)


// Захватывает данные о продажах по событию


выпустить продажу (msg.sender, продавец, стоимость, block.timestamp);


вернуть истину;


Эта функция собирает оплату с покупателя и отправляет продавцу 90% продаж и 10% владельцу магазина в качестве платы за использование их платформы.


```javascript


// Отправляет эфиры на указанный адрес


функция _payTo(адрес _to, uint256 _amount) внутренняя {


(логический успех1,) = подлежащий оплате (_to).call {значение: _amount} ("");


требуют (успех1);


Это внутренний метод перевода эфиров на указанный адрес, он работает совместно с функцией вывода. Он может быть вызван только другой функцией в рамках нашего смарт-контракта.


```javascript


// Выполняет передачу эфира


функция removeMoneyTo(адрес получателя, сумма uint256)


внутренний


возвращает (логический успех)


require(storeAcc >= сумма, "Недостаточно средств!");


_payTo(получатель, сумма);


storeAcc -= сумма;


// Захватывает данные о передаче по событию


выдать вывод (получатель, сумма, отметка времени блока);


вернуть истину;


Это функция, выполняющая отправку денег на указанный адрес. Он гарантирует, что проверяет баланс перед выполнением транзакции.


```javascript


// Извлекает все обработанные продажи из смарт-контракта


Функция публичного представления getAllSales() возвращает (память SalesStruct[]) {


возвратные продажи;


Наконец, эта функция возвращает массив всех продаж, которые произошли по нашему смарт-контракту.


Полный код выглядит так…


```javascript


// SPDX-идентификатор лицензии: MIT


прочность прагмы ^0,8,4;


договор Магазин {


// Определение переменных хранилища


адрес общедоступного неизменяемого storeOwner;


uint256 общедоступный магазинAcc;


строка общедоступного storeName;


uint256 общедоступная неизменяемая платаPercent;


uint256 публичный магазинПродажи;


// Отслеживание количества продаж пользователями


отображение (адрес => uint256) публичных продаж;


// Объявление событий внутри каждой продажи


Событие Распродажа(


адрес проиндексированного покупателя,


адрес проиндексирован продавца,


сумма uint256,


uint256 метка времени


событие Снятие(


получатель с индексацией адреса,


сумма uint256,


uint256 метка времени


// Структурирование объекта продажи


структура SalesStruct {


адрес покупателя;


адрес продавца;


сумма uint256;


предназначение строки;


uint256 метка времени;


SalesStruct[] продажи;


// Инициализация хранилища


конструктор(


строковая память _storeName,


адрес _storeOwner,


uint256 _feePercent


имя_магазина = _имя_магазина;


владелец магазина = _владелец магазина;


платапроцент = _feePercent;


магазин Акк = 0;


// Выполнение платежа за продажу


функция payNow(адрес продавца, цель памяти строки)


общественный


подлежащий уплате


возвращает (логический успех)


// Проверка платежей


require(msg.value > 0, "Эфиры не могут быть равны нулю!");


require(msg.sender != storeOwner, "Продажа запрещена");


// Расчет стоимости и комиссии


комиссия uint256 = (msg.value / 100) * FeePercent;


uint256 cost = msg.value - комиссия;


// Назначение продаж и платежей магазину и владельцу продукта


storeAcc += msg.value;


магазинПродажи += 1;


salesOf[продавец] += 1;


// Обналичивание продавцу


вывести деньги в (владелец магазина, комиссия);


вывестиMoneyTo(продавец, стоимость);


// Запись продаж в смарт-контракт


продажи.толчок (


SalesStruct(msg.sender, продавец, стоимость, цель, block.timestamp)


// Захватывает данные о продажах по событию


выпустить продажу (msg.sender, продавец, стоимость, block.timestamp);


вернуть истину;


// Отправляет эфиры на указанный адрес


функция _payTo(адрес _to, uint256 _amount) внутренняя {


(логический успех1,) = подлежащий оплате (_to).call {значение: _amount} ("");


требуют (успех1);


// Выполняет передачу эфира


функция removeMoneyTo(адрес получателя, сумма uint256)


внутренний


возвращает (логический успех)


require(storeAcc >= сумма, "Недостаточно средств!");


_payTo(получатель, сумма);


storeAcc -= сумма;


// Захватывает данные о передаче по событию


выдать вывод (получатель, сумма, отметка времени блока);


вернуть истину;


// Извлекает все обработанные продажи из смарт-контракта


Функция публичного представления getAllSales() возвращает (память SalesStruct[]) {


возвратные продажи;


Теперь, когда мы закончили кодирование этого смарт-контракта, пришло время протестировать его программно.


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


Прежде чем мы приступим к тестированию смарт-контракта, давайте настроим скрипт миграции в папке migrations.


Папка миграции


Перейдите в папку миграции и создайте новый файл с именем 2_deploy_contracts.js. Вставьте следующие коды в файл 2_deploy_contracts.js.


const Store = артефакты.require('Store')


module.exports = асинхронный (развертчик) => {


const [_feeAccount] = ожидание web3.eth.getAccounts()


const _name = 'Свежее'


константа _feePercent = 10


ожидайте развертывания.развертывание(


Магазин,


_имя,


_feeAccount,


_feePercent


Это будет необходимо, когда мы начнем тестировать смарт-контракт.


Тестирование смарт-контракта



Запустите Ganache и убедитесь, что он активен и доступен. Затем найдите папку test и создайте файл с именем Store.test.js.


Вставьте фрагмент кода внутрь него.


```javascript


const Store = артефакты.require('Store')


требовать ('чай'). использовать (требовать ('чай-как-обещано')). должен ()


const toWei = (число) => web3.utils.toWei (num.toString())


const fromWei = (число) => web3.utils.fromWei (num.toString())


контракт('Магазин', ([Владелец магазина, покупатель, продавец]) => {


постоянная плата в процентах = 10


const storeName = 'Новости'


пусть хранит


перед каждым (асинхронный () => {


store = await Store.new (storeName, storeOwner, feePercent)


описать('развертывание', () => {


it('подтверждает имя магазина', async () => {


константный результат = ожидание store.storeName()


результат.should.equal (имя_хранилища)


it('подтверждает владельца магазина', async () => {


константный результат = ожидание store.storeOwner()


результат. должен. равен (владелец магазина)


it('подтверждает комиссию за продажу', async () => {


константный результат = ожидание store.feePercent()


результат.toString().should.equal(feePercent.toString())


описать('Процесс продажи', () => {


постоянная сумма = fromWei (toWei (4))


const target = 'Продажи на ковшах'


it('подтверждает увеличение продаж магазина и продавца', async() => {


// Продажи продавца перед покупкой


пусть результат = ожидание store.salesOf (продавец)


результат.toString().should.equal('0')


// Продажи магазина перед покупкой


результат = ожидание store.storeSales()


результат.toString().should.equal('0')


// Осуществляем продажи


await store.payNow(продавец, цель, {от: покупатель, значение: сумма})


// Продажи после после покупки


результат = ожидание store.salesOf (продавец)


результат.toString().should.equal('1')


// Продажи магазина после покупки


результат = ожидание store.storeSales()


результат.toString().should.equal('1')


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


Взаимодействие со смарт-контрактом


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


Перейдите в папку скриптов и создайте файл с именем performSales.js. Затем вставьте в него следующие коды.


```javascript


const Store = артефакты.require("Store");


module.exports = асинхронный (обратный вызов) => {


const [Владелец магазина, продавец, покупатель] = await web3.eth.getAccounts()


постоянная сумма = web3.utils.toWei('4', 'эфир')


const target = 'Продажи на ковшах'


константное хранилище = ожидание Store.deployed()


let buybalance = await web3.eth.getBalance(покупатель)


letellerBal = await web3.eth.getBalance(продавец)


let storeOwnerBal = await web3.eth.getBalance(storeOwner)


console.log(Начальный баланс покупателя | ${web3.utils.fromWei(buyerBal.toString(), 'ether')})


console.log(Начальный баланс продавца | ${web3.utils.fromWei(sellerBal.toString(), 'ether')})


console.log(Начальный баланс storeOwner | ${web3.utils.fromWei(storeOwnerBal.toString(), 'ether')})


console.log(<br> ${цель} для ${web3.utils.fromWei(amount.toString(), 'ether')} эфиры... <br>)


await store.payNow(продавец, цель, {от: покупатель, значение: сумма})


байерБал = ожидание web3.eth.getBalance(покупатель)


продавецБал = ожидание web3.eth.getBalance(продавец)


storeOwnerBal = await web3.eth.getBalance(storeOwner)


console.log(Баланс покупателя после продажи | ${web3.utils.fromWei(buyerBal.toString(), 'ether')})


console.log(Баланс продавца после продажи | ${web3.utils.fromWei(sellerBal.toString(), 'ether')})


console.log(Баланс storeOwner после продажи | ${web3.utils.fromWei(storeOwnerBal.toString(), 'ether')})


Перезвоните()


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


трюфель мигрировать --reset


Вы увидите следующий результат на своем терминале.


Результат миграции на терминале


Если вы добрались сюда, вы молодец, давайте запустим скрипт perfomSales, запустив этот код на терминале.


скрипты truffle exec/performSales.js


У вас должно быть что-то подобное на вашем терминале…


Результат продаж скриптов


Замечательно, мы можем быть счастливы, что наш смарт-контракт сертифицирован и полностью функционален. Давайте развернем его в тестовой сети rinkeby.


Развертывание смарт-контракта


Чтобы выполнить это развертывание, настройте файл конфигурации truffle в следующем порядке:


```javascript


требуют('dotenv').config()


const HDWalletProvider = require('@truffle/hdwallet-provider')


модуль.экспорт = {


// Настраиваем сети (Localhost, Kovan и т.д.)


сети: {


разработка: {


хост: «127.0.0.1»,


порт: 7545,


network_id: '*', // Соответствует любому идентификатору сети


ринкеби: {


провайдер: () =>


новый HDWalletProvider(process.env.SECRET_KEY, process.env.ENDPOINT_URL),


network_id: 4, // идентификатор Ринкеби


газ: 5500000, // Rinkeby имеет более низкий лимит блоков, чем основная сеть


подтверждения: 2, // количество конфигов для ожидания между развертываниями. (по умолчанию: 0)


timeoutBlocks: 200, // количество блоков до истечения времени развертывания (минимум/по умолчанию: 50)


skipDryRun: true, // Пропустить пробный запуск перед миграцией? (по умолчанию: false для публичных сетей)


Contracts_directory: './contracts/',


Contracts_build_directory: './src/shared/abis/',


// Настройте свои компиляторы


компиляторы: {


соль: {


версия: «0.8.11»,


оптимизатор: {


включено: правда,


пробеги: 200,


Развертывание в Алхимию


Разработка и развертывание блокчейна Alchemy


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


Зарегистрируйтесь сейчас или войдите, если у вас уже есть учетная запись.


Страница аутентификации


Когда вы войдете в систему, вы увидите страницу панели инструментов, которая позволяет вам создать новое приложение блокчейна.


Панель управления алхимией


Создание приложения для алхимии


Нажмите кнопку СОЗДАТЬ ПРИЛОЖЕНИЕ и введите информацию, показанную на изображении ниже, обязательно включив сеть теста Ринкеби.


Создать всплывающее окно нового приложения


После того, как вы создали приложение, вы можете просмотреть его информацию, щелкнув имя приложения или кнопку просмотра сведений.


Создано приложение


Скопируйте URL-адрес WSS, как показано на изображении ниже, нажав кнопку VIEW KEY.


Конечная точка веб-сокета


Удивительно, теперь действуйте, как показано на изображениях ниже, чтобы получить свою учетную запись Rinkeby. Пожалуйста, имейте в виду, что мы используем не обычный адрес учетной записи, а закрытый ключ к этой учетной записи.


Шаг первый


Шаг второй


Шаг третий


Шаг четвертый


```javascript


ENDPOINT_URL=<ВАШ_ALCHEMY_WSS_URL>


SECRET_KEY=<ВАША_METAMASK_SECRET_PHRASE>


DEPLOYER_KEY=<ВАШ_МЕТАМАСК_ЧАСТНЫЙ_КЛЮЧ>


Пожалуйста, не используйте свои настоящие детали метамаски; эти ключи должны храниться в секрете. Вот почему мы помещаем их в файл среды и говорим git игнорировать их.


После того, как вы ввели вышеуказанные ключи в соответствующие переменные, выполните приведенные ниже команды.


truffle migrate --reset --network rinkeby


Как мы видим ниже, ваш смарт-контракт будет развернут в тестовой сети Rinkeby.


Один: Компиляция смарт-контракта


Два: развертывание смарт-контракта миграции


Три: развертывание смарт-контракта магазина


Ничего себе, вы много работали, чтобы добраться до этого момента. Вы только что закончили развертывание привлекательного смарт-контракта в сети блокчейна Ethereum. Мы подключим его к внешнему интерфейсу ReactJs во ЧАСТИ-ВТОРОЙ этого руководства.


Заключение


Вы завершили первую часть этого руководства; Далее мы узнаем, как подключить смарт-контракт Solidity, который мы только что развернули, к нашему внешнему интерфейсу React.


Вы можете увидеть готовую версию этого приложения здесь, а также проверить репозиторий git здесь, который вы должны пометить.


Увидимся снова в ЧАСТИ-ВТОРОЙ этот учебник.


Об авторе


Госпел Дарлингтон начал свой путь в качестве инженера-программиста в 2016 году. За эти годы он приобрел полноценные навыки работы со стеками JavaScript, такими как React, ReactNative, VueJs и другими.


В настоящее время он работает фрилансером, создает приложения для клиентов, пишет технические руководства, обучая других тому, что делает он.


Евангелие в Дарлингтоне открыто и доступно для вас. Вы можете связаться с ним на LinkedIn, Facebook, Github или на его веб-сайте.


Также опубликовано [здесь] (https://coinsbench.com/how-to-build-a-decentralized-ecommerce-platform-with-react-and-solidity-part-one-4a71a7e02f2a)



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE