July 27, 2022

Как NFT представлены в Solana: большой конспект без единой строчки кода

Всем привет! С вами ArteMm aka Скамушка

В этой статье мы разберёмся как работают нфт в солане. Это вольный перевод/конспект данной статьи.

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

Навигация по статье:

1. Различия с Ethereum

2. Представление обычных токенов

3. Данные в Mint и Token аккаунтах

4. Теперь поговорим о NFT

5. Где картинка?

6. Опять же, где картинка?

7. Зачем два хранилища метаданных?

8. Печать нескольких выпусков

9. Стандарт токенов и Semi-Fungible токены

10. Заключение

11. Доп. материалы на эту тему

1. Различия с Ethereum

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

В солане же программа (=контракт) взаимодействует с аккаунтами (=счетами, учётными записями), которые хранятся за пределами программы. Как и файл, аккаунты могут хранить произвольные типы данных (например, целые числа, строки, открытые ключи), а также SOL. Аккаунты также имеют метаданные, которые описывают, кому разрешен доступ к их данным и как долго может существовать аккаунт. Любой может читать или пополнять аккаунт, но только владелец аккаунта может списывать средства или изменять его данные.

В общем, аккаунт либо содержит данные (например, сколько у вас токенов), либо представляет собой исполняемую программу (например, смарт-контракт). Первые называют «data accounts», а вторые — «program accounts». В отличие от эфира программные аккаунты не хранят состояние. Всё состояние хранится в дата аккаунтах.

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

2. Представление обычных токенов

Каждый тип токена определяется тем, что мы называем «Mint Account». Этот аккаунт аналогичен печатной машине, поскольку его можно буквально использовать для минта токенов, что эквивалентно печати денег.

Затем отдельные лица могут владеть токенами через «Token Accounts» (=банковский счёт), в которых хранится количество принадлежащих токенов.

Наконец, в блокчейне нет такого понятия, как отдельны лица, поскольку люди взаимодействуют с ними через пары криптографических ключей, называемые кошельками. Открытый ключ каждого кошелька («Wallet Account») указывает на Token Account, который хранит информацию о количество токенов, принадлежащих этому кошельку.

Это приводит нас к следующей аналогии.

Прежде чем мы перейдем к следующему разделу, давайте рассмотрим краткий пример владения токенами в солане. Мы будем использовать токены USDC и AVDO.

Как вы можете видеть, Алиса владеет частью USDC и частью AVDO через два кошелька и три токен аккаунта. С другой стороны, Боб владеет AVDO только через один кошелёк и два токен аккаунта.

Однако здесь появляется проблема. Представим, что Алиса хочет отправить Бобу несколько токенов AVDO. Поскольку у Боба есть два Token Account, какой аккаунт следует выбрать Алисе для внесения своих токенов? Должна ли она попросить Боба прислать ей открытый ключ выбранного им токен аккаунта? Ещё хуже, представьте, что Алиса хочет отправить Бобу токены USDC, а у Боба в настоящее время нет ни одного аккаунта для токенов USDC. Должна ли она создать новый токен аккаунт для Боба, а затем отправить ему его открытый ключ?

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

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

Решение этой проблемы: «Program Derived Addresses» или сокращенно PDA. Это открытые ключи, полученные из других открытых ключей по специальному алгоритму.

Для нас это означает, что, имея «Wallet Account» и «Mint Account», мы можем детерминистически найти соответствующий Token Account. На самом деле эти аккаунты называются «Associated Token Accounts» (сокращенно ATA), и они управляются «Associated Token Account Program».

Таким образом, у нас есть два способа создания и использования токен аккаунтов: один детерминированный (с использованием PDA) и другой — нет (с использованием обычных токен аккаунтов).

Обратите внимание на аннотацию над PDA. Это параметры, необходимые для получения адреса связанного токен аккаунта.

Поскольку мы будем часто использовать эту диаграмму в данной статье, давайте немного сократим её представление. Мы будем использовать следующую диаграмму для представления общей связи между кошельками и минт аккаунтами. Они могли использовать PDAs, а могли и не использовать.

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

Обратите внимание, что теперь у нас только один токен аккаунт на кошелёк для одного минт аккаунта, что означает, что Алиса знает, куда отправить токены AVDO Бобу. Кроме того, Алиса знает, куда отправить Бобу USDC, даже если аккаунт еще не существует.

