ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Сразу оговоримся, что в статье использовано много упрощений и ручной работы, материал не подходит для профессионального использования. Код можно улучшить, а некоторые процессы автоматизировать. Однако нашей целью было подготовить подробное руководство по созданию генеративной коллекции для начинающих на русском языке.

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

Что нам понадобится?

Сначала определимся с блокчейном для запуска сбора и установки необходимого ПО.

Исторически блокчейн Polygon использовался как дешевая альтернатива Ethereum. Сама сеть является сайдчейном сети эфира, т.е. имеет полную совместимость и целую кучу шлюзов, и все основные рынки ее полностью поддерживают. Это идеально подходит для нашей задачи, если у вас есть другие цели, вам придется изменить несколько строк в коде, мы отметим это позже в тексте.

Для развертывания контракта мы будем использовать онлайн-версию среды разработки Remix, поэтому установка программного обеспечения не требуется. Но для чеканки токенов по заранее сформированному списку получателей нам нужно использовать какое-то программное обеспечение — Python оказался удобным, и его мод предполагает, что даже неопытные пользователи знают основы языка.

Мы использовали бесплатную версию среды разработки PyCharm с предустановленным языком 3.11.

В дальнейшем по необъяснимым причинам не удалось правильно установить библиотеку web3 (вероятно, для корректной установки нужны были дополнительные библиотеки), но времени и желания разбираться в причинах ошибок не было, поэтому попытка была повторена для версии 3.9. (что осталось от предыдущих проектов), где все шло как по маслу. Так что имейте в виду, что код должен работать в обеих версиях, но если вы не можете установить библиотеку для интерпретатора 3.11, попробуйте скачать более старую версию.

Мы используем бесплатный хостинг IPFS для хранения данных: ФАЙЛОВАЯ ОСНОВА

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

Генерация метаданных для NFT

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

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

А вот простейший пример кода для генерации кучи нужных файлов с метаданными:

