Перейти до основного вмісту

Як написати та розгорнути NFT (Частина 1/3 серії посібників про NFT)

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

Оскільки невзаємозамінні токени (NFT) привертають увагу громадськості до блокчейну, зараз чудова нагода самостійно зрозуміти цей ажіотаж, опублікувавши власний контракт NFT (токен ERC-721) у блокчейні Етеріум!

У цьому посібнику ми крок за кроком розглянемо створення та розгортання смарт-контракту ERC-721 у тестовій мережі Sepolia за допомогою МетаМаск (відкривається в новій вкладці), Solidity (відкривається в новій вкладці), Hardhat (відкривається в новій вкладці), Pinata (відкривається в новій вкладці) та Alchemy (відкривається в новій вкладці) (не хвилюйтеся, якщо ви ще не розумієте, що все це означає — ми все пояснимо!).

У частині 2 цього посібника ми розглянемо, як можна використати наш смарт-контракт, щоб викарбувати NFT, а в частині 3 ми пояснимо, як переглянути ваш NFT у МетаМаск.

І, звісно, якщо у вас виникнуть запитання на будь-якому етапі, не соромтеся звертатися до Discord 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 — це те, що дійсно оживляє його, дозволяючи йому мати настроювані властивості, такі як назва, опис, зображення та інші атрибути. У частині 2 цього посібника ми опишемо, як налаштувати ці метадані.

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

Крок 11: Підключення МетаМаск та Alchemy до вашого проєкту

Тепер, коли ми створили гаманець МетаМаск, акаунт Alchemy та написали наш смарт-контракт, настав час об’єднати їх.

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

Щоб дізнатися більше про надсилання транзакцій, перегляньте документацію про транзакції.

Створіть файл .env у кореневому каталозі нашого проєкту та додайте до нього свій приватний ключ МетаМаск і URL-адресу HTTP 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. Якщо ні, ви завжди можете написати в Discord 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, який є запитом на читання інформації про нашу транзакцію за заданим хешем (типовий патерн під час надсилання транзакцій). Щоб дізнатися більше про надсилання транзакцій, перегляньте документацію про транзакції.

На цьому частина 1 цього посібника завершується. У частині 2 ми фактично взаємодіятимемо з нашим смарт-контрактом, карбуючи NFT, а в частині 3 ми покажемо вам, як переглянути ваш NFT у вашому гаманці Етеріум!