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

Как написать и развернуть NFT (Часть 1/3 серии руководств по NFT)

ERC-721
Alchemy
Solidity
смарт-контракты
Для начинающих
Суми Мудгил
22 апреля 2021 г.
13 минут на чтение

Поскольку NFT привлекают внимание общественности к блокчейну, сейчас отличная возможность разобраться в этом ажиотаже самостоятельно, опубликовав свой собственный контракт NFT (токен ERC-721) в блокчейне Эфириума!

В этом руководстве мы шаг за шагом рассмотрим создание и развертывание смарт-контракта ERC-721 в тестовой сети Sepolia с использованием МетаМаск (открывается в новой вкладке), Solidity (открывается в новой вкладке), Hardhat (открывается в новой вкладке), Pinata (открывается в новой вкладке) и Alchemy (открывается в новой вкладке) (не волнуйтесь, если вы пока не понимаете, что все это значит — мы все объясним!).

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

И, конечно же, если у вас возникнут вопросы на любом этапе, не стесняйтесь обращаться в Дискорд Alchemy (открывается в новой вкладке) или посетите документацию по API NFT от Alchemy (открывается в новой вкладке)!

Шаг 1: Подключение к сети Эфириума

Существует множество способов делать запросы к блокчейну Эфириума, но для простоты мы будем использовать бесплатный аккаунт на Alchemy (открывается в новой вкладке) — платформе для разработчиков блокчейна и API, которая позволяет нам взаимодействовать с цепью Эфириума без необходимости запускать собственные узлы.

В этом руководстве мы также воспользуемся инструментами разработчика Alchemy для мониторинга и аналитики, чтобы понять, как технически работает развертывание нашего смарт-контракта. Если у вас еще нет аккаунта Alchemy, вы можете бесплатно зарегистрироваться здесь (открывается в новой вкладке).

Шаг 2: Создание приложения (и ключа программного интерфейса приложения (API))

После создания аккаунта Alchemy вы можете сгенерировать ключ API, создав приложение. Это позволит нам делать запросы к тестовой сети Sepolia. Ознакомьтесь с этим руководством (открывается в новой вкладке), если хотите узнать больше о тестовых сетях.

  1. Перейдите на страницу «Create new app» (Создать новое приложение) на панели управления Alchemy, выбрав «Select an app» (Выбрать приложение) на панели навигации и нажав «Create new app».

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

  1. Дайте название вашему приложению (мы выбрали «My First NFT!»), добавьте краткое описание и выберите вариант использования. Затем найдите «Ethereum» и выберите сеть. Мы будем использовать Sepolia, рекомендованную тестовую сеть для разработки приложений (см. сети Эфириума).

  2. Нажмите «Next» (Далее), чтобы продолжить, затем «Create app» (Создать приложение), и все готово! Ваше приложение должно появиться в выпадающем меню панели навигации, а ключ API будет доступен для копирования.

Шаг 3: Создание аккаунта (адреса) Эфириума

Нам нужен аккаунт Эфириума для отправки и получения транзакций. В этом руководстве мы будем использовать МетаМаск — виртуальный кошелек в браузере, который используется для управления адресом вашего аккаунта Эфириума. Если вы хотите больше узнать о том, как работают транзакции в Эфириуме, ознакомьтесь с этой страницей от Фонда Ethereum.

Вы можете бесплатно скачать и создать аккаунт МетаМаск здесь (открывается в новой вкладке). При создании аккаунта, или если он у вас уже есть, обязательно переключитесь на тестовую сеть «Sepolia» с помощью меню выбора сети (чтобы мы не имели дело с реальными деньгами). Если вы не видите Sepolia в списке, откройте меню в правом верхнем углу, выберите «Networks» (Сети) и включите «Show test networks» (Показывать тестовые сети) (см. руководство МетаМаск по просмотру тестовых сетей (открывается в новой вкладке)).

Установка Sepolia в качестве вашей сети

Шаг 4: Добавление эфира из крана

Чтобы развернуть наш смарт-контракт в тестовой сети, нам понадобится немного ненастоящих ETH. Чтобы получить ETH в Sepolia, выберите один из кранов, перечисленных в информации о сети Sepolia, и введите адрес вашего аккаунта. Если один не работает, попробуйте другой, так как они иногда могут иссякать, а в некоторых есть правила допуска: например, кран Alchemy для Sepolia (открывается в новой вкладке) требует, чтобы на адресе получателя было не менее 0.001 ETH в основной сети Ethereum. Вскоре после этого вы должны увидеть ETH в своем аккаунте МетаМаск!

Шаг 5: Проверка баланса