<?php
$nums=555; $i=0;
while ($i <= $nums) { file_put_contents(str_pad($i, 3, "0", STR_PAD_LEFT).'.json', '{
  "name": "Unit #'.str_pad($i++, 3, "0", STR_PAD_LEFT).'",
  "description": "The award for loyal BestChange fans who have actively interacted with the service.",
  "image": "ipfs://QmYBrWr1MCMCxNB78RF96EzJHypZ658nUGtAQYq8VnWfqj"
}');}
?>

В нашем примере файлы создаются 000.json, 001.json и так далее, пока 555.json. В поле name имя токена, содержащее его серийный номер, description содержит описание, которое размещается непосредственно под изображением на биржах, а поле image содержит ссылку на изображение. В нашем случае это ссылка на децентрализованное хранилище, поэтому адрес начинается с ipfs://хотя ссылки на централизованные сервера тоже подойдут.

ЧИТАТЬ   Французский боксер Соро подал протест на результат боя с Курбановым

Содержимое файлов будет выглядеть так:

{
  "name": "Unit #002",
  "description": "The award for loyal BestChange fans who have actively interacted with the service.",
  "image": "ipfs://QmYBrWr1MCMCxNB78RF96EzJHypZ658nUGtAQYq8VnWfqj"
}

Нам не нужно было комплектовать токены разными атрибутами, но если у вас стоит такая задача, советуем ознакомиться с описанием стандарта метаданных, который использует OpenSea: https://docs.opensea.io/docs/metadata-standards

Пример более сложных метаданных:

{
  "name": "Example #1",
  "description": "Name: BestChange Creator",
  "image": "ipfs://Qmc3qZmHiYw6qiViDPhSX1wxjaeGwVuLg6TUde3zxdAbLS",
  "attributes": [
    {
      "trait_type": "Position",
      "value": "Senior analyst"
    },
    {
      "trait_type": "Level",
      "value": 5,
      "max_value": 10
    }
  ]
}

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

После того, как все файлы json сгенерированы, мы также загружаем их в IPFS и собираем список хэшей для будущего сбора.

Смарт-контракт для сбора NFT

Перейдем к самому «страшному» и в то же время самому простому этапу — созданию и публикации смарт-контракта.

На самом деле добрые разработчики из OpenZeppelin позаботились о нас и создали простейший генератор смарт-контрактов: https://docs.openzeppelin.com/contracts/4.x/wizard

6a395f7d63adecadddc4557c5c5745ed

Здесь все просто. Для нашей задачи нам нужно открыть вкладку ERC721наполнять Имя И Символ (позже видно только в браузерах) и поставьте галочки:
Обналичиваемый – держателю контракта чеканить токены;
Идентификатор автоматического увеличения — добавляет автоматический счетчик жетонов;
Исчисляемый – добавляет необходимые функции для браузеров;
хранилище URI – добавляет возможность устанавливать URL с метаданными для каждого отдельного токена.

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

Еще заполнить Сведения о безопасности (будет добавлено в код контракта в качестве комментария), а тип лицензии оставьте С.

После этого нажмите кнопку Открыть в ремиксеонлайн-версия IDE уже откроется с нашим кодом контракта.

b66d93729c7e96ad5b3cb64713a4f048

Затем перейдите на третью вкладку сверху и нажмите на кнопку Составить договор-…

82364caea5e01e0791407abea19fc2f1

Результат компиляции (появится контракт и в третьем разделе появится зеленая галочка):

3628e6b00d7c415d0bb6d28348350553

Далее вам необходимо авторизоваться в MetaMask:

f74fa4a7e30f53b553d448b643c3872e

Теперь на четвертой вкладке сверху можно подключиться к сети, определенной в MetaMask (Внедренный провайдер – MetaMask). Обязательно проверьте, что Polygon Mainnet включен в MetaMask.

8584b70222ae21a95ec2b810d09b3b59

Если все было установлено правильно, то под строкой с сетью будет указан идентификатор цепочки 137 (для основной сети Polygon).

eb86db5f555eeccfe1d324a6d1d8a309

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

e402794b31c2f438bf1669efd8182a46

! Есть необъяснимая ошибка. Ваша транзакция может уйти в небытие (Вероятно, MetaMask время от времени отправляет транзакции на резервную ноду, либо Remix передает неверную цену на газ, но данные поступят в сеть через несколько часов).

Если повезет, транзакция сразу получит подтверждение, если не повезет, подождите, не верьте MetaMask, что транзакция отменена, она не бесследно исчезла, а подтвердится через несколько часов (если за это время вы сгенерируете еще несколько попыток, то они тоже будут “отменены” в МетаМаске, затем будут подтверждены одним большим пакетом в тот момент, когда вы этого уже не ждете).

Не удалось понять происхождение этого бага, поэтому мы не можем вам ничего посоветовать, чтобы его избежать.

Теперь, когда наш контракт размещен в блокчейне, нам нужно отследить тег и проверить его. Для этого идем в https://polygonscan.com, здесь нужно создать учетную запись, а затем указать адрес только что созданного контракта в браузере. Адрес контракта вы можете найти в списке транзакций MetaMask, по ссылке “Показать в обозревателе блоков

ЧИТАТЬ   Такер Карлсон выдвинут кандидатом в президенты США
4a3e9192f7174ca9f85d932fde6aa203

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

289a299b3e730db435bc1e168a2b8430

Без проверки браузер видит только байт-код. Давайте исправим это, нажав на “Проверить и опубликовать“.

40d0353c3e23dc2dad16f03fd262f83e

Далее заполните все поля в соответствии с настройками Remix и нажмите “Продолжать“:

47ff86b1b7e3cee04269fd1020727b3d

Теперь нам нужно вернуться к Remix и на нашем контракте в контекстном меню выбрать “сгладить“. Он сгенерирует нам единый документ со всеми используемыми библиотеками.

71349291a9b9a66b8aee0220c9c56bf4

Обязательно добавьте первую строку: // SPDX-License-Identifier: MIT

d40bf996b61f2259ad2a0cbd08e14c12

Вставьте полученный текст в окно проверки. Пройдите рекапчу и нажмите “Проверить и опубликовать

e16c55db841bb4b3c1c5cfc53bb1a5b7

Если все прошло хорошо, мы увидим что-то вроде этого:

01ead93b1449b906f2e206fb6c53b8df

Кстати, созданный здесь ABI пригодится нам в будущем, поэтому советуем скопировать его и сохранить в отдельный документ.

2336e1fe60a57a048dab0db72291d195

После выполнения всех процедур контракт получил свое имя и галочку для подтверждения кода.

Забастовка коллекции NFT

Теперь самое интересное — создание коллекции с помощью Python-скрипта.

Для работы скрипта нам потребуется следующее:

  • Адрес кошелька

  • Закрытый ключ

  • Адрес контракта

  • Контракт ABI

1cb2e2412647677b3a293accdc7eb91b

Ищем первые две точки в MetaMask.

Если скопировать адрес не сложно, то для получения приватного ключа заходим в “Детали учетной записи” в настройках кошелька и нажмите на кнопку “Экспорт закрытого ключа“.

После этого вам нужно будет ввести пароль от кошелька и вы получите приватный ключ (хранить его очень бережнос ним у любого будет полный доступ к вашему кошельку).

e382b033e9e9c2bbea448de263dc02aa

Адрес контракта можно взять в браузере и АБИ мы предварительно скопировали в отдельный файл, когда проверяли договор.

Далее берем этот готовый скрипт и вставляем в него необходимые данные:

import csv
import requests
from web3 import Web3

# Определение URL ноды
node_url = "

# Связь с нодой
web3 = Web3(Web3.HTTPProvider(node_url))

# Проверка соединения с нодой
if web3.isConnected():
    print("-" * 50)
    print("Connection Successful")
    print("-" * 50)
else:
    print("Connection Failed")

# Определение адреса отправителя (должен быть владелец контракта) и приватного ключа
caller = "0x24......"
private_key = "2f6......."

# Определение ABI и адреса контракта
abi = '[ { "inputs": [], .........'
contract_address = "0xc73........"

# Создание объекта с данными контракта
contract = web3.eth.contract(address=contract_address, abi=abi)

# Определение ID цепочки
Chain_id = web3.eth.chain_id

# Определение номера будущей транзакции для этого кошелька
nonce = web3.eth.getTransactionCount(caller)

# Читаем построчно данные из документа list.csv
with open('list.csv') as csvfile:
    # Разделитель полей в скрипте запятая, иногда excel может устанавливать разделителем точку с запятой, проверить можно открыв csv-файл в блокноте
    readCSV = csv.reader(csvfile, delimiter=",")
    for row in readCSV:
        # Получаем текущие цены за газ для сети Polygon
        gaspricearr = requests.get('
        gPrice = int(float(gaspricearr['fast']['maxFee'])*1000000000)
        # Проверяем формат кошелька, если он без контрольной суммы, меняем на правильный
        if web3.is_checksum_address(row[0]):
            toAddress = row[0]
        else:
            toAddress = web3.to_checksum_address(row[0])
        # Определяем параметры транзакции
        call_function = contract.functions.safeMint(toAddress, row[1]).buildTransaction({"chainId": Chain_id, "from": caller, "gas": 1000000, "gasPrice": gPrice, "nonce": nonce})
        # Увеличиваем номер будущей транзакции на единицу
        nonce += 1
        # Подписываем транзакцию приватным ключём
        signed_tx = web3.eth.account.sign_transaction(call_function, private_key=private_key)
        # Отправляем транзакцию в блокчейн
        send_tx = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
        # Дожидаемся обработки транзакции
        tx_receipt = web3.eth.wait_for_transaction_receipt(send_tx)
        # Печатаем в терминал данные опубликованной транзакции
        print(tx_receipt)

В дополнение к скрипту нам нужен список получателей с их URI токенов в формате CSV. Содержимое файла должно выглядеть так:

0x4C3A0d41cB765c47D3933F1a05160B7BA085DfCa,ipfs://QmQPe3Kg7FQJdAbANw6gWy8c9qT6r7LKWKFKbE5E1zSAjA
0x2e8B06982c01dc8604060F3604b544AB33bfe69D,ipfs://QmajZpQWNo1pjKCkWp1UyM43oFiv7tX3deJw23LvuHW9bJ
0x636CDce269C60E20bFBa65D3C88F6EF73F8A1a28,ipfs://QmaNF3dWa19k2YJRCErYRjn9fB9EGmPLWm6bwX76VpUHib
0x32FeB01eE4387a18cf4051F2ef7C943Bee51E2c5,ipfs://QmPU2FFPojFei38LDFqQQaQXUPL27r9PKneyozkXYUTMk6
0x275D40dFD150270C7212fc626798dde0176EFaBE,ipfs://QmUfFA9vuhjTDQW29EpA5U6R6HjRRcBMNLaLDm8yXwnGVD
0xbb1338d34740Dd6c0342e46c4c51cDf38C1CceD8,ipfs://QmahVcksCjoaxNbYuk2wqyNY2CbnYxmj4Zovq5iVH9xTei

Обратите внимание на разделитель полей, его нужно будет правильно указать в скрипте.

ЧИТАТЬ   ‘Мы стояли на месте около двух часов’: рыбаков спасли от тающего льда на озере в Челябинской области

Финал

Все готово, запускаем скрипт и ждем пока токены полетят к своим получателям.

! Иногда раз в 100-300 транзакций случаются неуловимые баги и скрипт прерывается ошибкой (каждый раз новая, закономерность определить не удалось). Для продолжения нужно подождать минуту, зайти в браузер и найти ID последнего отправленного токена в истории транзакций вашего кошелька, удалить все ранее обработанные строки в CSV, сохранить и перезапустить скрипт.

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

Основной:

Если вы используете IPFS для хранения метаданных, одним из популярных сайтов является Rarible (используется ВКонтакте для импорта данных) имеет свойство иногда не загружать метаданные из этой файловой системы, если шлюз не отрендерил их своевременно.

Для проверки точности рекомендуем использовать собственный API:

<?php
$body = file_get_contents(' //Получаем в $body json строку с нужным количеством записей
$arr = json_decode($body, true); //Разбираем json запрос на массив в переменную $arr
foreach ($arr['items'] as $nums){
echo $nums['meta']['name'].'<br>'; //Построчно выводим имена токенов, если какого-то не хватает, значит Rarible не скачал данные
}
?>

Если нет нескольких строк, напишите в их поддержку через форма для обратной связи. Они исправят это в течение нескольких дней.

Source

От admin