3. Данные в Mint и Token аккаунтах

Уже скоро мы доберёмся до нфт, но сначала нам нужно понять, какие данные хранятся как в токен аккаунтах, так и в минт аккаунтах.

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

Хорошо, у нас есть несколько вещей, на которые стоит обратить внимание.

  • Во-первых, обратите внимание, как токен аккаунт (ассоциированный или нет) отслеживает как минт аккаунт, так и аккаунт кошелька. Эти связи выделены пунктирными линиями.
  • Следующим важным элементом данных в токен аккаунте является «Amount». В нём хранится количество токенов, имеющихся на аккаунте.
  • Остальные данные также важны, но выходят за рамки этой статьи, поэтому я не буду их рассматривать. Я просто скажу, что когда вы видите атрибут курсивом, это означает, что он необязателен.
  • Кстати говоря, следующий атрибут — «Supply» — сообщает нам общее количество токенов, находящихся в настоящее время в обращении. Этот атрибут нельзя обновить вручную, он автоматически обновляется программой.
  • Далее, атрибут «Decimals» определяет, сколько знаков после запятой мы должны использовать для данного токена. Например, если токен аккаунт имеет Amount = 250, а минт аккаунт имеет Decimals = 2, это означает, что токен аккаунт фактически владеет 2.50 этого токена. Таким образом, все денежные значения могут быть сохранены с использованием целых чисел.
  • Мы также пропустим остальные атрибуты, поскольку они выходят за рамки данной статьи.

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

Что, если мы создадим минт аккаунт с Decimals = 0 и сразу же заминтим один токен на аккаунт кошелька?

Результатом будет минт аккаунт с одним токеном в обращении, который нельзя разбить на более мелкие единицы — например, Алиса и Боб не могут иметь по 0.5 этого токена.

Единственная проблема заключается в том, что ничто не мешает «Mint Authority» продолжать минтить больше токенов в будущем. Если бы они это сделали, у нас внезапно появилось бы более одного токена в обращении и, следовательно, ими могло бы владеть более одного кошелька.

Чтобы предотвратить это, Mint Authority должен отозвать своё право на минт новых токенов сразу после минта первого.

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

Таким образом, в любой момент времени у этого минта может быть только один холдер токена.

4. Теперь поговорим о NFT

Чтобы токен был non-fungible, он должен обладать такими характеристиками, чтобы его нельзя было обменять на что-то аналогичное. Нам удалось достичь этого путем создания минт аккаунта, у которого никогда не будет более одного держателя токена. Тот, кто владеет этим токеном, владеет минт аккаунтом и, следовательно, владеет нфт.

Вкратце: NFT — это минт аккаунт с Decimals = 0, предложение (Supply) которого никогда не превысит единицу.

На мой взгляд, данная модель достаточно элегантна. Её представление не только встроено в её определение, но и, опираясь на токен и минт аккаунты, мы можем взаимодействовать с нфт так же, как и с токенами.

5. Где картинка?

То, что мы объяснили до сих пор, действительно является нфт по определению, но не очень-то полезным. Где название? Где картинка?!

Что ж, похоже, нам нужно прикрепить больше данных к нашему нфт, чтобы сделать его полезным. Вот тут и приходит на помощь Metaplex!

Metaplex — компания, которая создаёт и поддерживает программы Solana. Их самая популярная программа называется «Token Metadata Program». Как вы уже догадались, она добавляет метаданные к нашим токенам!

Для этого используются Program Derived Addresses (PDAs), которые позволяют нам детерминированно найти адрес, используя другие адреса.

В этом случае Token Metadata Program создаст новый «Metadata Account», прикрепленный к этому нфт. Но как вы думаете, какой адрес он использует для получения собственного адреса? Минт аккаунт или токен аккаунт?

Ответ: минт аккаунт! Минт аккаунт является наиболее важным аккаунтом для нфт. Токен аккаунт — это связь между нфт и кошельком. Если мы привяжем PDA к токен аккаунту, а затем продадим наш нфт, новый владелец потеряет все эти данные. Таким образом, минт аккаунт является основной точкой входа в нфт.

Хорошо, давайте посмотрим, какими данными нас наградил Metaplex в «Metadata Account».