Чтобы убедиться, что наш баланс на месте, давайте сделаем запрос eth_getBalance (открывается в новой вкладке) с помощью инструмента песочницы Alchemy (открывается в новой вкладке). Это вернет количество ETH в нашем кошельке. После того как вы введете адрес своего аккаунта МетаМаск и нажмете «Send Request», вы должны увидеть ответ вроде этого:

{ "jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000" }

Примечание Этот результат указан в Wei, а не в ETH. Wei используется как наименьшая единица измерения эфира. Конвертация из Wei в ETH: 1 ETH = 1018 Wei. Поэтому, если мы переведем 0xde0b6b3a7640000 в десятичную систему, мы получим 1*1018 Wei, что равно 1 ETH.

Фух! Наши ненастоящие деньги на месте.

Шаг 6: Инициализация нашего проекта

Сначала нам нужно будет создать папку для нашего проекта. Перейдите в командную строку и введите:

mkdir my-nft
cd my-nft

Теперь, когда мы находимся в папке нашего проекта, мы используем npm init для инициализации проекта. Если у вас еще не установлен npm, следуйте инструкциям по установке Node.js (открывается в новой вкладке) (для этого руководства нам понадобятся Node.js и npm).

npm init

Не имеет особого значения, как вы ответите на вопросы при установке; вот как это сделали мы для справки:

Одобрите файл package.json. Hardhat 3, который мы установим следующим, поддерживает только проекты модулей ES, поэтому отметьте проект как таковой:

npm pkg set type=module

И мы готовы к работе!

Шаг 7: Установка Hardhat (открывается в новой вкладке)

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

Hardhat 3 требует Node.js версии 22.13.0 или новее. Внутри нашего проекта my-nft выполните:

npm install --save-dev hardhat

Ознакомьтесь с этой страницей для получения более подробной информации об инструкциях по установке (открывается в новой вкладке).

Шаг 8: Создание проекта Hardhat

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

import { defineConfig } from "hardhat/config"

export default defineConfig({
  solidity: "0.8.34",
})

Здесь мы укажем все настройки для нашего проекта (на шаге 13). Пока что это просто указывает Hardhat, какую версию компилятора Solidity использовать.

Шаг 9: Добавление папок проекта

Чтобы поддерживать порядок в нашем проекте, мы создадим две новые папки. Перейдите в корневой каталог вашего проекта в командной строке и введите:

mkdir contracts
mkdir scripts
  • contracts/ — здесь мы будем хранить код нашего смарт-контракта NFT

  • scripts/ — здесь мы будем хранить скрипты для развертывания и взаимодействия с нашим смарт-контрактом

Шаг 10: Написание нашего контракта

Теперь, когда наша среда настроена, перейдем к более интересному: написанию кода нашего смарт-контракта!

Откройте проект my-nft в вашем любимом редакторе (нам нравится VSCode (открывается в новой вкладке)). Смарт-контракты пишутся на языке под названием Solidity, который мы и будем использовать для написания нашего смарт-контракта MyNFT.sol.‌

  1. Перейдите в папку contracts и создайте новый файл с именем MyNFT.sol

  2. Ниже приведен код нашего смарт-контракта NFT, который мы основали на реализации ERC-721 из библиотеки ОпенЗеппелин (открывается в новой вкладке). Скопируйте и вставьте приведенное ниже содержимое в ваш файл MyNFT.sol.

  3. Поскольку мы наследуем классы из библиотеки контрактов ОпенЗеппелин, в командной строке выполните npm install @openzeppelin/contracts, чтобы установить библиотеку в нашу папку. В этом руководстве используется OpenZeppelin Contracts 5.x, для которого требуется Solidity 0.8.24 или новее.

Итак, что именно делает этот код? Давайте разберем его построчно.

В начале нашего смарт-контракта мы импортируем три класса смарт-контрактов ОпенЗеппелин (открывается в новой вкладке):

  • @openzeppelin/contracts/token/ERC721/ERC721.sol содержит реализацию стандарта ERC-721, которую унаследует наш смарт-контракт NFT. (Чтобы быть действительным NFT, ваш смарт-контракт должен реализовывать все методы стандарта ERC-721.) Чтобы узнать больше об унаследованных функциях ERC-721, ознакомьтесь с определением интерфейса здесь (открывается в новой вкладке).

  • @openzeppelin/contracts/access/Ownable.sol настраивает контроль доступа (открывается в новой вкладке) в нашем смарт-контракте, поэтому только владелец смарт-контракта (вы) может чеканить NFT. Владельцем является адрес initialOwner, переданный в конструктор. (Обратите внимание, что включение контроля доступа — это исключительно вопрос предпочтений. Если вы хотите, чтобы любой мог чеканить NFT с помощью вашего смарт-контракта, удалите Ownable и Ownable(initialOwner) из определения контракта и конструктора, а также onlyOwner из функции mintNFT.)

  • @openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol расширяет ERC-721, чтобы каждый токен мог хранить свой собственный URI метаданных, который мы устанавливаем при чеканке.

