Основна програма Metaplex
Основна програма Metaplex вирішує проблеми складності та вартості, притаманні багатоакаунтній архітектурі програми Token Metadata. Хоча Token Metadata спирається на SPL-Token як свою основу, вимагаючи кілька акаунтів для кожного NFT, такий підхід створює дорогі та громіздкі реалізації, які обтяжують як користувачів, так і мережу.
Випущена у 2024 році, Metaplex Core представляє собою надлегку програму, розроблену спеціально для операцій з NFT. На відміну від свого попередника, Core працює незалежно без залежностей від SPL-Token, обробляючи карбування, передачі, спалювання та налаштовувану поведінку через власну програмну логіку.
Цей стандарт нового покоління використовує дизайн з одним акаунтом, що значно зменшує витрати на карбування, одночасно покращуючи загальну продуктивність мережі завдяки гнучкій системі плагінів.
Assets
Революційний аспект Metaplex Core полягає в її уніфікованій структурі акаунтів, яка усуває традиційне розділення між акаунтами карбування та токенів.
Оскільки NFT підтримують унікальне володіння з одним власником, програма зберігає відносини між гаманцем та активом безпосередньо в самому акаунті активу.
Цей дизайн має інтуїтивний сенс, якщо врахувати, що оригінальна система Token Account була створена для управління тисячами власників на один карбований токен, сценарій, який ніколи не застосовується до невзаємозамінних токенів.
Структура Asset демонструє цей підхід, орієнтований на ефективність, через свої мінімальні вимоги до полів:
#[derive(Clone, BorshSerialize, BorshDeserialize, Debug, ShankAccount, Eq, PartialEq)]
pub struct AssetV1 {
/// The account discriminator.
pub key: Key,
/// The owner of the asset.
pub owner: Pubkey,
/// The update authority of the asset.
pub update_authority: UpdateAuthority,
/// The name of the asset.
pub name: String,
/// The URI of the asset that points to the off-chain data.
pub uri: String,
/// The sequence number used for indexing with compression.
pub seq: Option<u64>,
}
Ця структура представляє абсолютний мінімум даних, необхідних для функціональних операцій з NFT.
Традиційні поля акаунта Mint
стають надлишковими в цьому контексті, оскільки: запас завжди дорівнює одиниці, десяткові знаки завжди дорівнюють нулю, повноваження карбування повинні залишатися невстановленими, а повноваження заморожування можуть бути об'єднані з полем повноважень оновлення.
Аналогічно, більшість функціональності облікового запису Token
інтегрується безпосередньо в структуру активу.
Відсутність явного механізму заморожування демонструє філософію розумного дизайну Core.
Замість того, щоб резервувати місце для функцій, які багато активів ніколи не використовують, Core реалізує функціональність заморожування через свою систему плагінів, додаючи можливості за потреби, а не підтримуючи невикористані поля.
Цей підхід оптимізує витрати на зберігання, зберігаючи при цьому повну функціональність для активів, які потребують можливостей заморожування.
Членство в колекції отримує однаково продуманий підхід через систему перерахування повноважень оновлення: оскільки згруповані активи зазвичай мають однакові повноваження оновлення, Core використовує цей зв'язок для усунення надлишкового зберігання полів:
pub enum UpdateAuthority {
None,
Address(Pubkey),
Collection(Pubkey),
}
Поле повноважень оновлення виконує потрійну функцію, вказуючи на незмінні активи через None
, незалежні активи через конкретні адреси або членів колекції, які успадковують повноваження оновлення від своєї батьківської колекції.
Це елегантне рішення зменшує вимоги до зберігання, зберігаючи при цьому чіткі відносини повноважень та перевірку членства в колекції.
Collections
Колекції в Metaplex Core представляють згруповані набори активів, які мають тематичні, творчі або функціональні зв'язки.
На відміну від традиційних колекцій NFT, які покладаються на зовнішні системи перевірки, колекції Core встановлюють перевірені онлайн-зв'язки між активами через їхню інтегровану структуру повноважень.
Створення колекції починається зі встановлення Активу Колекції, який служить авторитетним батьківським обліковим записом для всіх активів-членів.
Цей Актив Колекції функціонує як організаційний центр і сховище метаданих для загальної інформації про колекцію, включаючи назву колекції, опис та репрезентативні зображення.
Обліковий запис колекції також діє як центральна точка контролю для плагінів, які застосовуються до всіх активів-членів, дозволяючи творцям впроваджувати однакову поведінку по всій своїй колекції.
pub struct CollectionV1 {
/// The account discriminator.
pub key: Key, //1
/// The update authority of the collection.
pub update_authority: Pubkey, //32
/// The name of the collection.
pub name: String, //4
/// The URI that links to what data to show for the collection.
pub uri: String, //4
/// The number of assets minted in the collection.
pub num_minted: u32, //4
/// The number of assets currently in the collection.
pub current_size: u32, //4
}
Структура колекції підтримує критично важливу статистику через поля num_minted
та current_size
, які відстежують загальну кількість активів, коли-небудь створених у колекції, та поточну кількість активів, що залишаються активними.
Ці метрики забезпечують точну аналітику колекцій і підтримують такі функції, як випуск обмежених видань або відстеження спалювання без необхідності використання зовнішніх служб індексації.
Коли актив встановлює своє update_authority
на Collection(collection_pubkey)
, він автоматично успадковує структуру повноважень колекції, одночасно встановлюючи перевірене членство. Ця конструкція усуває потребу в окремих облікових записах верифікації або зовнішніх системах атестації, створюючи незмінні зв'язки колекцій, які можна перевірити повністю в мережі.
Plugins
Система плагінів є найбільш інноваційною функцією Metaplex Core, яка вирішує обмеження жорстких, заздалегідь визначених поведінок, що характеризували попередні стандарти NFT.
У той час як застаріла програма Token Metadata вимагала складних обхідних шляхів, таких як програмовані NFT для користувацької функціональності, архітектура плагінів Core забезпечує детальну кастомізацію без шкоди для простоти чи продуктивності.
Революційний підхід Core розглядає дані в мережі гнучко, а не фіксує їх у жорстких структурах. Ця філософія дизайну забезпечує гнучку систему на основі плагінів, яка обслуговує різноманітні випадки використання, зберігаючи ефективне управління обліковими записами.
Кожен плагін визначає власну модель дозволів, точно вказуючи, хто може виконувати певні дії, тоді як система валідації Core запобігає конфліктам між різними повноваженнями та дозволами.
Архітектура облікового запису поділяється на два окремі компоненти:
- Основний розділ даних, що містить важливу інформацію про актив з передбачуваною довжиною полів
- Необов'язковий розділ метаданих плагіна, де розміщуються додаткові функціональні можливості та користувацька поведінка.
Це розділення забезпечує легкість базових активів, тоді як складна функціональність масштабується за потребою.
Метадані плагіна організовуються через трикомпонентну структуру: заголовок, окремі плагіни та реєстр, який координує все.
Header | Plugin1 | Plugin2 | Plugin3 | Registry
Заголовок плагіна служить точкою входу, містячи вказівник plugin_registry_offset
, який вказує на розташування реєстру в обліковому записі:
pub struct PluginHeaderV1 {
/// The Discriminator of the header which doubles as a Plugin metadata version.
pub key: Key, // 1
/// The offset to the plugin registry stored at the end of the account.
pub plugin_registry_offset: usize, // 8
}
Реєстр плагінів функціонує як координаційний центр, підтримуючи вектори як внутрішніх записів RegistryRecord
, так і записів ExternalRegistryRecord
для сторонніх плагінів.
Кожен запис містить тип плагіна, керуючий орган та зміщення розташування в обліковому записі:
pub struct PluginRegistryV1 {
/// The Discriminator of the header which doubles as a plugin metadata version.
pub key: Key, // 1
/// The registry of all plugins.
pub registry: Vec<RegistryRecord>, // 4
/// The registry of all adapter, third party, plugins.
pub external_registry: Vec<ExternalRegistryRecord>, // 4
}
pub struct RegistryRecord {
/// The type of plugin.
pub plugin_type: PluginType, // 2
/// The authority who has permission to utilize a plugin.
pub authority: Authority, // Variable
/// The offset to the plugin in the account.
pub offset: usize, // 8
}
pub struct ExternalRegistryRecord {
/// The adapter, third party plugin type.
pub plugin_type: ExternalPluginAdapterType,
/// The authority of the external plugin adapter.
pub authority: Authority,
/// The lifecycle events for which the external plugin adapter is active.
pub lifecycle_checks: Option<Vec<(HookableLifecycleEvent, ExternalCheckResult)>>,
/// The offset to the plugin in the account.
pub offset: usize, // 8
/// For plugins with data, the offset to the data in the account.
pub data_offset: Option<usize>,
/// For plugins with data, the length of the data in the account.
pub data_len: Option<usize>,
}
Отримання плагінів відбувається за систематичним процесом, який використовує цю організовану структуру.
Система спочатку завантажує дані активу, щоб визначити розташування заголовка плагіна, потім використовує зміщення заголовка для знаходження реєстру, і нарешті перебирає записи реєстру для складання повного списку плагінів:
pub fn list_plugins(account: &AccountInfo) -> Result<Vec<PluginType>, ProgramError> {
let asset = AssetV1::load(account, 0)?;
if asset.get_size() == account.data_len() {
return Err(MplCoreError::PluginNotFound.into());
}
let header = PluginHeaderV1::load(account, asset.get_size())?;
let PluginRegistryV1 { registry, .. } =
PluginRegistryV1::load(account, header.plugin_registry_offset)?;
Ok(registry
.iter()
.map(|registry_record| registry_record.plugin_type)
.collect())
}