Давайте пройдемся по всем этим атрибутам по очереди.

  • Key: Этот атрибут является тем, что мы называем дискриминатором. Поскольку Metaplex имеет много разных типов аккаунтов в рамках Token Metadata Program, это говорит нам, с каким аккаунтом мы имеем дело. Здесь Metadata Account идентифицируется ключом MetadataV1. Обратите внимание, что Token Program использует размер аккаунта вместо дискриминатора для определения этого параметра, что более эффективно, но менее гибко.
  • Update Authority: Это аккаунт, который может обновлять «Metadata Account».
  • Mint: Это указывает на минт аккаунт.
  • Name: Ончейн имя NFT — ограничено 32 байтами.
  • Symbol: Ончейн символ NFT, ограниченный 10 байтами. Часто этот параметр оставляют как пустую строку, но он может быть полезен, если вы хотите, чтобы у вашей коллекции NFT был общий символ. Например, ваш NFT дроп «Banana Blossom» может иметь символ «BNBL».
  • URI: URI нфт ограничен 200 байтами. Это один из важнейших атрибутов. Он содержит URI, указывающий на оффчейн JSON-файл. Этот JSON-файл можно хранить либо на традиционном сервере (например, с помощью AWS), либо с помощью решения для постоянного хранения в другой сети (например, с помощью Arweave). Мы поговорим об этом JSON-файле чуть позже.
  • Seller Fee Basis Points: Роялти, распределяемые между создателями в базисных пунктах, т. е. 550 означает 5.5%.
  • Creators: Массив создателей и их доля роялти. Этот массив ограничен 5 создателями. Для каждого создателя существует атрибут verified, чтобы убедиться, что он подписал NFT для подтверждения его подлинности.
  • Primary Sale Happened: Логическое значение, отслеживающее, был ли NFT продан ранее или нет. Это влияет на роялти.
  • Is Mutable: Логическое значение, указывающее, можно ли изменить ончейн метаданные NFT. После переключения на false, его нельзя вернуть.
  • Edition Nonce: Этот необязательный атрибут немного выходит за рамки, но он используется для проверки номера выпуска NFT, выпущенных ограниченным тиражом.
  • Token Standard: Этот необязательный атрибут определяет взаимозаменяемость токена. Подробнее об этом мы поговорим в этой статье.
  • Collection: Этот необязательный атрибут ссылается на минт адрес другого NFT, который действует как NFT коллекция. Это полезно для торговых площадок, чтобы группировать NFT вместе и безопасно проверять эти коллекции.
  • Uses: Этот необязательный атрибут может сделать NFT пригодными для использования. То есть вы можете загрузить в него определенное количество "использований" и использовать его, пока он не закончится. Вы даже можете сделать так, чтобы NFT уничтожался, когда он полностью израсходован.
  • Collection Details: Этот необязательный атрибут позволяет нам отличать Collection NFT от обычных NFT и добавляет дополнительный контекст, например, количество NFT, связанных с Collection NFT. Этого атрибута нет на иллюстрации.

Как видите, много интересных функций. Сейчас я не собираюсь рассматривать их все здесь. Но вы всегда можете ознакомиться с официальной документацией Metaplex для получения дополнительной информации.

6. Опять же, где картинка?

Помните тот атрибут URI, который указывает на оффчейн объект JSON? Так вот, этот объект JSON следует определенному стандарту, чтобы хранить еще больше данных.

Как видите, среди прочего мы можем предоставить name, description и, наконец, image! Подобно атрибуту URI у Metadata Account, этот атрибут image должен быть URI, который можно использовать для загрузки цифрового актива. Также есть атрибут animation_url и массив files для NFT, которые имеют более настраиваемые потребности. Все эти активы могут храниться оффчейн (на традиционном сервере), либо с помощью постоянного хранилища (в другом блокчейне, например, Arweave). Рекомендую ознакомиться с документацией Metaplex для получения дополнительной информации о стандарте NFT.

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

7. Зачем два хранилища метаданных?

Вам может быть интересно, зачем нам два места для хранения данных вашего NFT? Разве мы не можем просто хранить все в Metadata Account?

Есть несколько проблем с этим.

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

В результате нам необходимо грамотно и безопасно разделить данные на две категории: on-chain и off-chain. Например, массив Creators — ончейн, потому что нам нужен надежный способ узнать, действительно ли NFT был предложен и подписан данным исполнителем. Атрибут Is Mutable — ончейн, потому что нам нужно гарантировать, что после того, как он будет изменен на false, его нельзя будет вернуть обратно.