После наших инструкций импорта идет наш пользовательский смарт-контракт NFT, который на удивление короткий — он содержит только счетчик, конструктор и одну функцию! Это благодаря нашим унаследованным контрактам ОпенЗеппелин, которые реализуют большинство методов, необходимых нам для создания NFT, таких как ownerOf, который возвращает владельца NFT, и transferFrom, который передает право собственности на NFT от одного аккаунта другому.

Счетчик _nextTokenId отслеживает общее количество отчеканенных NFT и устанавливает уникальный идентификатор для нашего нового NFT. (Каждому NFT, отчеканенному с использованием смарт-контракта, должен быть присвоен уникальный идентификатор — здесь наш уникальный идентификатор просто определяется общим количеством существующих NFT. ++_nextTokenId увеличивает счетчик перед его использованием, поэтому первый NFT, который мы чеканим с помощью нашего смарт-контракта, имеет идентификатор «1», наш второй NFT имеет идентификатор «2» и т. д.)

В нашем конструкторе ERC-721 вы заметите, что мы передаем 2 строки: «MyNFT» и «NFT». Первая переменная — это имя смарт-контракта, а вторая — его символ. Вы можете назвать каждую из этих переменных как пожелаете!

Наконец, у нас есть функция mintNFT(address recipient, string memory tokenURI), которая позволяет нам чеканить NFT! Вы заметите, что эта функция принимает две переменные:

  • address recipient указывает адрес, который получит ваш свежеотчеканенный NFT

  • string memory tokenURI — это строка, которая должна указывать на JSON-документ, описывающий метаданные NFT. Метаданные NFT — это то, что действительно оживляет его, позволяя ему иметь настраиваемые свойства, такие как имя, описание, изображение и другие атрибуты. Во второй части этого руководства мы опишем, как настроить эти метаданные.

mintNFT вызывает некоторые методы из унаследованной библиотеки ERC-721 и в конечном итоге возвращает число, представляющее идентификатор свежеотчеканенного NFT.

Шаг 11: Подключение МетаМаск и Alchemy к вашему проекту

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

Каждая транзакция, отправленная из вашего виртуального кошелька, требует подписи с использованием вашего уникального приватного ключа. Чтобы предоставить нашей программе это разрешение, мы можем безопасно сохранить наш приватный ключ (и ключ API Alchemy) в файле среды.

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

Создайте файл .env в корневом каталоге нашего проекта и добавьте в него ваш приватный ключ МетаМаск и HTTP URL API Alchemy.

Ваш файл .env теперь должен выглядеть так:

API_URL="https://eth-sepolia.g.alchemy.com/v2/your-api-key"
PRIVATE_KEY="your-metamask-private-key"

Чтобы фактически подключить их к нашему коду, мы сошлемся на эти переменные в нашем файле hardhat.config.js на шаге 13. Node.js может самостоятельно читать файлы .env, поэтому устанавливать дополнительные пакеты не нужно.

Не коммитьте .env! Пожалуйста, убедитесь, что вы никогда не делитесь и не раскрываете свой файл .env кому-либо, так как тем самым вы ставите под угрозу свои секретные данные. Если вы используете систему контроля версий, добавьте ваш .env в файл gitignore (открывается в новой вкладке).

Шаг 12: Установка Ethers.js

Ethers.js — это библиотека, которая упрощает взаимодействие и выполнение запросов к Эфириуму, оборачивая стандартные методы JSON-RPC в более удобные для пользователя методы.

Hardhat позволяет очень легко интегрировать плагины (открывается в новой вкладке) для дополнительных инструментов и расширенной функциональности. Мы воспользуемся плагином Ethers (открывается в новой вкладке) для развертывания контрактов (в Ethers.js (открывается в новой вкладке) есть очень понятные методы развертывания контрактов).

В каталоге вашего проекта введите:

npm install --save-dev @nomicfoundation/hardhat-ethers ethers

Мы также добавим плагин в наш hardhat.config.js на следующем шаге.

Шаг 13: Обновление hardhat.config.js

К этому моменту мы добавили несколько зависимостей и плагинов, теперь нам нужно обновить hardhat.config.js, чтобы наш проект знал о них всех.

Обновите ваш hardhat.config.js, чтобы он выглядел так:

