|
@@ -1,27 +1,33 @@
|
|
|
pub use crate::errors::GameErrorCode;
|
|
|
pub use crate::errors::ProgramErrorCode;
|
|
|
pub use crate::state::game_data::GameData;
|
|
|
-use anchor_lang::{prelude::*, system_program};
|
|
|
+use anchor_lang::{ prelude::*, system_program };
|
|
|
use anchor_spl::{
|
|
|
- associated_token::{self, AssociatedToken}, token_2022, token_interface::{spl_token_2022::instruction::AuthorityType, Token2022}
|
|
|
+ associated_token::{ self, AssociatedToken },
|
|
|
+ token_2022,
|
|
|
+ token_interface::{ spl_token_2022::instruction::AuthorityType, Token2022 },
|
|
|
};
|
|
|
-use solana_program::program::{invoke, invoke_signed};
|
|
|
-use spl_token_2022::{extension::ExtensionType, state::Mint};
|
|
|
+use solana_program::program::{ invoke, invoke_signed };
|
|
|
+use spl_token_2022::{ extension::ExtensionType, state::Mint };
|
|
|
|
|
|
pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
|
|
|
msg!("Mint nft with meta data extension and additional meta data");
|
|
|
|
|
|
- let space = match ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::MetadataPointer]) {
|
|
|
+ let space = match
|
|
|
+ ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::MetadataPointer])
|
|
|
+ {
|
|
|
Ok(space) => space,
|
|
|
- Err(_) => return err!(ProgramErrorCode::InvalidMintAccountSpace)
|
|
|
+ Err(_) => {
|
|
|
+ return err!(ProgramErrorCode::InvalidMintAccountSpace);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
- // This is the space required for the metadata account.
|
|
|
- // We put the meta data into the mint account at the end so we
|
|
|
- // don't need to create and additional account.
|
|
|
+ // This is the space required for the metadata account.
|
|
|
+ // We put the meta data into the mint account at the end so we
|
|
|
+ // don't need to create and additional account.
|
|
|
let meta_data_space = 250;
|
|
|
|
|
|
- let lamports_required = (Rent::get()?).minimum_balance(space + meta_data_space);
|
|
|
+ let lamports_required = Rent::get()?.minimum_balance(space + meta_data_space);
|
|
|
|
|
|
msg!(
|
|
|
"Create Mint and metadata account size and cost: {} lamports: {}",
|
|
@@ -35,59 +41,52 @@ pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
|
|
|
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(),
|
|
|
+ &ctx.accounts.token_program.key()
|
|
|
)?;
|
|
|
|
|
|
// Assign the mint to the token program
|
|
|
system_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,
|
|
|
+ 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 =
|
|
|
- match 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()),
|
|
|
- ) {
|
|
|
+ let init_meta_data_pointer_ix = match
|
|
|
+ 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())
|
|
|
+ )
|
|
|
+ {
|
|
|
Ok(ix) => ix,
|
|
|
- Err(_) => return err!(ProgramErrorCode::CantInitializeMetadataPointer)
|
|
|
+ Err(_) => {
|
|
|
+ return err!(ProgramErrorCode::CantInitializeMetadataPointer);
|
|
|
+ }
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
invoke(
|
|
|
&init_meta_data_pointer_ix,
|
|
|
- &[
|
|
|
- ctx.accounts.mint.to_account_info(),
|
|
|
- ctx.accounts.nft_authority.to_account_info()
|
|
|
- ],
|
|
|
+ &[ctx.accounts.mint.to_account_info(), ctx.accounts.nft_authority.to_account_info()]
|
|
|
)?;
|
|
|
-
|
|
|
+
|
|
|
// Initialize the mint cpi
|
|
|
let 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
|
|
|
+ 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;
|
|
@@ -96,8 +95,7 @@ pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
|
|
|
msg!("Init metadata {0}", ctx.accounts.nft_authority.to_account_info().key);
|
|
|
|
|
|
// Init the metadata account
|
|
|
- let init_token_meta_data_ix =
|
|
|
- &spl_token_metadata_interface::instruction::initialize(
|
|
|
+ let 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,
|
|
@@ -105,13 +103,16 @@ pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
|
|
|
ctx.accounts.nft_authority.to_account_info().key,
|
|
|
"Beaver".to_string(),
|
|
|
"BVA".to_string(),
|
|
|
- "https://arweave.net/MHK3Iopy0GgvDoM7LkkiAdg7pQqExuuWvedApCnzfj0".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,
|
|
|
+ &[
|
|
|
+ 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 level
|
|
@@ -121,7 +122,7 @@ pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
|
|
|
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(),
|
|
|
+ "1".to_string()
|
|
|
),
|
|
|
&[
|
|
|
ctx.accounts.mint.to_account_info().clone(),
|
|
@@ -133,16 +134,17 @@ pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
|
|
|
// Create the associated token account
|
|
|
associated_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(),
|
|
|
- },
|
|
|
- ))?;
|
|
|
+ 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 player
|
|
|
token_2022::mint_to(
|
|
@@ -155,7 +157,7 @@ pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
|
|
|
},
|
|
|
signer
|
|
|
),
|
|
|
- 1,
|
|
|
+ 1
|
|
|
)?;
|
|
|
|
|
|
// Freeze the mint authority so no more tokens can be minted to make it an NFT
|
|
@@ -169,7 +171,7 @@ pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
|
|
|
signer
|
|
|
),
|
|
|
AuthorityType::MintTokens,
|
|
|
- None,
|
|
|
+ None
|
|
|
)?;
|
|
|
|
|
|
Ok(())
|
|
@@ -188,16 +190,9 @@ pub struct MintNft<'info> {
|
|
|
pub mint: Signer<'info>,
|
|
|
pub rent: Sysvar<'info, Rent>,
|
|
|
pub associated_token_program: Program<'info, AssociatedToken>,
|
|
|
- #[account(
|
|
|
- init_if_needed,
|
|
|
- seeds = [b"nft_authority".as_ref()],
|
|
|
- bump,
|
|
|
- space = 8,
|
|
|
- payer = signer,
|
|
|
- )]
|
|
|
- pub nft_authority: Account<'info, NftAuthority >
|
|
|
+ #[account(init_if_needed, seeds = [b"nft_authority".as_ref()], bump, space = 8, payer = signer)]
|
|
|
+ pub nft_authority: Account<'info, NftAuthority>,
|
|
|
}
|
|
|
|
|
|
#[account]
|
|
|
-pub struct NftAuthority {
|
|
|
-}
|
|
|
+pub struct NftAuthority {}
|