В итоге, Token Metadata Program может создать гарантии и ожидания для on-chain данных, но не может делать этого для off-chain данных.

Однако это не обязательно означает, что оффчейн JSON-файл небезопасен и ему нельзя доверять. Блокчейны постоянного хранения, такие как Arweave, обычно используются для хранения как цифровых активов, так и метаданных JSON, которые на них ссылаются, обеспечивая неизменность оффчейн данных. Кроме того, NFT можно сделать неизменяемыми, гарантируя, что атрибут URI у Metadata Account никогда не будет указывать на другое место. Это самая безопасная конфигурация NFT, поскольку гарантируется, что ее нельзя будет изменить.

Также обратите внимание, что некоторым проектам NFT может потребоваться, чтобы их данные были изменяемыми таким образом, чтобы это было выгодно владельцам NFT. Например, если вы планируете создать NFT детеныша обезьяны, который постепенно превращается во взрослую обезьяну, вам нужно, чтобы метаданные JSON хранились на сервере, который вы контролируете, чтобы делать эти постепенные изменения. В следующий раз, когда владельцы NFT откроют свои кошельки, они увидят другое изображение, но скорее обрадуются, чем возмутятся. Я хочу сказать, что до тех пор, пока вы доверяете создателям ваших NFT, что гарантируется флагом Verified в ончейн атрибуте Creators, изменяемые оффчейн данные могут быть подлинными. Но, конечно же, не забывайте о DYOR.

8. Печать нескольких выпусков

По больше части мы уже понимаем, как представлены нфт в солане. Но не до конца. Существует еще один важный аккаунт, предлагаемый Token Metadata Program, полученный из минт аккаунта (с помощью PDA).

Фактически, аккаунт, находящийся внутри этого PDA, может быть одного из двух различных типов. Это может быть либо «Master Edition», либо «Edition».

«Master Edition», также известный как «Original Edition», — это NFT, которое может быть продублировано его владельцем определенное количество раз, определяемое атрибутом «Max Supply».

«Edition», также известный как «Print Edition», — это NFT, которое было продублировано с «Master Edition». Всякий раз, когда создается новый «Edition», он отслеживает свой родительский «Master Edition» и его номер издания. Он также увеличивает supply своего родительского «Master Edition». Как только саплай достигает максимального саплая, больше NFT не могут быть напечатаны таким образом. Обратите внимание, что «Max Supply» у «Master Edition» может быть null, что означает, что из него можно распечатать неограниченное количество NFT.

Также обратите внимание, что еще один — менее известный — PDA аккаунт под названием «Edition Marker» существует в «Edition» NFT, для обеспечения отсутствия дублирования между номерами изданий данного «Master Edition».

Одним из вариантов использования этой функции является предоставление художникам возможности продавать более одной копии своих работ. Например, они могут выпустить 100 ограниченных выпусков своего 1/1 NFT, и каждый из них будет отслеживать номер своего издания ончейн.

Стоит отметить, что печать нескольких выпусков NFT совершенно необязательна, и большинство NFT устанавливают для своего «Max Supply» значение 0, чтобы предотвратить его использование.

Хотя печать изданий является основной задачей «Master Editions» и «Editions», они отвечают не только за это.

Если вы помните, ранее мы говорили, что для того, чтобы «Mint Account» был NFT, нужно:

  • Иметь Decimals = 0.
  • Заминтить ровно один токен на аккаунт кошелька.
  • Отозвать право на минт дополнительных токенов через атрибут «Mint Authority».

Что ж, Token Metadata Program использует Edition PDA, чтобы гарантировать эти свойства. При создании PDA Edition аккаунта (будь то «Master Edition» или «Edition») он проверит, что минт аккаунт имеет Decimals = 0 и Supply = 1. Если какое-либо из этих условий не выполняется, аккаунт не будет создан. Если это удается, то он передает «Mint Authority» этому новому Edition PDA, гарантируя, что ни один кошелек никогда не сможет заминтить дополнительные токены. Это означает, что сам факт существования аккаунта «Master Edition» или «Edition» в минт аккаунте является доказательством его невзаимозаменяемости.