configVariable указывает Hardhat считывать каждое значение из переменной среды только тогда, когда это необходимо, поэтому такие команды, как compile, работают даже до того, как значения будут установлены. Если вы предпочитаете не хранить свой приватный ключ в виде обычного текстового файла, Hardhat также может считывать переменные конфигурации из зашифрованного хранилища ключей (открывается в новой вкладке).

Шаг 14: Компиляция нашего контракта

Чтобы убедиться, что пока все работает, давайте скомпилируем наш контракт. Задача компиляции — одна из встроенных задач Hardhat.

Из командной строки выполните:

npx hardhat compile

При первой компиляции Hardhat загружает компилятор Solidity. Затем вы должны увидеть что-то вроде Compiled 1 Solidity file with solc 0.8.34. Если нет, вы всегда можете написать в Дискорд Alchemy (открывается в новой вкладке).

Шаг 15: Написание нашего скрипта развертывания

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

Перейдите в папку scripts/ и создайте новый файл с именем deploy.js, добавив в него следующее содержимое:

Давайте разберем, что делает каждая из этих строк кода.

const { ethers } = await network.create()

В Hardhat 3 скрипт явно открывает подключение к сети. network.create() подключается к сети, которую вы выбираете с помощью параметра --network при запуске скрипта, а плагин hardhat-ethers добавляет объект ethers к этому подключению.

const [deployer] = await ethers.getSigners()

getSigners() возвращает аккаунты, настроенные для сети. В Sepolia это аккаунт, приватный ключ которого вы поместили в .env. Мы передаем его адрес в конструктор, чтобы вы стали владельцем контракта.

const MyNFT = await ethers.getContractFactory("MyNFT")

ContractFactory в Ethers.js — это абстракция, используемая для развертывания новых смарт-контрактов, поэтому MyNFT здесь — это фабрика для экземпляров нашего контракта NFT. При использовании плагина hardhat-ethers экземпляры ContractFactory и Contract по умолчанию подключаются к первому подписанту.

const myNFT = await MyNFT.deploy(deployer.address)

Вызов deploy() для ContractFactory запустит развертывание и вернет Promise, который разрешается в Contract. Это объект, у которого есть метод для каждой функции нашего смарт-контракта. Аргументы, которые вы передаете в deploy(), отправляются в конструктор контракта, здесь это адрес initialOwner.

waitForDeployment() ожидает, пока транзакция развертывания не будет включена в блок, а getAddress() возвращает адрес нового контракта. См. документацию по контрактам Ethers.js (открывается в новой вкладке) для получения более подробной информации.

Шаг 16: Развертывание нашего контракта

Мы наконец-то готовы развернуть наш смарт-контракт! Вернитесь в корень каталога вашего проекта и в командной строке выполните:

npx hardhat run scripts/deploy.js --network sepolia

Затем вы должны увидеть что-то вроде:

Contract deployed to address: 0x4C5266cCc4b3F426965d2f51b6D910325a0E7650

Если мы перейдем в Etherscan для Sepolia (открывается в новой вкладке) и выполним поиск по адресу нашего контракта, мы должны увидеть, что он был успешно развернут. Если вы не видите его сразу, пожалуйста, подождите немного, так как это может занять некоторое время. Транзакция будет выглядеть примерно так:

Просмотр адреса вашей транзакции в Etherscan

Адрес «From» (От) должен совпадать с адресом вашего аккаунта МетаМаск, а в адресе «To» (Кому) будет указано «Contract Creation» (Создание контракта). Если мы нажмем на транзакцию, мы увидим адрес нашего контракта в поле «To»:

Просмотр адреса вашего контракта в Etherscan

Дааааа! Вы только что развернули свой смарт-контракт NFT в цепи Эфириума (в тестовой сети)!

Чтобы понять, как это работает технически, вы можете посмотреть на запросы, полученные вашим приложением, на панели управления Alchemy (открывается в новой вкладке).

Там вы увидите несколько вызовов JSON-RPC, которые Hardhat/Ethers сделали для нас внутренне, когда мы вызвали функцию .deploy(). Здесь следует выделить два важных вызова: eth_sendRawTransaction, который является запросом на фактическую запись нашего смарт-контракта в цепь Sepolia, и eth_getTransactionByHash, который является запросом на чтение информации о нашей транзакции по заданному хешу (типичный паттерн при отправке транзакций). Чтобы узнать больше об отправке транзакций, ознакомьтесь с документацией по транзакциям.

На этом первая часть данного руководства завершена. Во второй части мы будем взаимодействовать с нашим смарт-контрактом, чеканя NFT, а в третьей части мы покажем вам, как просматривать ваш NFT в вашем кошельке Эфириума!