diff --git a/programs/wen_new_standard/src/instructions/group/create.rs b/programs/wen_new_standard/src/instructions/group/create.rs index 0a7bbcb..6d242e9 100644 --- a/programs/wen_new_standard/src/instructions/group/create.rs +++ b/programs/wen_new_standard/src/instructions/group/create.rs @@ -2,16 +2,15 @@ use anchor_lang::{prelude::*, solana_program::entrypoint::ProgramResult}; use anchor_spl::{ associated_token::AssociatedToken, token_interface::{ - mint_to, set_authority, spl_token_2022::instruction::AuthorityType, + mint_to, set_authority, + spl_token_2022::instruction::AuthorityType, + token_group::{token_group_initialize, TokenGroupInitialize}, token_metadata_initialize, Mint, MintTo, SetAuthority, Token2022, TokenAccount, TokenMetadataInitialize, }, }; -use crate::{ - update_account_lamports_to_minimum_balance, Manager, TokenGroup, GROUP_ACCOUNT_SEED, - MANAGER_SEED, -}; +use crate::{update_account_lamports_to_minimum_balance, Manager, MANAGER_SEED}; #[derive(AnchorDeserialize, AnchorSerialize)] pub struct CreateGroupAccountArgs { @@ -31,14 +30,6 @@ pub struct CreateGroupAccount<'info> { #[account()] /// CHECK: can be any account pub receiver: UncheckedAccount<'info>, - #[account( - init, - seeds = [GROUP_ACCOUNT_SEED, mint.key().as_ref()], - bump, - payer = payer, - space = 8 + TokenGroup::INIT_SPACE - )] - pub group: Account<'info, TokenGroup>, #[account( init, signer, @@ -49,9 +40,8 @@ pub struct CreateGroupAccount<'info> { mint::freeze_authority = manager, extensions::metadata_pointer::authority = authority, extensions::metadata_pointer::metadata_address = mint, - // group pointer authority is left as the manager so that it can be updated once token group support inside mint is added - extensions::group_pointer::authority = manager, - extensions::group_pointer::group_address = group, + extensions::group_pointer::authority = authority, + extensions::group_pointer::group_address = mint, // temporary mint close authority until a better program accounts can be used extensions::close_authority::authority = manager, )] @@ -88,6 +78,19 @@ impl<'info> CreateGroupAccount<'info> { Ok(()) } + fn initialize_group(&self, max_size: u32) -> Result<()> { + let cpi_accounts = TokenGroupInitialize { + group: self.mint.to_account_info(), + mint: self.mint.to_account_info(), + mint_authority: self.authority.to_account_info(), + token_program_id: self.token_program.to_account_info(), + }; + + let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts); + token_group_initialize(cpi_ctx, Some(self.authority.key()), max_size)?; + Ok(()) + } + fn mint_to_receiver(&self) -> Result<()> { let cpi_ctx = MintTo { mint: self.mint.to_account_info(), @@ -105,9 +108,7 @@ impl<'info> CreateGroupAccount<'info> { account_or_mint: self.mint.to_account_info(), }; let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts); - // manager needs to be the new authority so that when solana upgrades to support group accounts, the mint can be updated - // this will updated to None once solana supports group accounts - set_authority(cpi_ctx, AuthorityType::MintTokens, Some(self.manager.key()))?; + set_authority(cpi_ctx, AuthorityType::MintTokens, None)?; Ok(()) } } @@ -117,12 +118,8 @@ pub fn handler(ctx: Context, args: CreateGroupAccountArgs) - ctx.accounts .initialize_metadata(args.name, args.symbol, args.uri)?; - // using a custom group account until token22 implements group account - let group = &mut ctx.accounts.group; - group.max_size = args.max_size; - group.update_authority = ctx.accounts.authority.key(); - group.mint = ctx.accounts.mint.key(); - group.size = 0; + // initialize group account + ctx.accounts.initialize_group(args.max_size)?; // mint to receiver ctx.accounts.mint_to_receiver()?; diff --git a/programs/wen_new_standard/src/instructions/mint/create.rs b/programs/wen_new_standard/src/instructions/mint/create.rs index 982f6b4..59348e5 100644 --- a/programs/wen_new_standard/src/instructions/mint/create.rs +++ b/programs/wen_new_standard/src/instructions/mint/create.rs @@ -40,7 +40,8 @@ pub struct CreateMintAccount<'info> { mint::freeze_authority = manager, extensions::metadata_pointer::authority = authority, extensions::metadata_pointer::metadata_address = mint, - extensions::group_member_pointer::authority = manager, + extensions::group_member_pointer::authority = authority, + extensions::group_member_pointer::member_address = mint, extensions::transfer_hook::authority = authority, extensions::permanent_delegate::delegate = args.permanent_delegate.unwrap_or_else(|| manager.key()), // temporary mint close authority until a better program accounts can be used @@ -101,9 +102,7 @@ impl<'info> CreateMintAccount<'info> { account_or_mint: self.mint.to_account_info(), }; let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts); - // manager needs to be the new authority so that when solana upgrades to support member accounts, the mint can be updated - // this will updated to None once solana supports member accounts - set_authority(cpi_ctx, AuthorityType::MintTokens, Some(self.manager.key()))?; + set_authority(cpi_ctx, AuthorityType::MintTokens, None)?; Ok(()) } @@ -139,7 +138,6 @@ pub fn handler(ctx: Context, args: CreateMintAccountArgs) -> // remove mint authority ctx.accounts.update_mint_authority()?; - // TODO: Once Token Extension program supports Group/Member accounts natively, should lock Mint Authority // transfer minimum rent to mint account update_account_lamports_to_minimum_balance( diff --git a/programs/wen_new_standard/src/instructions/mint/group/add.rs b/programs/wen_new_standard/src/instructions/mint/group/add.rs index c141e77..d2feb5d 100644 --- a/programs/wen_new_standard/src/instructions/mint/group/add.rs +++ b/programs/wen_new_standard/src/instructions/mint/group/add.rs @@ -1,12 +1,11 @@ use anchor_lang::prelude::*; -use anchor_spl::token_interface::{ - group_member_pointer_update, GroupMemberPointerUpdate, Mint, Token2022, -}; - -use crate::{ - get_bump_in_seed_form, Manager, TokenGroup, TokenGroupMember, MANAGER_SEED, - MEMBER_ACCOUNT_SEED, TOKEN22, +use anchor_spl::{ + token_2022::ID as TOKEN_2022_PROGRAM_ID, + token_interface::{ + token_group::{token_member_initialize, TokenMemberInitialize}, + Mint, Token2022, + }, }; #[derive(Accounts)] @@ -15,69 +14,41 @@ pub struct AddGroup<'info> { #[account(mut)] pub payer: Signer<'info>, #[account()] - pub authority: Signer<'info>, + pub group_update_authority: Signer<'info>, + #[account()] + pub member_mint_authority: Signer<'info>, #[account( mut, - constraint = group.update_authority == authority.key(), + mint::token_program = TOKEN_2022_PROGRAM_ID )] - pub group: Account<'info, TokenGroup>, + pub group_mint: Box>, #[account( - init, - seeds = [MEMBER_ACCOUNT_SEED, mint.key().as_ref()], - bump, - payer = payer, - space = 8 + TokenGroupMember::INIT_SPACE - )] - pub member: Account<'info, TokenGroupMember>, - #[account( - mint::token_program = TOKEN22 + mut, + mint::token_program = TOKEN_2022_PROGRAM_ID )] pub mint: Box>, - #[account( - seeds = [MANAGER_SEED], - bump - )] - pub manager: Box>, pub system_program: Program<'info, System>, pub token_program: Program<'info, Token2022>, } impl AddGroup<'_> { - fn update_group_member_pointer_member_address( - &self, - member: Pubkey, - signer_seeds: &[&[&[u8]]], - ) -> Result<()> { - let cpi_accounts = GroupMemberPointerUpdate { + fn initialize_token_member(&self) -> Result<()> { + let cpi_accounts = TokenMemberInitialize { token_program_id: self.token_program.to_account_info(), - mint: self.mint.to_account_info(), - authority: self.manager.to_account_info(), + group: self.group_mint.to_account_info(), + member: self.mint.to_account_info(), + member_mint: self.mint.to_account_info(), + group_update_authority: self.group_update_authority.to_account_info(), + member_mint_authority: self.member_mint_authority.to_account_info(), }; - let cpi_ctx = CpiContext::new_with_signer( - self.token_program.to_account_info(), - cpi_accounts, - signer_seeds, - ); - group_member_pointer_update(cpi_ctx, Some(member))?; + + let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts); + token_member_initialize(cpi_ctx)?; Ok(()) } } pub fn handler(ctx: Context) -> Result<()> { - let group = &mut ctx.accounts.group; - group.increment_size()?; - - let member = &mut ctx.accounts.member; - member.group = group.key(); - member.mint = ctx.accounts.mint.key(); - member.member_number = group.size; - - let member_address = member.key(); - - let signer_seeds = &[MANAGER_SEED, &get_bump_in_seed_form(&ctx.bumps.manager)]; - - ctx.accounts - .update_group_member_pointer_member_address(member_address, &[&signer_seeds[..]])?; - + ctx.accounts.initialize_token_member()?; Ok(()) } diff --git a/tests/wen_new_standard.test.ts b/tests/wen_new_standard.test.ts index 7f3b971..a8c8a17 100644 --- a/tests/wen_new_standard.test.ts +++ b/tests/wen_new_standard.test.ts @@ -605,7 +605,6 @@ describe("wen_new_standard", () => { mint: groupMintPublicKey, authority: groupAuthorityPublicKey, receiver: groupAuthorityPublicKey, - group, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, tokenProgram: TOKEN_2022_PROGRAM_ID, payer, @@ -745,12 +744,11 @@ describe("wen_new_standard", () => { await program.methods .addMintToGroup() .accountsStrict({ - authority: groupAuthorityPublicKey, - group, + groupMint: groupMintPublicKey, + memberMintAuthority: mintAuthPublicKey, + groupUpdateAuthority: groupAuthorityPublicKey, mint: mintPublicKey, payer: mintAuthPublicKey, - manager, - member, systemProgram: SystemProgram.programId, tokenProgram: TOKEN_2022_PROGRAM_ID, }) @@ -761,26 +759,15 @@ describe("wen_new_standard", () => { preflightCommitment: "confirmed", commitment: "confirmed", }); - - memberAccountInfo = await program.account.tokenGroupMember.getAccountInfo( - member - ); - memberAccount = program.coder.accounts.decode( - "tokenGroupMember", - memberAccountInfo.data - ); }); - it("should be an account owned by the program", async () => { - expect(memberAccountInfo.owner).to.eql(program.programId); - }); - it("should point back to the group", async () => { + it.skip("should point back to the group", async () => { expect(memberAccount.group).to.eql(group); }); - it("should have the right member number", async () => { + it.skip("should have the right member number", async () => { expect(memberAccount.memberNumber.toString()).to.eql("1"); }); - it("should have the right member mint", async () => { + it.skip("should have the right member mint", async () => { expect(memberAccount.mint).to.eql(mintPublicKey); }); }); @@ -841,12 +828,11 @@ describe("wen_new_standard", () => { await program.methods .addMintToGroup() .accountsStrict({ - authority: groupAuthorityPublicKey, - group, + groupMint: groupMintPublicKey, + memberMintAuthority: mintAuthPublicKey, + groupUpdateAuthority: groupAuthorityPublicKey, mint: mintPublicKey, payer: mintAuthPublicKey, - manager, - member, systemProgram: SystemProgram.programId, tokenProgram: TOKEN_2022_PROGRAM_ID, })