С помощью Token Extension program вы можете создавать NFT и цифровые активы, используя расширения метаданных. Вместе эти расширения (metadata pointer и token metadata) позволяют размещать любые нужные метаданные непосредственно в блокчейне. Всё это — в настраиваемом хранилище данных типа «ключ-значение» прямо на mint account токена, что снижает затраты и сложность.
Это особенно полезно для web3-игр, поскольку теперь можно хранить «дополнительные поля метаданных» в хранилище ключ-значение в блокчейне, позволяя играм сохранять и получать уникальное состояние внутри самого NFT (например, характеристики или инвентарь игрового персонажа).
Создание программы в блокчейне
В этом руководстве для разработчиков мы покажем, как создавать NFT на основе Token Extension и настраиваемые метаданные с помощью программы Anchor. Эта программа будет сохранять уровень и собранные ресурсы игрока внутри NFT.
Этот NFT будет создан программой Anchor, поэтому выпускать его через клиент на JavaScript очень просто. Каждый NFT будет иметь базовую структуру, предоставляемую интерфейсом Token Metadata:
- стандартные поля в блокчейне —
name,symbolиuriuri— это ссылка на внешний JSON-файл, содержащий внецепочечные метаданные NFT
- также у нас будут пользовательские «дополнительные поля», которые мы определяем сами
Все эти поля сохраняются с использованием расширения метаданных, которое указывает на mint account NFT, делая их доступными для любого пользователя или программы.
Видео и исходный код
Вы можете найти видеообзор этого примера на YouTube-канале Solana Foundation:
Другие варианты использования в играх
NFT такого типа с настраиваемыми метаданными в блокчейне открывают множество интересных возможностей для разработчиков игр. Особенно с учётом того, что этими метаданными можно напрямую взаимодействовать или управлять с помощью программы в блокчейне.
Некоторые из игровых вариантов использования включают:
- сохранение уровня и опыта (XP) игрока
- текущее оружие и броня
- текущий квест
- и это ещё не всё!
Выпуск NFT
Для создания NFT необходимо выполнить следующие шаги:
- Создать mint account
- Инициализировать mint account
- Создать аккаунт указателя метаданных
- Инициализировать аккаунт указателя метаданных
- Создать аккаунт метаданных
- Инициализировать аккаунт метаданных
- Создать associated token account
- Выпустить токен на associated token account
- Заморозить права на выпуск
Код программы на Rust
Вот код на Rust, используемый для выпуска NFT с помощью Token Extension program:
// calculate the space need for the mint account with the desired extensionslet space = ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::MetadataPointer]).unwrap();// This is the space required for the metadata account.// We put the metadata into the mint account at the end so we// don't need to create and additional account.// Then the metadata pointer points back to the mint account.// Using this technique, only one account is needed for both the mint// information and the metadata.let meta_data_space = 250;let lamports_required = (Rent::get()?).minimum_balance(space + meta_data_space);msg!("Create Mint and metadata account size and cost: {} lamports: {}",space as u64,lamports_required);system_program::create_account(CpiContext::new(ctx.accounts.token_program.to_account_info(),system_program::CreateAccount {from: ctx.accounts.signer.to_account_info(),to: ctx.accounts.mint.to_account_info(),},),lamports_required,space as u64,&ctx.accounts.token_program.key(),)?;// Assign the mint to the token programsystem_program::assign(CpiContext::new(ctx.accounts.token_program.to_account_info(),system_program::Assign {account_to_assign: ctx.accounts.mint.to_account_info(),},),&token_2022::ID,)?;// Initialize the metadata pointer (Need to do this before initializing the mint)let init_meta_data_pointer_ix =spl_token_2022::extension::metadata_pointer::instruction::initialize(&Token2022::id(),&ctx.accounts.mint.key(),Some(ctx.accounts.nft_authority.key()),Some(ctx.accounts.mint.key()),).unwrap();invoke(&init_meta_data_pointer_ix,&[ctx.accounts.mint.to_account_info(),ctx.accounts.nft_authority.to_account_info()],)?;// Initialize the mint cpilet mint_cpi_ix = CpiContext::new(ctx.accounts.token_program.to_account_info(),token_2022::InitializeMint2 {mint: ctx.accounts.mint.to_account_info(),},);token_2022::initialize_mint2(mint_cpi_ix,0,&ctx.accounts.nft_authority.key(),None).unwrap();// We use a PDA as a mint authority for the metadata account because// we want to be able to update the NFT from the program.let seeds = b"nft_authority";let bump = ctx.bumps.nft_authority;let signer: &[&[&[u8]]] = &[&[seeds, &[bump]]];msg!("Init metadata {0}", ctx.accounts.nft_authority.to_account_info().key);// Init the metadata accountlet init_token_meta_data_ix =&spl_token_metadata_interface::instruction::initialize(&spl_token_2022::id(),ctx.accounts.mint.key,ctx.accounts.nft_authority.to_account_info().key,ctx.accounts.mint.key,ctx.accounts.nft_authority.to_account_info().key,"Beaver".to_string(),"BVA".to_string(),"https://arweave.net/MHK3Iopy0GgvDoM7LkkiAdg7pQqExuuWvedApCnzfj0".to_string(),);invoke_signed(init_token_meta_data_ix,&[ctx.accounts.mint.to_account_info().clone(), ctx.accounts.nft_authority.to_account_info().clone()],signer,)?;// Update the metadata account with an additional metadata field in this case the player levelinvoke_signed(&spl_token_metadata_interface::instruction::update_field(&spl_token_2022::id(),ctx.accounts.mint.key,ctx.accounts.nft_authority.to_account_info().key,spl_token_metadata_interface::state::Field::Key("level".to_string()),"1".to_string(),),&[ctx.accounts.mint.to_account_info().clone(),ctx.accounts.nft_authority.to_account_info().clone(),],signer)?;// Create the associated token accountassociated_token::create(CpiContext::new(ctx.accounts.associated_token_program.to_account_info(),associated_token::Create {payer: ctx.accounts.signer.to_account_info(),associated_token: ctx.accounts.token_account.to_account_info(),authority: ctx.accounts.signer.to_account_info(),mint: ctx.accounts.mint.to_account_info(),system_program: ctx.accounts.system_program.to_account_info(),token_program: ctx.accounts.token_program.to_account_info(),},))?;// Mint one token to the associated token account of the playertoken_2022::mint_to(CpiContext::new_with_signer(ctx.accounts.token_program.to_account_info(),token_2022::MintTo {mint: ctx.accounts.mint.to_account_info(),to: ctx.accounts.token_account.to_account_info(),authority: ctx.accounts.nft_authority.to_account_info(),},signer),1,)?;// Freeze the mint authority so no more tokens can be minted to make it an NFTtoken_2022::set_authority(CpiContext::new_with_signer(ctx.accounts.token_program.to_account_info(),token_2022::SetAuthority {current_authority: ctx.accounts.nft_authority.to_account_info(),account_or_mint: ctx.accounts.mint.to_account_info(),},signer),AuthorityType::MintTokens,None,)?;
Код клиента на JavaScript
Вызов выпуска NFT из клиента очень прост:
const nftAuthority = PublicKey.findProgramAddressSync([Buffer.from("nft_authority")],program.programId);const mint = new Keypair();const destinationTokenAccount = getAssociatedTokenAddressSync(mint.publicKey,publicKey,false,TOKEN_2022_PROGRAM_ID);const transaction = await program.methods.mintNft().accounts({signer: publicKey,systemProgram: SystemProgram.programId,tokenProgram: TOKEN_2022_PROGRAM_ID,tokenAccount: destinationTokenAccount,mint: mint.publicKey,rent: web3.SYSVAR_RENT_PUBKEY,associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,nftAuthority: nftAuthority[0]}).signers([mint]).transaction();console.log("transaction", transaction);const txSig = await sendTransaction(transaction, connection, {signers: [mint],skipPreflight: true});console.log(`https://explorer.solana.com/tx/${txSig}?cluster=devnet`);
Пример быстрого старта
Приведённый выше пример основан на Solana Games Preset, который генерирует шаблон проекта, включающий клиент на JavaScript и Unity для этой игры, а также конфигурацию для взаимодействия с программой Anchor на Solana.
Вы можете запустить его самостоятельно с помощью следующей команды:
npx create-solana-game gameName
Настройка локальной среды
Чтобы запустить этот пример локально, убедитесь, что вы настроили локальную среду для разработки на Solana, включая установку и настройку Anchor CLI. Если вы этого ещё не сделали, вы можете воспользоваться упомянутым руководством по настройке.
Структура проекта
Проект Anchor структурирован следующим образом:
Точка входа находится в файле lib.rs. Здесь определяются идентификатор программы и инструкции. Инструкции определены в папке instructions. Состояние определено в папке state.
Таким образом, вызовы поступают в файл lib.rs и затем перенаправляются в инструкции. Инструкции затем обращаются к состоянию для получения данных и их обновления.
Инструкцию выпуска NFT можно найти в папке instructions.
├── src│ ├── instructions│ │ ├── chop_tree.rs│ │ ├── init_player.rs│ │ ├── mint_nft.rs│ │ └── update_energy.rs│ ├── state│ │ ├── game_data.rs│ │ ├── mod.rs│ │ └── player_data.rs│ ├── lib.rs│ └── constants.rs│ └── errors.rs
Программа Anchor
Для завершения настройки программы Anchor, сгенерированной инструментом create-solana-game:
cd program— для перехода в директорию программы- Выполните
anchor buildдля сборки программы - Выполните
anchor deployдля развёртывания программы - Скопируйте идентификатор программы из терминала в
lib.rs,anchor.tomlи в Unity-проекте вAnchorService, а если используете JavaScript — в файлanchor.ts - Выполните сборку и развёртывание ещё раз
Клиент NextJS
Для завершения настройки клиента NextJS, сгенерированного инструментом create-solana-game:
- Скопируйте
programIdвapp/utils/anchor.ts cd app— для перехода в директорию приложения- Выполните
yarn installдля установки зависимостей Node - Выполните
yarn devдля запуска клиента - После внесения изменений в программу Anchor обязательно скопируйте типы
из программы в клиент, чтобы их можно было использовать. Типы TypeScript
находятся в папке
target/idl.
Запуск этого примера локально
Использование команды test Anchor с флагом --detach запустит и настроит
локальный тестовый validator Solana с развёрнутой программой (и оставит
validator работающим после завершения тестов):
cd programanchor test --detach
Затем вы можете настроить Solana Explorer на использование вашего
локального тестового validator (который запускается при выполнении команды anchor test), чтобы
просматривать транзакции:
https://explorer.solana.com/?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899
Программа также уже развёрнута в сети, и вы можете опробовать её в devnet.
Клиент JavaScript также имеет кнопку для выпуска NFT. Запуск клиента JavaScript:
cd appyarn installyarn dev
Открытие проекта Unity
Сначала откройте проект Unity с версией Unity 2021.3.32.f1 (или аналогичной), затем
откройте GameScene или LoginScene и нажмите Play. Используйте кнопку входа в редакторе
в нижнем левом углу.
Если вы не можете получить devnet SOL, скопируйте свой адрес из консоли и следуйте инструкциям в этом руководстве: как получить devnet SOL
Подключение к тестовому validator Solana в Unity
Если вы хотите избежать необходимости следить за наличием devnet SOL, вы можете подключиться к запущенному локальному тестовому validator из Unity. Просто добавьте эти ссылки на игровой объект wallet holder:
http://localhost:8899ws://localhost:8900
Запуск клиента JavaScript
Чтобы запустить клиент JavaScript и иметь возможность взаимодействовать с игрой и программой через веб-браузер:
- откройте директорию
appв репозитории - установите зависимости Node
- выполните команду
devдля запуска сервера разработки
cd appyarn installyarn dev
Чтобы начать изменять программу и подключиться к своей программе, выполните следующие шаги.
Is this page helpful?