NFT-коллекции на TON
NFT на TON — это не просто картинки, а целая архитектура контрактов для управления уникальными цифровыми активами. Как и Jetton, NFT на TON используют двухуровневую структуру (Collection + Item), что обеспечивает масштабируемость, но добавляет сложность по сравнению с ERC-721. Понимание NFT-стандарта необходимо для разработки маркетплейсов, игровых предметов и любых уникальных токенов.
В предыдущих уроках мы разобрали шардированную архитектуру Jetton 2.0. NFT в TON следуют тому же принципу — каждый токен существует как отдельный контракт. Стандарт TEP-62 определяет модель коллекция + элемент, где коллекция с 10,000 NFT = 10,001 отдельный контракт.
TEP-62: стандарт NFT
Collection + Item модель
В отличие от Ethereum ERC-721, где один контракт хранит все tokenId в маппинге, TON использует два типа контрактов:
NFT Collection (один контракт):
- Metadata коллекции (имя, описание, обложка)
next_item_index— счётчик следующего элементаowner— владелец коллекции (может минтить новые элементы)deploy_nft_item()— создание нового NFT Item
NFT Item (отдельный контракт для каждого NFT):
index— порядковый номер в коллекцииcollection_address— адрес коллекции-родителяowner— текущий владелец (transferable — можно передать)content— метаданные элемента (TEP-64)
ERC-721 vs TEP-62
В Ethereum ERC-721 — это один контракт с маппингом tokenId => owner. Все 10,000 NFT живут в одном контракте. В TON каждый NFT — это отдельный контракт, развёрнутый в шардчейне владельца. Коллекция — это фабрика/индекс, а не хранилище.
Collection — фабрика, а не хранилище
Ключевой концептуальный сдвиг: NFT Collection в TON не хранит элементы. Она их создаёт (деплоит) и предоставляет индексирование.
Что делает Collection:
- Деплоит новые NFT Item при вызове
deploy_nft_item() - Вычисляет адрес любого Item по индексу:
get_nft_address_by_index(index) - Хранит метаданные коллекции (общие для всех элементов)
- Определяет royalty (процент отчислений создателю при перепродаже)
Что Collection НЕ делает:
- Не хранит список владельцев
- Не управляет трансферами после деплоя
- Не знает, кому сейчас принадлежит конкретный Item
Не думайте о Collection как о массиве NFT. После деплоя каждый NFT Item — полностью независимый контракт. Collection не может заблокировать, отозвать или изменить NFT (если это не предусмотрено в коде Item).
NFT Item: жизненный цикл
Деплой
Collection создаёт Item, передавая:
index— уникальный номерowner— первый владелецcontent— метаданные элемента
Адрес Item детерминирован: hash(code + init(index, collection_address)). Это позволяет вычислить адрес любого Item, зная только его индекс и адрес коллекции.
Передача (Transfer)
Передача NFT — это изменение owner в контракте Item:
User A NFT Item #42 User B
| | |
|-- transfer(User B) --->| |
| | owner = User B |
| |-- ownership_assigned ->|
|<-- excesses -----------| |
- Текущий владелец (User A) отправляет
transferв NFT Item - Item проверяет, что отправитель — текущий owner
- Item обновляет
ownerна User B - Item отправляет
ownership_assignedновому владельцу - Excesses возвращаются отправителю
Получение данных
Get-методы NFT Item:
| Метод | Возвращает |
|---|---|
get_nft_data() | init, index, collection, owner, content |
get_nft_content() | Полные метаданные (collection + item) |
Метаданные: TEP-64 для NFT
NFT используют двухуровневые метаданные:
Collection-level metadata
{
"name": "Cool Cats TON",
"description": "10,000 unique cats on TON",
"image": "https://example.com/collection-cover.png",
"social_links": ["https://t.me/coolcats"]
}
Item-level metadata
{
"name": "Cool Cat #42",
"description": "A rare blue cat with laser eyes",
"image": "https://example.com/cats/42.png",
"attributes": [
{ "trait_type": "Background", "value": "Blue" },
{ "trait_type": "Eyes", "value": "Laser" },
{ "trait_type": "Rarity", "value": "Legendary" }
]
}
Item metadata обычно хранится off-chain (IPFS или HTTPS) для экономии газа. Collection предоставляет базовый URI, а Item добавляет свой suffix. Например: base_uri/42.json для Item #42.
Определение адреса NFT Item
Как кошельки и маркетплейсы находят NFT пользователя?
- По Collection: вызвать
get_nft_address_by_index(i)для каждогоiот 0 доnext_item_index - 1 - По Item: вызвать
get_nft_data()и проверитьowner - Через индексеры: TON API и эксплореры индексируют все NFT Item по событиям деплоя
На практике используют индексеры (TON API, Tonviewer) — перебирать все Item напрямую слишком дорого для больших коллекций.
Реализация NFT Collection в Tact
import "@stdlib/deploy";
contract NftCollection with Deployable {
next_item_index: Int as uint32;
owner: Address;
collection_content: Cell;
nft_item_code: Cell;
init(owner: Address, collection_content: Cell, nft_item_code: Cell) {
self.next_item_index = 0;
self.owner = owner;
self.collection_content = collection_content;
self.nft_item_code = nft_item_code;
}
receive(msg: MintNft) {
let ctx: Context = context();
require(ctx.sender == self.owner, "Not owner");
let nft_init: StateInit = self.getNftItemInit(self.next_item_index);
send(SendParameters{
to: contractAddress(nft_init),
value: ton("0.05"),
mode: 0,
body: NftDeploy{
index: self.next_item_index,
owner: msg.owner,
content: msg.content,
}.toCell(),
code: nft_init.code,
data: nft_init.data,
});
self.next_item_index = self.next_item_index + 1;
}
fun getNftItemInit(index: Int): StateInit {
return initOf NftItem(index, myAddress());
}
}
Масштабируемость: 10,001 контрактов
Для коллекции из 10,000 NFT в TON деплоится 10,001 контракт (1 Collection + 10,000 Item). Это может показаться расточительным, но:
- Каждый Item весит ~500 байт состояния
- Хранение стоит ~0.0002 TON/год на Item
- Общая стоимость хранения 10,000 NFT ~ 2 TON/год
- Трансферы обрабатываются параллельно в разных шардах
Частые ошибки
- Хранят изображения и метаданные on-chain, что чрезмерно дорого; стандартный подход использует IPFS или CDN с записью URL в контракт.
- Не реализуют get_nft_data() в NFT Item контракте, без чего маркетплейсы и кошельки не смогут отобразить информацию о токене.
- Путают индекс NFT внутри коллекции и глобальный адрес NFT Item: для работы с конкретным NFT нужен его адрес, а не индекс.
- Забывают о royalty при реализации торговли: стандарт TON NFT поддерживает royalty, и его игнорирование нарушает ожидания создателей коллекций.
Проверка знанийПочему NFT Collection в TON не может отозвать или заблокировать переданный NFT Item?
Проверьте понимание
Закончили урок?
Отметьте его как пройденный, чтобы отслеживать свой прогресс
Войдите чтобы оценить урок