Вот почему счета «Master Edition» и «Edition» важны в Solana NFTs и заслуживают упоминания в этой статье.

Вот небольшое обновление нашей диаграммы NFT. Как вы можете видеть, «Mint Authority» больше не null, а указывает на Edition PDA, который может контролироваться только Token Metadata Program с открытым исходным кодом и аудитом.

9. Стандарт токенов и Semi-Fungible токены

Эта статья была бы неполной, если бы я не упомянул, что Token Metadata Program также поддерживает то, что мы называем «Semi-Fungible Tokens» (полувзаимозаменяемые токены) или сокращенно SFT.

SFT в основном такие же, как NFT, но без невзаимозаменяемых гарантий, о которых мы говорили ранее.

«Но почему?», спросите вы, «я думал, что все дело в невзаимозаменяемости?».

Ну, для NFT — да, но, если подумать, основная цель «Metadata Account» — добавление данных к токенам. Почему мы должны ограничивать эту функцию только невзаимозаменяемыми токенами?

Почему бы нашему взаимозаменяемому токену Avocado (AVDO) не добавить ончейн данные к своему минт аккаунту? Он мог бы использовать эти данные, чтобы сообщить децентрализованным биржам, какой символ использовать, какие внешние ссылки отображать, какой логотип показать и так далее.

Другим вариантом использования этого будет создание игрового актива в виде токена с Decimals = 0. Например, вы можете создать токен для ресурса «Wood» в своей игре. Поскольку игроки должны иметь возможность владеть и торговать более чем одним деревом, нет особого смысла создавать один NFT для каждого отдельного куска дерева в вашей игре. Вот почему создание взаимозаменяемых игровых ресурсов при сохранении преимуществ от ончейн данных является очень ценным.

Таким образом, Token Metadata Program позволяет нам создавать Metadata Accounts для минт аккаунтов, которые являются взаимозаменяемыми. Именно поэтому ответственность за гарантию отсутствия взаимозаменяемости лежит на Edition PDA.

Чтобы облегчить нам жизнь, аккаунт метаданных отслеживает, «насколько взаимозаменяем» токен, с помощью атрибута «Token Standard». Это может быть одно из следующих значений.

NonFungible

Если стандарт токена NonFungible, мы знаем, что имеем дело с NFT. Этот стандарт применяется тогда и только тогда, когда для этого минта был создан аккаунт «Master Edition» или «Edition».

Это означает, что у нас есть следующие гарантии:

  • Supply = 1.
  • Decimals = 0.
  • Аккаунт существует под Edition PDA.
  • Mint Authority было передано Edition PDA.

FungibleAsset

Если стандарт токена — FungibleAsset, мы знаем, что имеем дело с недесятичным SFT. Например, наш пример ресурса «Wood» будет обозначен как FungibleAsset.

Это означает, что у нас есть следующие гарантии:

  • Decimals = 0.
  • Под Edition PDA не существует аккаунта.

Fungible

Если стандарт токена — Fungible, мы знаем, что имеем дело с десятичным SFT. Например, токен Avocado или токен USDC подходят под эту категорию.

Это означает, что у нас есть следующие гарантии:

  • Decimals > 0 (строго больше 0).
  • Под Edition PDA не существует аккаунта.

Стоит отметить, что стандарт оффчейн JSON метаданных варьируется в зависимости от «Token Standard», о котором мы только что говорили. Вы можете найти определение JSON стардарта для каждого типа токена ниже.

10. Заключение

Теперь мы не только имеем полное представление о том, как выглядят NFT и SFT в Solana, но и понимаем, почему вещи устроены так, как они есть, и как они сравниваются с другими привычными нам моделями.

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

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

На этом всё! ❤️

11. Доп. материалы на эту тему

Solana’s Token Program, Explained: https://pencilflip.medium.com/solanas-token-program-explained-de0ddce29714

Understanding Program Derived Addresses: https://www.brianfriel.xyz/understanding-program-derived-addresses/

Metaplex Docs (Token Metadata): https://docs.metaplex.com/programs/token-metadata/

Solana Docs (Programming Model): https://docs.solana.com/developing/programming-model/overview

Solana Cookbook (Core Concepts): https://solanacookbook.com/core-concepts/accounts.html

Solana Wiki (Account Model): https://solana.wiki/zh-cn/docs/account-model/#account-storage