Первый NFT marketplace на Cardano
Популярность NFT растёт, а блокчейн Cardano входит в первую десятку криптовалют по рыночной капитализации. Так как за невзаимозаменяемые токены обычно платят криптовалютой, Cardano и NFT, кажется, созданы друг для друга как котики и коробки. Рассказываем, как появилась идея создать торговую NFT-площадку на Cardano и через какие тернии мы прошли, чтобы её реализовать.
Для участия в коллаборации с Cardano нам потребовалось изучить фреймворк Plutus Platform. Порог входа в Plutus достаточно высок, поскольку требует от разработчиков знания функционального языка Haskell (Plutus Core — язык смарт-контрактов Cardano — использует кодовую базу Haskell), а также опыта работы с блокчейном. Наши инженеры программировали в функциональном стиле с 2018 года и уже мастерски знали Haskell, — именно поэтому мы выбрали Cardano, и поэтому интеграция прошла успешно. С тех пор, уже больше года, мы разрабатываем проекты на блокчейне.
Обзор проекта
Проверяя, как смарт-контракты Plutus ведут себя в реальных приложениях, мы тесно сотрудничали с внутренней командой IOG. Наши разработчики опробовали протокол IPFS, помогали находить ошибки и участвовали в брейнштормах на тему внесения улучшений.
Главной задачей было спроектировать и разработать идею приложения на новой платформе. Можно было выбрать идею из списка предлагаемых организаторами, что мы и сделали. С августа по декабрь 2021 наша команда в составе пяти человек трудилась над её реализацией, и результатом стало создание первой торговой площадки NFT с аукционом на блокчейне Cardano.
Мы разработали приложение смарт-контракта — серверную часть приложения, которое взаимодействует с блокчейном. Это означает, что мы написали код, который конструирует транзакции, и код, который валидирует транзакции. Мы также написали фронтенд для ручного тестирования, и красивый интерфейс для пользователей приложения. Прежде чем приступить к разработке приложения, мы спроектировали конкретную концепцию его архитектуры и спецификацию имплементации.
Чтобы создать NFT на нашей платформе, нужно выполнить следующие шаги:
- загрузить связанные метаданные (это может быть любой файл, например изображение) в хранилище. Этот шаг требует адресуемости контента, — её обеспечивает протокол IPFS, который присваивает каждому файлу уникальный идентификатор (он представляет собой криптографический хеш);
- непосредственно отчеканить токен, который поступит в кошелёк создателя на блокчейне.
Основная функция, которую обеспечивает смарт-контракт нашей торговой NFT-площадки — прямая связь между токеном в кошельке пользователя и идентификатором контента. Пользователям нашего маркетплейса доступны опции:
- Загрузка изображений, а также видео и аудио файлов и создание своих невзаимозаменяемых токенов;
- Объединение NFT в коллекции;
- Запуск аукциона;
- Настройка цены и периода проведения аукциона;
- Продажа токенов по фиксированной цене.
Монетизируется платформа за счёт комиссий от продажи NFT и аукционов.
Проблемы и решения
На момент нашего участия тестовая сеть IOG не поддерживала смарт-контракты, и не располагала документацией, которая позволила бы разобраться в некоторых вещах. Все разработки мы тестировали на симуляции. После релиза хардфорка Alonzo, — обновления, которое принесло возможность создания смарт-контрактов и dApps, — оказалось, что оно не поддерживает многие фичи. Рассказываем, с какими именно проблемами мы столкнулись и как это отразилось на запуске проекта:
1. Хранение метаданных (изображений, видео или аудиофайлов, связанных с NFT).
Известно, что хранение файла в сети сильно увеличивает стоимость транзакции. Кроме того, на одну единицу отводится максимум 16 КБ хранилища (из-за ограничения размера транзакции). Это значит, что для хранения больших файлов вам нужно разрезать их на куски, как Ивана Царевича, а потом принести живой воды придумать метод объединения кусков в исходный файл.
Решение было заимствовано из существующей практики в блокчейне Ethereum. Мы решили хранить файлы в распределенном файловом хранилище, известном как IPFS. Файл загружается в IPFS и получает свой идентификатор контента, который представляет собой хеш содержимого файла. Система работает, потому что файлы по-прежнему однозначно идентифицируются хешем (иначе говоря — присваивают адрес содержимому).
Это решение убивает двух зайцев разом:
- позволяет однозначно идентифицировать NFT с чем-то (и таким образом сделать токен невзаимозаменяемым);
- даёт возможность хранить в цепочке только короткий хеш вместо большого файла.
2. Хранение идентификатора контента, созданного после загрузки файла в IPFS.
В Ethereum каждый токен — это смарт-контракт, который позволяет использовать storage. В Cardano все токены — нативные, поддерживаются реестром и могут вести себя аналогично основной валюте, ADA. Токен в Cаrdano представлен только PolicyID и неизменяемым именем актива, которые позволяют однозначно идентифицировать токен, передавать и отслеживать его.
Мы располагали двумя вариантами решения проблемы:
- Использовать для хранения имя актива — единственное место в токене, где можно что-то хранить, причём неизменное;
- Хранить все хеши внутри данных некоторых скриптов (например, скрипта торговой площадки), с возможностью внесения изменений. Также там может храниться много другой связанной информации.
В конце концов мы решили хранить идентификатор контента в имени токена и хранить другую информацию, — такую как описание токена, — внутри данных скриптов, чтобы сделать токен как можно более лёгким.
3. Общая готовность фреймворка Plutus.
В то время библиотека была абсолютно новой и экспериментальной, и сеть Cardano не поддерживала смарт-контакты. Специально созданный язык разработки смарт-контрактов и платформа их исполнения Plutus разрабатывались одновременно с нашим приложением для торговой площадки, поэтому постоянно что-то не работало.
Впрочем, к этому мы были готовы, и старались не отставать от обновлений Plutus и предоставлять обратную связь инженерам IOG. В специальном сообществе в Discord мы постоянно общались с разработчиками Plutus и другими участниками программы тестирования контрактов, обсуждая способы исправления возникших ошибок. Основная внутренняя команда также IOG постоянно нас поддерживала.
4. Существующее ограничение на размер транзакции.
Максимальный размер транзакции в Cardano — 16 КB. Лимиты также установлены на количество шагов вычисления (CPU) и оперативной памяти (RAM), потребляемых скриптом.
Наши сценарии оказались слишком большими, чтобы их можно было выполнять в сети. Позже стало ясно, что это связано с использованием абстракции конечного автомата из фреймворка Plutus. Абстракция обходится очень дорого, потому что добавляет много кода и увеличивает размер скрипта.
В итоге нам пришлось переписать всю реализацию, чтобы исправить проблему ограничения размера, исключив использование конечного автомата.
5. Отсутствие поддержки удалённых (браузерных) кошельков в PAB.
Для того, чтобы пользователь мог купить NFT, он должен зайти в свой браузерный кошелёк через браузерный интерфейс, ввести пароль и сабмитить транзакции (тем, кто знаком с MetaMask, известна эта схема).
Но оказалось что Plutus App Framework не поддерживает интеграцию PAB с удалённым (браузерным) кошельком. Это была самая большая проблема, которая, к сожалению, стала известна лишь в процессе работы. Реальное решение тогда было невозможно найти.
Правда, сдались мы не сразу и подготовили альтернативный сценарий запуска приложения через Cardano Wallet Backend. Сценарий развёртывания, подготовленный нами к тестированию, заключался в локальном развертывании PAB вместе с Cardano-кошельком, chain-index и приложениями Cardano-node. Таким образом, у пользователя dApp все приложения работают на его компьютере, и он использует локальный кошелёк с полным узлом. Со своей стороны мы, как провайдер, обязались хранить все его данные и совершать действия от его имени.
Этот сценарий нарушал политику конфиденциальности и казался непривлекательным для юзера, которому пришлось бы предоставить нам мастер-ключ от своего кошелька. В итоге, мы так и не смогли реализовать сценарий и запустить проект в тестнет.
На момент написания статьи (сентябрь 2022) PAB в режиме браузерного кошелька всё ещё находится в разработке. Работа с браузерными кошельками необходима для любого DeFi приложения. Необходимо дополнительно исследовать временные решения, с помощью которых можно запустить приложение для широкого круга пользователей.
Цифры
Разработка приложения заняла 5 месяцев. Для этого потребовались усилия команды из 5 человек:
- один Frontend разработчик;
- три Plutus & frontend разработчика;
- один Project manager.
Для разработки приложения мы задействовали следующий стек технологий: Haskell, PureScript, NixOS, Docker, TypeScript.