TL;DR. Если вы предпочитаете, чтобы разговоры были дешевыми, покажите мне код, вы можете найти исходный код здесь.

Фон

Если вы хотите узнать, как создать бота для продаж NFT на Solana прямо сейчас, ваши варианты не очень хороши. Есть несколько репозиториев ботов с открытым исходным кодом, и они хорошо написаны, но я думаю, что они сложнее, чем необходимо.

Кроме того, по какой-то странной причине новые разработчики в Солане автоматически предполагают, что вы должны быть мастером Rust, чтобы создавать что-либо. Это неправда. Вам не нужно знать Rust, чтобы строить на Solana (если только вам не нужно писать контракты).

И что еще хуже, если вы не разработчик, у вас есть только один выбор:

а) Заплатите случайному разработчику (и получите переплату)

б) Купите существующее решение для ботов продаж (и получите переплату)

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

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

Общий обзор (необязательно)

Что мы создаем: бот продаж, который отслеживает продажи данного NFT на всех основных торговых площадках Solana и публикует информацию о продажах на канале Discord.

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

Способ, которым мы собираемся добиться этого, будет следующим:

  1. Выясните учетную запись / адрес коллекции NFT для получения роялти
  2. Постоянно опрашивать этот адрес для новых подписей транзакций
  3. Просматривайте подписи транзакций, извлекайте детали их транзакций и проверяйте действительные продажи NFT.
  4. Если они действительны, получите метаданные NFT и опубликуйте подробности в Discord.
  5. Перейдите к шагу 2 — убедитесь, что опрашиваются только те транзакции, которые происходят после последней наблюдаемой транзакции.

Опрос против потоковой передачи (необязательно)

Всякий раз, когда вы имеете дело с «живыми» данными, у вас в основном есть два варианта: опрос или потоковая передача/PubSub.

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

В этом уроке мы собираемся опросить данные. Это связано с тем, что 1) его легче кодировать и объяснять концептуально (IMO), и 2) это значительно упрощает заполнение исторических данных о продажах.

Настраивать

Во-первых, убедитесь, что у вас установлен Node JS (версия 14.17.0 или выше), я рекомендую использовать NVM. Затем откройте терминал, создайте в нем новую папку cd и инициализируйте npm.

$ mkdir nft-sales-bot
$ cd nft-sales-bot
$ npm init

После того, как репо инициализировано, нам действительно нужны только 3 вещи:

$ npm i @solana/web3.js @metaplex/js axios

Solana/web3.js — это библиотека для взаимодействия с узлами Solana в цепочке (извлечение транзакций, информации об учетной записи, подписей и т. д.).

Metaplex представляет собой набор инструментов/контрактов/стандартов для взаимодействия с NFT Solana.

А axios — это библиотека для создания HTTP-запросов.

Код

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

Во-первых, импортируйте библиотеки, которые мы только что установили.

Далее давайте инициализируем некоторые переменные и проведем некоторые проверки.

Здесь происходит несколько вещей. Во-первых, мы проверяем, что адрес проекта и URL-адрес Discord передаются боту (подробнее об этом позже). Во-вторых, мы подключаемся к основной сети для Metaplex и Solana. Кроме того, вы можете подключиться к devnet для тестирования. В-третьих, мы удаляем программу метаданных из Metaplex, это поможет нам получить метаданные NFT. В-четвертых, мы создаем новый объект PublicKey из переменной среды PROJECT_ADDRESS — это необходимо для передачи в библиотеку solana/web3. Наконец, мы устанавливаем интервал опроса, как часто мы хотим, чтобы наш бот проверял наличие новых продаж. Я рекомендую установить это значение как минимум между 2000–5000 мс. Это связано с тем, что узлы Solana RPC по умолчанию имеют ограничения скорости, и ваши запросы не будут проходить, если вы делаете слишком много вызовов за короткий период времени. Вы можете использовать провайдера RPC, такого как GenesysGo, для совершения неограниченных звонков, хотя это не будет бесплатно.

Теперь давайте добавим основные торговые площадки Solana NFT и адреса их программ. Всякий раз, когда на торговой площадке происходит продажа NFT, очевидно, должен быть задействован программный адрес торговой площадки, и вы можете наблюдать это в сети (вот пример для Magic Eden).

Давайте теперь запустим основную функцию для запуска бота продаж.

Вы можете пока игнорировать неназначенные переменные — здесь главное отметить функцию getSignaturesForAddress. Это возвращает подтвержденные подписи для транзакций, связанных с данным адресом, назад во времени от самого последнего подтвержденного блока (или любой другой подписи, которую вы передаете в параметрах). По сути, если на основной адрес проекта поступают какие-либо новые транзакции, эта функция их получит. Если транзакций нет, мы ждем длительность интервала опроса и снова непрерывно проверяем в бесконечном цикле. Вы можете найти реализацию timer fn и любых других вспомогательных fn в исходниках.

