Добро пожаловать в полное руководство по созданию и развертыванию смарт-контракта NFT на RSK.
Введение
В этом руководстве мы рассмотрим пошаговый процесс создания смарт-контракта ERC-721 и его развертывания в тестовой сети RSK с помощью следующих инструментов: Solidity, Hardhat, Ether.js, RSK Testnet, IPFS, Pinata и Test RBTC из крана. Не волнуйтесь, если эти термины для вас новые — мы их объясним!
В этом руководстве мы сделаем следующее.
- Краткое введение в НФТ и ERC-721
- Настройка вашего окружения
- Что такое IPFS?
- Как настроить учетную запись Pinata
- Создание метаданных NFT (JSON-файл)
- Создание смарт-контракта ERC 721
- Развернуть смарт-контракт на блокчейне РСК
Предварительные условия
Чтобы следовать этому руководству, вы должны обладать знаниями в:
- Основы смарт-контрактов с использованием Solidity
- JavaScript
- Командная строка
- Git
Если вы не знакомы с вышеперечисленным, рекомендуется изучить основы, перейдя по ссылкам выше, прежде чем приступить к этому уроку о том, как создать и развернуть свой проект NFT в RSK Testnet.
Что такое невоспроизводимый токен (NFT)?
Сгораемость — это взаимозаменяемость и делимость чего-либо. Сменный токен обладает обоими этими свойствами и ведет себя подобно фиатным деньгам; в то время как несменный токен не является ни сменным, ни делимым и ведет себя подобно многим реальным объектам.
ERC-20 является наиболее распространенным техническим стандартом для сменных токенов (FTs); а ERC-721 — наиболее распространенный технический стандарт для несменных токенов (NFTs).
Несгораемые токены — это термин, используемый для описания цифровых активов, которые представляют собой объекты реального мира, такие как искусство, мебель, файл песни, внутриигровые предметы, ваш компьютер или даже недвижимость. В отличие от токенов ERC-20, токены, созданные в рамках ERC-721, не являются взаимозаменяемыми. Это происходит из-за того, что хотя два NFT могут выглядеть идентично друг другу, они оба содержат уникальную информацию. У нефункционирующих токенов также отсутствует еще одна особенность их аналогов ERC-20 — они не являются делимыми, что означает, что вы не можете владеть частью NFT.
NFT могут быть использованы в следующих случаях:
- Медицинские записи и проверка личности — бухгалтерские книги NFT могут хранить медицинские записи человека без ущерба для конфиденциальности или риска фальсификации из внешних источников.
- Недвижимость — НФТ можно использовать для передачи документов на землю, предоставления доказательств права собственности и даже отслеживания изменений стоимости недвижимости с течением времени с помощью НФТ с временной меткой.
- Обеспечение подлинности товаров — НФТ могут быть использованы для обеспечения подлинности приобретаемого товара. НФТ также можно использовать для хранения информации о процессе производства, что гарантирует честную торговлю.
- Академические дипломы — НФТ также являются хорошим способом представления академических дипломов. НФТ могут предоставить подтверждение посещаемости, полученной степени и другую важную информацию, которая будет храниться в цепочке НФТ и не может быть изменена или взломана.
- Игровая индустрия — НФТ могут быть интегрированы в игровой мир благодаря возможности кросс-платформенной игры с НФТ.
Что такое ERC-721?
ERC-721 — это стандарт для представления прав собственности на неиграбельные токены, где каждый токен уникален. Он обеспечивает такие функции, как перевод токенов с одного счета на другой, получение текущего баланса токенов на счете, получение владельца конкретного токена, а также общего количества токенов, доступных в сети.
EIP-721 — это стандартный интерфейс для нефункциональных токенов.
**Настройка среды разработки
Что такое Hardhat?
Hardhat — это среда разработки, которая позволяет компилировать, развертывать, тестировать и отлаживать программное обеспечение RSK. Она помогает управлять и автоматизировать повторяющиеся задачи, присущие процессу создания приложений Blockchain.
Ознакомьтесь с пошаговым руководством по настройке проекта Hardhat для подключения к RSK Testnet.
Что такое ethers.js?
Ethers.js — это библиотека JavaScript, которая позволяет разработчикам взаимодействовать с блокчейном. Библиотека включает в себя утилитарные функции на JavaScript и TypeScript, а также может поддерживать кошельки.
Что такое tRBTC (Smart Bitcoin в Testnet)?
Тестовый смарт-биткоин (tRBTC) — это токен, используемый для оплаты выполнения транзакций в среде РСК Testnet.
Посмотрите видеоурок о том, как получить tRBTC из крана РСК Testnet.
Что такое IPFS?
IPFS (Interplanetary File System) — это файловая система/протокол для хранения и обмена контентом, она позволяет хранить файлы, отслеживая их в распределенной сети. Эта система хранения позволяет напрямую взаимодействовать через безопасную и глобальную P2P-сеть.
Файлы IPFS являются адресуемыми по содержимому. Это означает, что в качестве метки для указания на материал в IPFS используются идентификаторы содержимого, или CID. Эти CID основаны на содержимом самих файлов, и их можно представить в виде хэшей. Они не указывают, где хранится содержимое, но образуют своего рода адрес, основанный на самом содержимом. Это свойство делает IPFS подходящей платформой для ссылки на изображения в смарт-контрактах. Мы будем использовать IPFS для размещения/хранения наших изображений NFT.
Настройте метаданные для вашего NFT с помощью Pinata
Чтобы получить наш параметр tokenURI, который должен разрешиться в JSON-документ, описывающий метаданные нашего NFT, включающие такие свойства, как название, описание, изображение и другие атрибуты, нам нужно настроить Pinata, удобный IPFS API и инструментарий, для хранения нашего актива NFT и метаданных.
Проще говоря, tokenURI в NFT — это уникальный идентификатор того, как «выглядит» токен. URI может быть вызовом API через HTTPS, хэшем IPFS или чем-либо еще, что является уникальным.
Если у вас нет аккаунта Pinata, зарегистрируйтесь бесплатно здесь и выполните шаги по верификации вашей электронной почты.
После того, как вы создали учетную запись:
- Перейдите на страницу «Файлы» и нажмите синюю кнопку «Загрузить» в левом верхнем углу страницы.
- Загрузите в Pinata два изображения кошек — это будет актив изображения для ваших NFT. Не стесняйтесь назвать актив как угодно.
- После загрузки вы увидите информацию о файле в таблице на странице «Файлы». Вы также увидите колонку CID. Вы можете скопировать CID, нажав на кнопку копирования рядом с ним. Вы можете просмотреть свою загрузку по адресу: https://gateway.pinata.cloud/ipfs/.
Теперь давайте создадим и загрузим в pinata еще два файла, каждый из которых содержит информацию о двух кошках в формате JSON.
В корневом каталоге создайте новую папку nft- metadata и добавьте в нее следующие json-коды:
Первый файл называется doerak.json
.
{
"attributes": [
{
"trait_type": "Breed",
"value": "European short hair"
},
{
"trait_type": "Parent",
"value": "Gino Osahon"
}
],
"description": "Doerak. Gray & white kitty",
"image": "ipfs://QmX7P1aswXLKLPd7RqbtwrNGD9CzGjvNFKmdEhWtBmoyiS",
"name": "Doerak"
}
Второй файл называется luna.json
.
{
"attributes": [
{
"trait_type": "Breed",
"value": "European short hair"
},
{
"trait_type": "Parent",
"value": "Alex Shenshin"
}
],
"description": "Luna. Ginger kitty",
"image": "ipfs://QmZZfJcrppaRiq5dWtC6zpnGZRNoVwdyh69VoA89xGW5Yt",
"name": "Luna"
}
Не стесняйтесь изменять данные в json. Вы можете удалить или добавить в раздел атрибутов. Самое главное, убедитесь, что поле image указывает на местоположение вашего образа IPFS.
После того как вы закончите редактировать JSON-файл, сохраните его и загрузите в Pinata, выполнив те же шаги, что и при загрузке изображения.
Генерирование начальной фразы
В корневом каталоге создайте файл secret.json и добавьте в него свою начальную фразу.
Начальные фразы — это человекочитаемая версия ваших закрытых ключей. Вы можете подписывать транзакции и восстанавливать потерянные учетные записи, используя часть своей мнемонической фразы. Мнемонические или семенные фразы могут состоять из 12-24 слов в зависимости от экосистемы блокчейна, с которой вы имеете дело. Любое приложение может генерировать свою мнемоническую фразу в целях безопасности.
{
"mnemonic": "please put your twelve words long mnemonic phrase to this string now"
}
Для взаимодействия с блокчейном РСК необходима учетная запись, которая состоит из закрытого ключа, открытого ключа и адреса.
BIP-39 — это технический стандарт, который позволяет генерировать несколько учетных записей из набора словарных слов плюс путь деривации. Многие программные библиотеки и кошельки реализуют этот технический стандарт, включая ethers.js и MetaMask, которые мы будем использовать в этом учебнике. Обратите внимание, что к начальным фразам следует относиться так же безопасно, как и к приватным ключам, поэтому не используйте тот, который приведен в этом руководстве, в RSK Mainnet — его использование достаточно только для RSK Testnet.
Конфигурация хардхата
Давайте объясним, что такое файл hardhat.config.js. Этот файл конфигурации всегда выполняется при запуске, прежде чем произойдет что-либо еще, и у него есть две основные задачи. Вы можете определить задачу как асинхронную функцию JavaScript с некоторыми связанными метаданными. Эти метаданные используются Hardhat для автоматизации задач, или асинхронные функции JavaScript получают доступ к среде выполнения Hardhat, которая раскрывает их конфигурацию и параметры.
task('deploy', 'Deploys smart contract to a blockchain').setAction(async () => {
const meowContractFactory = await ethers.getContractFactory('Meow');
const meowNft = await meowContractFactory.deploy();
await meowNft.deployed();
console.log(
`Meow NFT deployed to: ${meowNft.address}nCopy this address and paste to the 'mint' task in 'hardhat.config.js'`,
);
});
Когда вызывается задача deploy, hardhat развернет ваш смарт-контракт на блокчейн RSK. Функция принимает два метаданных, а вторая строка const meowContractFactory = await ethers.getContractFactory(‘Meow’); получает contractFactory скомпилированного исходного кода.
ContractFactory в ethers.js — это абстракция, используемая для развертывания новых смарт-контрактов, поэтому Meow здесь — это фабрика для экземпляров нашего контракта Meow.
Строка const meowNft = await meowContractFactory.deploy(); отправляет транзакцию deploy, а следующая строка await meowNft.deployed(); ждет, пока транзакция будет добыта. Последняя строка в задаче deploy использует console.log для печати сообщения, в котором говорится, что NFT был развернут по адресу переменной контракта.
task('mint', 'Mint new NFT collectibles').setAction(async () => {
const deployedAddress = '0xE360F4BFb74A1B2B1d102f40BE6c7D0f5C9d12C8';
const newCIDsToMint = [
'QmaXZxVGYcCY36seYTVuGeY9mWchC1WjMscV1FLNfZsM3f',
'QmR5mspowKw6B68QPSuYE9SGH1A6gPKxjdVRokhAZZh4LD',
];
const api = (await ethers.getContractFactory('Meow')).interface;
const [signer] = await ethers.getSigners();
const meowNft = new ethers.Contract(deployedAddress, api, signer);
async function mintSequentially() {
const cid = newCIDsToMint.shift();
if (cid) {
const tx = await meowNft.mintNFT(signer.address, `ipfs://${cid}`);
const receipt = await tx.wait();
const { tokenId } = receipt.events[0].args;
console.log(`Minted NFT ${deployedAddress} #${tokenId}`);
await mintSequentially();
}
}
await mintSequentially();
});
Задача mint при вызове будет майнить новый NFT. Строка const deployedAddress = ‘0xE360F4BFb74A1B2B1d102f40BE6c7D0f5C9d12C8’; принимает адрес, по которому исходный код смарт-контракта был развернут в задаче deploy. Это означает, что вам нужно сначала запустить задачу deploy, затем скопировать адрес развернутого исходного кода и присвоить его здесь константе deployedAddress.
В приведенных ниже строках содержатся идентификаторы содержимого IPFS (CID), полученные от Pinata.
const newCIDsToMint = [
'QmaXZxVGYcCY36seYTVuGeY9mWchC1WjMscV1FLNfZsM3f',
'QmR5mspowKw6B68QPSuYE9SGH1A6gPKxjdVRokhAZZh4LD',
];
В строках ниже получен интерфейс прикладного программирования смарт-контракта, получена информация об учетной записи разработчика и инстанцирован объект представления смарт-контракта.
const api = (await ethers.getContractFactory('Meow')).interface;
const [signer] = await ethers.getSigners();
const meowNft = new ethers.Contract(deployedAddress, api, signer);
Приведенная ниже функция mintSequentially майнит все элементы из массива newCIDsToMint один за другим. Оператор const cid = newCIDsToMint.shift(); удаляет первый CID из массива newCIDsToMint, если массив уже пуст (майнятся все элементы). Вызывается оператор if, если все еще есть предметы, которые нужно майнить, он вызывает функцию mintNFT смарт-контракта, тем самым инициируя транзакцию. Затем он ждет, пока транзакция будет отчеканена, получает квитанцию о транзакции, извлекает ID нового майнингового NFT из события передачи, эмитированного смарт-контрактом, и рекурсивно вызывает сам себя, пока массив newCIDsToMint не станет пустым.
async function mintSequentially() {
const cid = newCIDsToMint.shift();
if (cid) {
const tx = await meowNft.mintNFT(signer.address, `ipfs://${cid}`);
const receipt = await tx.wait();
const { tokenId } = receipt.events[0].args;
console.log(`Minted NFT ${deployedAddress} #${tokenId}`);
await mintSequentially();
}
}
Секция module.export уже была описана в разделе «Базовые сети JSON-RPC» руководства «Как настроить проект Hardhat для RSK Testnet», на которое вы ссылаетесь в этой статье.
Законченный конфигурационный файл
Теперь ваш окончательный конфигурационный файл должен выглядеть следующим образом:
/* eslint-disable no-undef */
require('@nomiclabs/hardhat-waffle');
const { mnemonic } = require('./.secret.json');
task('deploy', 'Deploys smart contract to a blockchain').setAction(async () => {
const meowContractFactory = await ethers.getContractFactory('Meow');
const meowNft = await meowContractFactory.deploy();
await meowNft.deployed();
console.log(
`Meow NFT deployed to: ${meowNft.address}nCopy this address and paste to the 'mint' task in 'hardhat.config.js'`,
);
});
task('mint', 'Mint new NFT collectibles').setAction(async () => {
const deployedAddress = '0xE360F4BFb74A1B2B1d102f40BE6c7D0f5C9d12C8';
const newCIDsToMint = [
'QmaXZxVGYcCY36seYTVuGeY9mWchC1WjMscV1FLNfZsM3f',
'QmR5mspowKw6B68QPSuYE9SGH1A6gPKxjdVRokhAZZh4LD',
];
const api = (await ethers.getContractFactory('Meow')).interface;
const [signer] = await ethers.getSigners();
const meowNft = new ethers.Contract(deployedAddress, api, signer);
async function mintSequentially() {
const cid = newCIDsToMint.shift();
if (cid) {
const tx = await meowNft.mintNFT(signer.address, `ipfs://${cid}`);
const receipt = await tx.wait();
const { tokenId } = receipt.events[0].args;
console.log(`Minted NFT ${deployedAddress} #${tokenId}`);
await mintSequentially();
}
}
await mintSequentially();
});
module.exports = {
solidity: '0.8.12',
defaultNetwork: 'rsktestnet',
networks: {
hardhat: {},
rsktestnet: {
chainId: 31,
url: 'https://public-node.testnet.rsk.co/',
accounts: {
mnemonic,
path: "m/44'/60'/0'/0",
},
},
},
};
Создание смарт-контракта
В корневом каталоге создайте новую директорию под названием contracts и создайте внутри нее файл Meow.sol.
mkdir contracts
touch contracts/Meow.sol
code contracts/Meow.sol
Ниже приведен код нашего смарт-контракта NFT, который основан на реализации ERC-721 библиотеки OpenZeppelin. Скопируйте и вставьте приведенное ниже содержимое в ваш файл Meow.sol.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// using OpenZeppelin libraries
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract Meow is ERC721URIStorage, Ownable {
/**
From the `Counters` docs:
Provides counters that can only be incremented, decremented or reset.
This can be used e.g. to track the number
of elements in a mapping, issuing ERC721 ids, or counting request ids.
Include with `using Counters for Counters.Counter;`
*/
using Counters for Counters.Counter;
// tracks the number of minted NFTs
Counters.Counter private _tokenIds;
// calling ERC721 constructor
constructor() ERC721("Meow NFT", "MEO") {}
// mints new NFTs. Can be called only by the deployer (s/c owner)
function mintNFT(address recipient, string memory tokenURI)
public onlyOwner
returns (uint256)
{
// increment counter
_tokenIds.increment();
// get new NFT id
uint256 newItemId = _tokenIds.current();
// call internal ERC721 mint function
_mint(recipient, newItemId);
// write token URI to newly minted NFT
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
}
Мы наследуем классы из библиотеки OpenZeppelin contracts, в командной строке выполните npm install @openzeppelin/contracts, чтобы установить библиотеку в нашу папку.
Итак, что именно делает этот код? Давайте разберем его построчно.
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
В верхней части нашего смарт-контракта мы импортируем три класса смарт-контракта OpenZeppelin и одно расширение:
- @openzeppelin/contracts/token/ERC721/ERC721.sol содержит реализацию стандарта ERC-721, который унаследует наш смарт-контракт NFT. Чтобы быть действительным NFT, ваш смарт-контракт должен реализовать все методы стандарта ERC-721. Чтобы узнать больше о наследуемых функциях ERC-721, ознакомьтесь с полной спецификацией ERC-721.
- @openzeppelin/contracts/utils/Counters.sol предоставляет счетчики, которые могут быть увеличены или уменьшены только на единицу. Наш смарт-контракт использует счетчик для отслеживания общего количества майнинга NFT и установки уникального ID для нового NFT. (Каждому НФТ, чеканенному с помощью смарт-контракта, должен быть присвоен уникальный ID — в данном случае наш уникальный ID определяется общим количеством существующих НФТ. Например, первый NFT, который мы майним с помощью нашего смарт-контракта, имеет ID 1, второй NFT — ID 2 и т.д.).
- @openzeppelin/contracts/access/Ownable.sol устанавливает контроль доступа к нашему смарт-контракту, поэтому только владелец смарт-контракта (вы) может майнить NFT. Обратите внимание, что включение контроля доступа — это исключительно ваше предпочтение. Если вы хотите, чтобы любой мог майнить NFT с помощью вашего смарт-контракта, уберите слово Ownable в строке 10 и onlyOwner в строке 17.
- @openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol — Это более гибкий, но более дорогой способ хранения метаданных.
using Counters for Counters.Counter;
// tracks the number of minted NFTs
Counters.Counter private _tokenIds;
// calling ERC721 constructor
constructor() ERC721("Meow NFT", "MEO") {}
После утверждений импорта у нас есть наш пользовательский смарт-контракт NFT, который на удивление короткий — он содержит только счетчик, конструктор и одну функцию! Это происходит благодаря унаследованным нами контрактам OpenZeppelin, которые реализуют большинство методов, необходимых для создания NFT, таких как ownerOf, который возвращает владельца NFT, и transferFrom, который передает право собственности на NFT с одного счета на другой.
В нашем конструкторе ERC-721, как вы заметили, мы передали 2 строки, Meow-NFT и MEO. Первая переменная — это имя смарт-контракта, а вторая — его символ. Вы можете назвать каждую из этих переменных как угодно!
// mints new NFTs. Can be called only by the deployer (s/c owner)
function mintNFT(address recipient, string memory tokenURI)
public onlyOwner
returns (uint256)
{
// increment counter
_tokenIds.increment();
// get new NFT id
uint256 newItemId = _tokenIds.current();
// call internal ERC721 mint function
_mint(recipient, newItemId);
// write token URI to newly minted NFT
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
Наконец, у нас есть функция mintNFT(адрес получателя, строковый токен памяти tokenURI), которая позволяет нам майнить NFT! Вы заметите, что эта функция принимает две переменные:
- адрес получателя указывает адрес, который получит ваш свеженамайненный NFT
- string memory tokenURI — это строка, которая должна разрешиться в JSON-документ, описывающий метаданные NFT. Метаданные НМТ — это то, что оживляет его, позволяя ему иметь настраиваемые свойства, такие как имя, описание, изображение и другие атрибуты.
mintNFT вызывает некоторые методы из унаследованной библиотеки ERC-721 и в конечном итоге возвращает число, которое представляет собой идентификатор свежеотчеканенного НМТ.
Как развернуть свой НМТ на РСК
Шаги
Мы выполним следующие шаги;
- Перейдите на Node.js 12 для работы Hardhat nvm use 12
- скомпилировать смарт-контракт Meow-NFT npx hardhat compile
- развернуть смарт-контракт Meow-NFT в тестовой сети RSK. Смотрите другие возможные сети в hardhat.config.js npx hardhat deploy —network rsktestnet
вы увидите сообщение:
Meow NFT deployed to: 0xE360F4BFb74A1B2B1d102f40BE6c7D0f5C9d12C8 Скопируйте этот адрес и вставьте в задачу ‘mint’ в ‘hardhat.config.js’.
Вставьте адрес в задачу mint!
- Произведите чеканку ваших NFT из CID, указанных в задаче mint в файле project.config.js
npx hardhat mint —network rsktestnet
Просмотр NFT с помощью Metamask
Metamask
Metamask — это своего рода веб-кошелек, который облегчает транзакции с использованием ваших счетов. Он также может быть использован с сетями RSK. У него есть версии для нескольких браузеров, таких как Chrome, Firefox, Opera и Brave.
Перейдите на сайт metamask.io и установите его.
Создайте аккаунт.
Запишите свою начальную фразу из 12 слов. Она используется для восстановления аккаунта, если вы потеряете пароль.
Начальная фраза — это самое важное в кошельке/аккаунте!
Подключите MetaMask к тестовой сети РСК
Перейдите в раздел networks -> Custom RPC, и введите следующие значения:
- Network Name RSK Testnet
- Новый RPC URL https://public-node.testnet.rsk.co
- ChainID (необязательно) 31
- Символ (необязательно) tRBTC
- Block Explorer URL (необязательно) https://explorer.testnet.rsk.co
После настройки выберите RSK Testnet.
Скриншот MetaMask перед добавлением коллекции NFT
Теперь вы должны увидеть аккаунт, подключенный к RSK Testnet.
Не волнуйтесь, если на вкладке NFTs вы увидите «No NFTs yet»,
есть еще один шаг, прежде чем мы сможем их увидеть!
Добавление НФТ в Метамаску
Как только вы окажетесь в сети РСК, выберите вкладку «NFTs» справа и добавьте адрес смарт-контракта NFT и идентификатор токена ERC-721 вашего NFT, который вы сможете найти в RSK Testnet Explorer по хэшу транзакции вашего NFT, развернутого в RSK Testnet.
Вам может потребоваться обновить страницу, чтобы увидеть ваш новый майнинговый NFT.
Снимок экрана MetaMask после добавления коллекции NFT
Поздравляем! В этой статье мы узнали о NFT, IPFS, Hardhat, а также успешно создали и развернули наш проект NFT в RSK Testnet.
Если вы хотите углубиться в эту тему, вот некоторые ресурсы и инструменты, которые мы рекомендуем.
Ресурсы
Посетите наш портал для разработчиков
- Открытое Slack-сообщество РСК
- RSK Youtube
Эта статья была первоначально опубликована на портале разработчиков РСК.