Skip to content

Commit

Permalink
WIP fix CI for meta data pointer nft (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
Woody4618 authored Jun 14, 2024
1 parent 5107274 commit f0c0b36
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 83 deletions.
1 change: 0 additions & 1 deletion .github/.ghaignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ compression/cutils/anchor
compression/cnft-vault/anchor
# builds but need to test on localhost
compression/cnft-burn/anchor
tokens/token-2022/nft-meta-data-pointer/anchor-example/anchor
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[features]
seeds = false
[programs.localnet]
extension_nft = "MkabCfyUD6rBTaYHpgKBBpBo5qzWA2pK2hrGGKMurJt"
extension_nft = "9aZZ7TJ2fQZxY8hMtWXywp5y6BgqC4N2BPcr9FDT47sW"

[registry]
url = "https://anchor.projectserum.com"
Expand Down
Original file line number Diff line number Diff line change
@@ -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: {}",
Expand All @@ -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;
Expand All @@ -96,22 +95,24 @@ 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,
ctx.accounts.mint.key,
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
Expand All @@ -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(),
Expand All @@ -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(
Expand All @@ -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
Expand All @@ -169,7 +171,7 @@ pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
signer
),
AuthorityType::MintTokens,
None,
None
)?;

Ok(())
Expand All @@ -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 {}
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
pub use crate::errors::GameErrorCode;
pub use anchor_lang::prelude::*;
pub use session_keys::{session_auth_or, Session, SessionError};
pub use session_keys::{ session_auth_or, Session, SessionError };
pub mod constants;
pub mod errors;
pub mod instructions;
pub mod state;
use instructions::*;

declare_id!("H31ofLpWqeAzF2Pg54HSPQGYifJad843tTJg8vCYVoh3");
declare_id!("9aZZ7TJ2fQZxY8hMtWXywp5y6BgqC4N2BPcr9FDT47sW");

#[program]
pub mod extension_nft {

use super::*;

pub fn init_player(ctx: Context<InitPlayer>, _level_seed: String) -> Result<()> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import * as anchor from '@coral-xyz/anchor';
import type { Program } from '@coral-xyz/anchor';
import { ASSOCIATED_PROGRAM_ID } from '@coral-xyz/anchor/dist/cjs/utils/token';
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync } from '@solana/spl-token';
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_2022_PROGRAM_ID,
getAssociatedTokenAddressSync,
getOrCreateAssociatedTokenAccount,
} from '@solana/spl-token';
import { Keypair, PublicKey } from '@solana/web3.js';
import type { ExtensionNft } from '../target/types/extension_nft';

Expand Down Expand Up @@ -30,22 +35,16 @@ describe('extension_nft', () => {
ASSOCIATED_TOKEN_PROGRAM_ID,
);

const nft_authority = await PublicKey.findProgramAddress([Buffer.from('nft_authority')], program.programId);

getOrCreateAssociatedTokenAccount;
const tx = await program.methods
.mintNft()
.accounts({
signer: payer.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
tokenProgram: TOKEN_2022_PROGRAM_ID,
associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
tokenAccount: destinationTokenAccount,
mint: mint.publicKey,
nftAuthority: nft_authority[0],
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
})
.signers([mint])
.rpc({ skipPreflight: true });
.rpc();

console.log('Mint nft tx', tx);
await anchor.getProvider().connection.confirmTransaction(tx, 'confirmed');
Expand Down

0 comments on commit f0c0b36

Please sign in to comment.