Закончим основную функцию.

Помните, что getSignaturesForAddress возвращает транзакции в порядке убывания времени. Это означает, что нам нужно начать цикл с последнего элемента массива signatures, чтобы отобразить продажи в хронологическом порядке.Для каждой подписи мы можем вызвать метод getTransaction в библиотеке web3, чтобы получить точные сведения о транзакции. Имея под рукой детали, мы сначала проверяем, есть ли в транзакции какие-либо ошибки, и в этом случае мы знаем, что успешной продажи не было бы.

Затем мы преобразуем blockTime, который соответствует времени Unix, в более читаемый объект даты. Затем мы делаем простой расчет, чтобы получить цену продажи, а также посмотреть, на какую торговую площадку сопоставляется последняя учетная запись (по моему опыту, последняя учетная запись всегда является идентификатором торговой площадки — я не уверен, что это универсально верно, поскольку я я глупый, если вы хотите быть в полной безопасности, вы можете просмотреть все учетные записи).

Затем мы получаем метаданные NFT, которыми обменивались, а вместе с ними у нас есть вся информация, необходимая для публикации сведений о продаже в Discord.

Перед повторным опросом мы также хотим убедиться, что получаем только те транзакции, которые произошли с момента последнего опроса. Для этого метод getSignaturesForAddress принимает параметр until, который мы можем установить как самую последнюю транзакцию, о которой мы знаем, lastKnownSignature.

(Примечание:getSignaturesForAddress по умолчанию возвращает последние 1000 подписей. Это означает, что торговый бот фактически начнет с воспроизведения старых продаж. Мне нравится делать это, чтобы заполнить исторические данные в Discord, что нравится сообществу. Если вы хотите показывать только новые продажи, вам нужно изменить это. Например, вы можете установить bootupDate при первом запуске вашего бота, а затем проверить, что даты всех транзакций должны быть больше, чем это перед публикацией)

Получение метаданных

Пришло время определить функцию getMetadata, на которую мы ссылались ранее.

Сначала мы получаем программный производный адрес (PDA) для адреса нашего токена, а затем подключаем его к встроенному в Metaplex Metadata.load, чтобы получить ссылку на метаданные. Затем мы используем эту ссылку, чтобы получить фактические метаданные.

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

К счастью, мы можем немного оптимизировать это, воспользовавшись помощью наших надежных друзей, Magic Eden — крупнейшей и лучшей, по мнению IMO, торговой площадки NFT в Солане.

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

Публикация в дискорде

Чтобы опубликовать сообщение в Discord, нам сначала нужно получить URL-адрес веб-перехватчика. Для этого: щелкните правой кнопкой мыши на своем сервере -> настройки сервера -> интеграции -> вебхуки -> новый вебхук. Здесь вы можете назвать веб-хук и указать, на какой канал вы хотите отправлять продажи. После настройки — просто нажмите «Копировать URL вебхука».

Далее напишем функцию отправки продаж.

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

Запуск бота

Теперь код закончен. Для того, чтобы запустить его, нам нужно еще несколько вещей.

Во-первых, нам нужно выяснить, каким должно быть process.env.PROJECT_ADDRESS. Для этого я обычно просто открываю NFT в Solana Explorer и определяю, какие авторы получают большую часть гонорара.

Во-вторых, имея это и URL-адрес Discord на руках, просто добавьте строку для запуска бота runSalesBot(); и, наконец, запустите:

$ PROJECT_ADDRESS=8u...s DISCORD_URL=paste-url-here node sales_bot.js

Подсказка: для размещения бота мне нравится использовать Replit в постоянном режиме, но вы можете использовать Heroku или даже свою собственную машину.

Заключение/следующие шаги

Вы можете найти готовый код здесь.

Я хочу повторить, что я не утверждаю, что это лучший способ создать бота (или даже хороший способ). Я уверен, что есть бесчисленное множество других способов сделать это намного лучше. Моя главная цель в этом руководстве состояла в том, чтобы написать что-то, что вы могли бы легко прочитать/понять и осмыслить концептуально. Всего около 100 строк. На практике в идеале вы бы использовали модель PubSub и лучшую структуру проекта с хорошо протестированными вспомогательными функциями.

Если вам понравился этот урок или у вас есть какие-либо вопросы/советы/исправления/предложения, дайте мне подписку на Twitter (@turkmmtz).