Với Token Extension Program, bạn có thể tạo NFT và tài sản kỹ thuật số bằng cách sử dụng các extension metadata. Kết hợp lại, các extension này (metadata pointer và token metadata) cho phép bạn lưu trữ bất kỳ metadata mong muốn nào trực tiếp trên chuỗi. Tất cả đều nằm trong một kho dữ liệu key-value có thể tùy chỉnh trực tiếp trên mint account của token, giúp giảm chi phí và độ phức tạp.
Điều này đặc biệt hữu ích cho các game web3 vì chúng ta có thể có các "trường metadata bổ sung" trong một kho key-value trên chuỗi, cho phép các game lưu/truy cập trạng thái độc đáo ngay trong chính NFT (chẳng hạn như chỉ số hoặc kho đồ của nhân vật game).
Xây dựng chương trình onchain
Trong hướng dẫn dành cho nhà phát triển này, chúng tôi sẽ trình bày cách xây dựng các NFT dựa trên Token Extension và metadata tùy chỉnh bằng cách sử dụng Anchor program. Chương trình này sẽ lưu cấp độ và các tài nguyên đã thu thập của người chơi game trong một NFT.
NFT này sẽ được tạo bởi Anchor program, giúp việc mint từ client JavaScript trở nên rất đơn giản. Mỗi NFT sẽ có một số cấu trúc cơ bản được cung cấp thông qua giao diện Token Metadata:
- các trường mặc định onchain -
name,symbolvàuriurilà liên kết đến một tệp json offchain chứa metadata ngoài chuỗi của NFT
- chúng ta cũng sẽ có các "trường bổ sung" tùy chỉnh mà chúng ta định nghĩa
Tất cả các trường này được lưu bằng extension metadata, được trỏ đến mint account của NFT, giúp bất kỳ ai hoặc bất kỳ chương trình nào cũng có thể truy cập chúng.
Video và Mã Nguồn
Bạn có thể tìm thấy video hướng dẫn về ví dụ này trên kênh YouTube của Solana Foundation:
Các trường hợp sử dụng khác trong game
Các loại NFT với metadata onchain có thể tùy chỉnh này mở ra nhiều khả năng thú vị cho các nhà phát triển game. Đặc biệt khi metadata này có thể được tương tác trực tiếp hoặc quản lý bởi một chương trình onchain.
Một số trường hợp sử dụng liên quan đến game bao gồm:
- lưu cấp độ và XP của người chơi
- vũ khí và giáp hiện tại
- nhiệm vụ hiện tại
- và còn nhiều hơn nữa!
Mint NFT
Để tạo NFT, chúng ta cần thực hiện các bước sau:
- Tạo một mint account
- Khởi tạo mint account
- Tạo một tài khoản metadata pointer
- Khởi tạo tài khoản metadata pointer
- Tạo tài khoản metadata
- Khởi tạo tài khoản metadata
- Tạo associated token account
- Mint token vào associated token account
- Đóng băng quyền mint
Mã chương trình Rust
Đây là mã Rust được dùng để mint NFT bằng 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,)?;
Mã client JavaScript
Gọi mint NFT từ client rất đơn giản:
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`);
Ví dụ Quickstart
Ví dụ trên được xây dựng dựa trên Solana Games Preset, tạo ra cho bạn một scaffold bao gồm client JavaScript và Unity cho game này, kèm theo cấu hình để tương tác với Anchor program trên Solana.
Bạn có thể tự chạy với lệnh sau:
npx create-solana-game gameName
Thiết lập môi trường cục bộ
Để chạy ví dụ này cục bộ, bạn cần đảm bảo rằng bạn đã thiết lập môi trường cục bộ cho việc phát triển Solana, bao gồm việc cài đặt và cấu hình Anchor CLI. Nếu chưa có, bạn có thể làm theo hướng dẫn thiết lập đã được liên kết trước đó.
Cấu trúc dự án
Dự án Anchor được cấu trúc như sau:
Điểm vào là tệp lib.rs. Tại đây chúng ta định nghĩa id chương trình và các lệnh. Các lệnh được định nghĩa trong thư mục instructions. Trạng thái được định nghĩa trong thư mục state.
Vì vậy các lời gọi đến tệp lib.rs và sau đó được chuyển tiếp đến các lệnh. Các lệnh sau đó gọi state để lấy dữ liệu và cập nhật nó.
Bạn có thể tìm thấy lệnh mint NFT trong thư mục 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 Program
Để hoàn tất việc thiết lập Anchor program được tạo từ công cụ create-solana-game:
cd programđể vào thư mục chương trình- Chạy
anchor buildđể build chương trình - Chạy
anchor deployđể deploy chương trình - Sao chép program id từ terminal vào
lib.rs,anchor.tomlvà trong dự án Unity tạiAnchorService, và nếu bạn dùng JavaScript thì vào tệpanchor.ts - Build và deploy lại
Client NextJS
Để hoàn tất việc thiết lập client NextJS được tạo từ công cụ create-solana-game:
- Sao chép
programIdvàoapp/utils/anchor.ts cd appđể vào thư mục app- Chạy
yarn installđể cài đặt các phụ thuộc Node - Chạy
yarn devđể khởi động client - Sau khi thực hiện các thay đổi đối với Anchor program, hãy đảm bảo sao chép các kiểu
từ chương trình vào client để bạn có thể sử dụng chúng. Bạn có thể tìm thấy các
kiểu TypeScript trong thư mục
target/idl.
Chạy ví dụ này cục bộ
Sử dụng lệnh test của Anchor với cờ --detach sẽ khởi động và cấu hình
validator kiểm thử cục bộ Solana của bạn để triển khai chương trình (và giữ cho
validator tiếp tục chạy sau khi các bài kiểm thử hoàn thành):
cd programanchor test --detach
Sau đó bạn có thể đặt Solana Explorer để sử dụng
validator kiểm thử cục bộ của bạn (khởi động khi chạy lệnh anchor test) để
bạn có thể xem các giao dịch:
https://explorer.solana.com/?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899
Chương trình cũng đã được triển khai trên mạng, vì vậy bạn có thể thử nghiệm trên devnet.
Client JavaScript cũng có một nút để mint NFT. Khởi động client JavaScript:
cd appyarn installyarn dev
Mở dự án Unity
Đầu tiên mở dự án Unity với Unity Version 2021.3.32.f1 (hoặc tương tự), sau đó
mở GameScene hoặc LoginScene và nhấn play. Sử dụng nút đăng nhập trong trình chỉnh sửa
ở góc dưới bên trái.
Nếu bạn không thể lấy SOL trên devnet, bạn có thể sao chép địa chỉ của mình từ console và theo dõi hướng dẫn trong tài liệu này về cách lấy SOL trên devnet
Kết nối với Solana test validator trong Unity
Nếu bạn muốn tránh phải lo lắng về việc duy trì SOL trên devnet, bạn có thể kết nối với validator kiểm thử cục bộ đang chạy của mình từ bên trong Unity. Chỉ cần thêm các liên kết này vào đối tượng game wallet holder:
http://localhost:8899ws://localhost:8900
Chạy client JavaScript
Để khởi động client JavaScript và có thể tương tác với game và chương trình bằng trình duyệt web của bạn:
- mở thư mục
apptrong repo - cài đặt các phụ thuộc Node
- chạy lệnh
devđể khởi động server phát triển
cd appyarn installyarn dev
Để bắt đầu thay đổi chương trình và kết nối với chương trình của riêng bạn, hãy làm theo các bước dưới đây.
Is this page helpful?