Подробное руководство по разработке полного стека Web3
Автор
Oracle LabsСоздание полностекового web3-приложения с помощью Next.js, Polygon, Solidity, The Graph, IPFS и Hardhat.
В этом подробном руководстве вы узнаете об инструментах, протоколах и фреймворках для создания web3-приложений полного стека, а главное - как собрать все вместе, чтобы заложить основу для реализации ваших собственных идей в будущем.
Перевод статьи: The Complete Guide to Full Stack Web3 Development
Кодовая база для этого приложения находится здесь.
Основная сеть, в которой мы будем разворачивать приложение, - Polygon. Я выбрал Polygon из-за ее низкой стоимости транзакций, быстрого времени подтверждения блока и текущей адаптации сети.
Тем не менее, мы будем строить на виртуальной машине Ethereum (EVM), поэтому вы можете применить эти навыки для создания приложений для десятков других сетей блокчейн, включая Ethereum, Celo, Avalanche и многие другие.
Приложение, которое мы будем создавать, представляет собой блог с полным стеком, а также систему управления контентом (CMS), что означает, что у вас будет открытый, публичный и композитный бэк-энд, который можно переносить и повторно использовать где угодно.
К концу этого урока у вас должно быть хорошее понимание наиболее важных частей современного стека web3 и того, как создавать производительные, масштабируемые, децентрализованные блокчейн-приложения с полным стеком.
Мы будем использовать части этого стека для данного приложения:
- Блокчейн - Polygon (с дополнительным провайдером RPC)
- Среда разработки Ethereum - Hardhat
- Front end framework - Next.js & React
- Библиотека веб-клиента Ethereum - Ethers.js
- Файловое хранилище - IPFS
- Индексирование и запросы - Graph Protocol
Научившись использовать эти строительные блоки, мы сможем создавать множество типов приложений, поэтому цель этого урока - показать, как они работают и как сочетаются друг с другом.
Давайте приступим!
Необходимые условия
- Node.js установлен на вашей локальной машине
- Расширение MetaMask Chrome, установленное в вашем браузере
Настройка проекта
Здесь мы создадим шаблоны приложений, установим все необходимые зависимости и настроим проект.
Код будет прокомментирован, чтобы вы могли понять, что происходит, и я также буду описывать некоторые из происходящих событий на протяжении всего урока.
Чтобы начать, создайте новое приложение Next.js и перейдите в новую директорию:
Затем перейдите в новую директорию и установите следующие зависимости с помощью npm, yarn или pnpm:
Обзор некоторых из этих зависимостей:
- hardhat - среда разработки Ethereum
- web3modal - Простая в использовании библиотека, которая позволяет пользователям подключать свои кошельки к вашему приложению
- react-markdown и simplemde - редактор Markdown и рендерер Markdown для CMS
- @emotion/css - Отличная библиотека CSS в JS
- @openzeppelin/contracts - Реализация полезных стандартов и функциональности смарт-контрактов с открытым исходным кодом.
Далее мы инициализируем локальную среду разработки смарт-контрактов.
Это должно создать базовую среду разработки Solidity, которую мы будем использовать. Вы должны увидеть несколько новых файлов и папок, включая contracts, scripts, test и hardhat.config.js.
Далее, давайте обновим конфигурацию hardhat в файле hardhat.config.js.
Обновите этот файл следующим кодом:
Здесь мы настроили локальную среду разработки hardhat, а также установили (и закомментировали) среды Polygon mainnet и Mumbai testnet, которые мы будем использовать для развертывания в Polygon.
Далее, давайте добавим несколько основных глобальных CSS, которые нам понадобятся для оформления редактора разметки для CMS.
Откройте файл styles/globals.css и добавьте следующий код под существующим css:
Далее мы создадим несколько SVG-файлов для изображений приложения: один для логотипа и один для кнопки со стрелкой.
Создайте logo.svg и right-arrow.svg в общей папке и скопируйте связанный SVG-код в каждый из этих файлов.
Смарт-контракт
Далее давайте создадим смарт-контракт, который будет управлять нашим блогом и CMS.
Создайте новый файл в папке contracts под названием Blog.sol.
Добавьте в него следующий код:
Этот контракт позволяет владельцу создавать и редактировать сообщения, а любому человеку - получать сообщения.
Чтобы сделать этот смарт-контракт без прав доступа, можно убрать модификатор onlyOwner и использовать The Graph для индексации и запроса постов по владельцу.
Далее давайте напишем базовый тест для проверки наиболее важных функций, которые мы будем использовать.
Для этого откройте файл test/sample-test.js и обновите его следующим кодом:
Next, run the test by opening your terminal and running this command:
Развертывание контракта
Теперь, когда контракт написан и протестирован, давайте попробуем развернуть его в локальной тестовой сети.
Чтобы запустить локальную сеть, откройте в терминале как минимум два отдельных окна. В одном окне запустите следующий скрипт:
Когда мы выполним эту команду, вы должны увидеть список адресов и закрытых ключей.
Это 20 тестовых аккаунтов и адресов, созданных для нас, которые мы можем использовать для развертывания и тестирования наших смарт-контрактов. Каждый счет также загружен 10 000 ненастоящих Эфиров. Через некоторое время мы узнаем, как импортировать тестовый счет в MetaMask, чтобы мы могли его использовать.
Далее нам нужно развернуть контракт в тестовой сети. Сначала измените имя файла scripts/sample-script.js на scripts/deploy.js.
Затем обновите файл с этим новым сценарием развертывания:
Теперь в отдельном окне (пока локальная сеть все еще работает) мы можем запустить сценарий развертывания и дать флаг CLI, что мы хотим развернуть в нашей локальной сети:
Когда контракт будет развернут, вы должны увидеть некоторый результат в вашем сетевом терминале 🎉.
Импорт тестового счета в ваш кошелек
Чтобы отправлять транзакции смарт-контракту, нам нужно подключить наш кошелек MetaMask, используя один из аккаунтов, созданных при запуске npx hardhat node. В списке контрактов, который выводит CLI, вы должны увидеть как номер счета, так и закрытый ключ:
Мы можем импортировать эту учетную запись в MetaMask, чтобы начать использовать некоторые из доступных там ненастоящих Eth.
Скопируйте и вставьте самый первый закрытый ключ, зарегистрированный в CLI, и нажмите Импортировать. После того, как учетная запись будет импортирована, вы должны увидеть Eth в учетной записи:
Убедитесь, что вы импортировали первый аккаунт в списке аккаунтов (Account #0), так как он будет использоваться по умолчанию при развертывании контракта и, следовательно, будет владельцем контракта.
Теперь, когда у нас есть развернутый смарт-контракт и готовый к использованию счет, мы можем начать взаимодействовать с ним из приложения Next.js.
Приложение Next.js
Далее давайте напишем код для приложения.
Первое, что мы сделаем, это настроим пару переменных окружения, которые мы будем использовать для переключения между локальной средой тестирования, Mumbai testnet и Polygon mainnet.
Создайте новый файл с именем .env.local в корне вашего проекта и добавьте следующую конфигурацию для начала:
Мы сможем переключать эти переменные между local, testnet и mainnet, чтобы переключаться между ними.
Это позволит нам ссылаться на наше окружение как на клиенте, так и на сервере. Чтобы узнать больше о том, как работают переменные окружения в Next.js, ознакомьтесь с документацией здесь.
context.js
Далее давайте создадим контекст приложения. Контекст даст нам простой способ обмена состоянием во всем приложении.
Создайте файл с именем context.js и добавьте в него следующий код:
Разметка и навигация
Далее откроем файл pages/_app.js. Здесь мы обновим код, чтобы включить навигацию, подключение к кошельку, контекст и некоторые базовые стили.
Эта страница служит в качестве обертки или макета для остальной части приложения.
Точка входа
Теперь, когда макет настроен, давайте создадим точку входа в приложение.
Эта страница будет получать список постов из сети и отображать заголовки постов в виде списка. Когда пользователь нажмет на пост, мы переведем его на другую страницу для детального просмотра (страница будет создана позже).
Создание постов
Далее создайте новый файл в каталоге pages с именем create-post.js.
Он будет содержать маршрут, который позволит нам создавать посты и сохранять их в сети.
У нас также будет возможность загружать и сохранять изображение обложки в IPFS, при этом хэш ipfs-загрузки будет закреплен по цепочке с остальными данными.
Добавьте следующий код в этот файл:
Просмотр сообщения
Теперь, когда у нас есть возможность создавать посты, как нам перемещаться и просматривать посты? Мы хотим иметь возможность просматривать пост в маршруте, который выглядит примерно так: myapp.com/post/some-post-id.
Мы можем сделать это несколькими различными способами с помощью динамических маршрутов next.js.
Мы будем использовать серверную выборку данных с помощью getStaticPaths и getStaticProps, которые создадут эти страницы во время сборки, используя массив постов, запрашиваемых из сети.
Для этого создайте новую папку в каталоге pages с именем posts и файл в этой папке с именем [id].js. Добавьте туда следующий код:
Редактирование сообщения
Последняя страница, которую нам нужно создать, - это способ редактирования существующих постов.
Эта страница перенесет некоторые функции из pages/create-post.js, а также pages/post/[id].js. Мы сможем переключаться между просмотром и редактированием сообщения.
Создайте новую папку в каталоге pages под названием edit-post и файл [id].js в ней. Затем добавьте следующий код:
Тестирование
Теперь мы можем протестировать его.
Для этого убедитесь, что вы уже развернули контракт в сети в предыдущих шагах и у вас все еще работает локальная сеть.
Откройте новое окно терминала и запустите приложение Next.js:
Вы можете заметить, что приложение работает не так быстро, как могло бы быть, но Next.js работает молниеносно в производстве.
Чтобы запустить производственную сборку, выполните следующие команды:
Развертывание на Polygon
Теперь, когда проект запущен и протестирован локально, давайте развернем его в Polygon. Мы начнем с развертывания в Мумбаи, тестовой сети Polygon.
Первое, что нам нужно будет сделать, это установить один из наших закрытых ключей из кошелька в качестве переменной окружения.
Чтобы получить приватный ключ, вы можете экспортировать его непосредственно из MetaMask.
Закрытые ключи ни при каких обстоятельствах не предназначены для публичного распространения. Рекомендуется никогда не записывать закрытый ключ в файл. Если вы все же решили это сделать, убедитесь, что используете кошелек для тестирования, и ни при каких обстоятельствах не выкладывайте файл с закрытым ключом в систему контроля исходного кода и не публикуйте его публично.
Если вы работаете на Mac, вы можете установить переменную окружения из командной строки следующим образом (не забудьте запустить сценарий развертывания из этого же терминала и сессии):
Настройка сети
Далее нам нужно переключиться с локальной тестовой сети на Mumbai Testnet.
Для этого нам нужно создать и настроить конфигурацию сети.
Здесь мы добавим следующие конфигурации для тестовой сети Mumbai, перечисленные здесь:
Имя сети: Mumbai TestNet
Новый URL RPC: https://rpc-mumbai.matic.today
Идентификатор цепи: 80001
Символ валюты: Matic
Сохраните это, после чего вы сможете переключиться на новую сеть и использовать ее!
Наконец, для взаимодействия с приложениями вам понадобятся токены testnet Polygon.
Чтобы получить их, вы можете посетить Polygon Faucet, введя адреса кошельков, с которых вы хотели бы запросить токены.
Развертывание в сети Polygon
Теперь, когда у вас есть токены, вы можете развернуть сеть Polygon!
Для этого убедитесь, что адрес, связанный с закрытым ключом, с помощью которого вы развертываете свой контракт, получил токены, чтобы оплатить комиссию за транзакцию.
Затем откомментируйте конфигурацию mumbai в файле hardhat.config.js:
Для развертывания в тестовой сети Polygon выполните следующую команду:
Если вы столкнулись с этой ошибкой: ProviderError: RPCError, публичный RPC может быть перегружен. В производственных условиях рекомендуется использовать RPC-провайдер, например Infura, Alchemy или Quicknode.
Далее обновите переменные окружения в .env.local, чтобы они стали testnet:
Затем перезапустите сервер, чтобы зарегистрировать изменения в переменных окружения:
Теперь вы можете протестировать приложение в новой сети 🎉!
Если у вас возникли проблемы с подключением к публичной конечной точке RPC Mumbai, подумайте о замене конечных точек в вашем приложении на конечные точки от провайдера RPC, например Infura, Alchemy или Quicknode.
Создание API подграфа
По умолчанию единственными шаблонами доступа к данным являются две функции, которые мы прописали в контракте, fetchPost и fetchPosts.
Это хорошее место для начала, но когда ваше приложение начнет расширяться, вы, вероятно, обнаружите, что вам нужен более гибкий и масштабируемый API.
Например, что если мы захотим дать пользователю возможность искать сообщения, получать сообщения, созданные определенным пользователем, или сортировать сообщения по дате их создания?
Мы можем встроить все эти функции в API, используя протокол The Graph. Давайте посмотрим, как это сделать.
Создание проекта в The Graph
Чтобы начать работу, зайдите на сервис The Graph и зарегистрируйтесь или создайте новую учетную запись.
Затем перейдите на приборную панель и нажмите на Add Subgraph, чтобы создать новый подграф.
Настройте ваш подграф со следующими свойствами:
Имя подграфа - Blogcms
Подзаголовок - Подграф для запроса данных о постах.
Дополнительно - заполните свойства описания и URL GITHUB.
После создания подграфа мы инициализируем его локально с помощью Graph CLI.
Инициализация нового подграфа с помощью Graph CLI
Далее установите Graph CLI:
После установки Graph CLI вы можете инициализировать новый подграф с помощью команды Graph CLI init.
Поскольку мы уже развернули наш контракт в сети, мы можем инициализировать с адреса этого контракта, передав адрес контракта с помощью флага --from-contract.
Этот адрес доступен для ссылки в config.js как contractAddress.
Эта команда создаст базовый подграф на основе адреса контракта, переданного в качестве аргумента в команде --from-contract. Используя этот адрес контракта, CLI инициализирует несколько вещей в вашем проекте для начала работы (включая получение abis и сохранение их в каталоге abis).
При передаче параметра --index-events CLI автоматически заполнит некоторый код как в schema.graphql, так и в src/mapping.ts на основе событий, испускаемых контрактом.
Основная конфигурация и определение подграфа находится в файле subgraph.yaml. Кодовая база подграфа состоит из нескольких файлов:
- subgraph.yaml: файл YAML, содержащий манифест подграфа
- schema.graphql: схема GraphQL, определяющая, какие данные хранятся для вашего подграфа, и как запрашивать их через GraphQL
- AssemblyScript Mappings: Код на языке AssemblyScript, который переводит данные о событиях в Ethereum в сущности, определенные в вашей схеме (например, mapping.ts в этом учебнике).
Записи в subgraph.yaml, с которыми мы будем работать, следующие:
- description (опционально): человекочитаемое описание того, что представляет собой подграф. Это описание отображается в Graph Explorer, когда подграф развертывается в Hosted Service.
- repository (необязательный): URL репозитория, в котором можно найти манифест подграфа. Он также отображается в Graph Explorer.
- dataSources.source: адрес смарт-контракта, источником которого является подграф, и abi смарт-контракта, который будет использоваться. Адрес необязателен; его опущение позволяет индексировать совпадающие события из всех контрактов.
- dataSources.source.startBlock (необязательно): номер блока, с которого источник данных начинает индексирование. В большинстве случаев мы рекомендуем использовать блок, в котором был создан контракт.
- dataSources.mapping.entities : сущности, которые источник данных записывает в хранилище. Схема для каждой сущности определяется в файле schema.graphql.
- dataSources.mapping.abis: один или несколько именованных ABI-файлов для исходного контракта, а также для любых других смарт-контрактов, с которыми вы взаимодействуете в связке.
- dataSources.mapping.eventHandlers: список событий смарт-контракта, на которые реагирует данный подграф, и обработчики в отображении - ./src/mapping.ts в примере - которые преобразуют эти события в сущности в хранилище.
Определение сущностей
В The Graph вы определяете типы сущностей в schema.graphql, а Graph Node генерирует поля верхнего уровня для запросов отдельных экземпляров и коллекций этого типа сущностей. Каждый тип, который должен быть сущностью, должен быть аннотирован директивой @entity.
Сущности / данные, которые мы будем индексировать, - это токен и пользователь. Таким образом, мы сможем индексировать токены, созданные пользователями, а также самих пользователей.
Для этого обновите schema.graphql следующим кодом:
Теперь, когда мы создали схему GraphQL для нашего приложения, мы можем сгенерировать сущности локально, чтобы начать использовать их в связках, созданных CLI:
Чтобы сделать работу с умными контрактами, событиями и сущностями простой и безопасной для типов, Graph CLI генерирует типы AssemblyScript из комбинации схемы GraphQL подграфа и ABI контрактов, включенных в источники данных.
Обновление подграфа с сущностями и связками
Теперь мы можем настроить subgraph.yaml на использование сущностей, которые мы только что создали, и настроить их сопоставления.
Для этого сначала обновите поле dataSources.mapping.entities с сущностями User и Token:
Далее нам нужно найти блок, в котором был развернут контракт (необязательно). Это нужно для того, чтобы мы могли установить начальный блок для индексатора, чтобы начать синхронизацию, и чтобы ему не нужно было синхронизироваться с блока genesis. Стартовый блок можно найти на сайте https://mumbai.polygonscan.com/ и вставить адрес вашего контракта.
Наконец, обновите конфигурацию, чтобы добавить startBlock
Сопоставления ассемблера
Далее откройте src/mappings.ts, чтобы записать маппинги, которые мы определили в наших eventHandlers подграфа.
Обновите файл следующим кодом:
Эти связки будут обрабатывать события, когда создается новый пост и когда пост обновляется. При наступлении этих событий связки будут сохранять данные в подграф.
Запуск сборки
Далее давайте запустим сборку, чтобы убедиться, что все настроено правильно. Для этого выполните команду build:
Если сборка прошла успешно, вы должны увидеть новую папку сборки, созданную в вашем корневом каталоге.
Развертывание подграфа
Для развертывания мы можем выполнить команду deploy. Для развертывания сначала нужно скопировать маркер доступа для вашей учетной записи, доступный в Graph Dashboard:
Затем выполните следующую команду:
После развертывания подграфа он должен появиться на приборной панели.
При нажатии на подграф откроется подробная информация о подграфе:
Запрос данных
Теперь, когда мы находимся в приборной панели, мы должны иметь возможность начать запрашивать данные. Выполните следующий запрос, чтобы получить список постов:
Мы также можем настроить направление заказов по дате создания:
Мы также можем выполнить полнотекстовый поиск по заголовку или содержанию сообщения:
Поздравляем, теперь вы создали более гибкий API, который можно использовать для запросов в вашем приложении!
Чтобы узнать, как использовать конечную точку API в вашем приложении, ознакомьтесь с документацией здесь или видео здесь.
Следующие шаги
Если вы хотите решить сложную задачу, подумайте о добавлении функциональности, которая позволит вам обновлять изображение обложки в pages/edit-post/[id].js.
Если вы хотите развернуть свое приложение и сделать его живым, ознакомьтесь с Vercel.
https://dev.to/dabit3/the-complete-guide-to-full-stack-web3-development-4g74 | The Complete Guide to Full Stack Web3 Development