Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 834d4a3

Browse files
committed
token 2022: add InitializeGroup instruction from SPL Token Group interface
1 parent 31ee52e commit 834d4a3

File tree

6 files changed

+111
-1
lines changed

6 files changed

+111
-1
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

token/program-2022/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ solana-program = "1.16.16"
2727
solana-zk-token-sdk = "1.16.16"
2828
spl-memo = { version = "4.0.0", path = "../../memo/program", features = [ "no-entrypoint" ] }
2929
spl-token = { version = "4.0", path = "../program", features = ["no-entrypoint"] }
30+
spl-token-group-interface = { version = "0.1.0", path = "../../token-group/interface" }
3031
spl-token-metadata-interface = { version = "0.2.0", path = "../../token-metadata/interface" }
3132
spl-transfer-hook-interface = { version = "0.3.0", path = "../transfer-hook-interface" }
3233
spl-type-length-value = { version = "0.3.0", path = "../../libraries/type-length-value" }

token/program-2022/src/extension/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use {
2929
program_error::ProgramError,
3030
program_pack::{IsInitialized, Pack},
3131
},
32+
spl_token_group_interface::state::TokenGroup,
3233
spl_pod::{
3334
bytemuck::{pod_from_bytes, pod_from_bytes_mut, pod_get_packed_len},
3435
primitives::PodU16,
@@ -68,6 +69,8 @@ pub mod non_transferable;
6869
pub mod permanent_delegate;
6970
/// Utility to reallocate token accounts
7071
pub mod reallocate;
72+
/// Token-group extension
73+
pub mod token_group;
7174
/// Token-metadata extension
7275
pub mod token_metadata;
7376
/// Transfer Fee extension
@@ -904,6 +907,8 @@ pub enum ExtensionType {
904907
ConfidentialTransferFeeAmount,
905908
/// Mint contains a pointer to another account (or the same account) that holds metadata
906909
MetadataPointer,
910+
/// Mint contains token group configurations
911+
TokenGroup,
907912
/// Mint contains token-metadata
908913
TokenMetadata,
909914
/// Test variable-length mint extension
@@ -979,6 +984,7 @@ impl ExtensionType {
979984
pod_get_packed_len::<ConfidentialTransferFeeAmount>()
980985
}
981986
ExtensionType::MetadataPointer => pod_get_packed_len::<MetadataPointer>(),
987+
ExtensionType::TokenGroup => pod_get_packed_len::<TokenGroup>(),
982988
ExtensionType::TokenMetadata => unreachable!(),
983989
#[cfg(test)]
984990
ExtensionType::AccountPaddingTest => pod_get_packed_len::<AccountPaddingTest>(),
@@ -1039,6 +1045,7 @@ impl ExtensionType {
10391045
| ExtensionType::TransferHook
10401046
| ExtensionType::ConfidentialTransferFeeConfig
10411047
| ExtensionType::MetadataPointer
1048+
| ExtensionType::TokenGroup
10421049
| ExtensionType::TokenMetadata => AccountType::Mint,
10431050
ExtensionType::ImmutableOwner
10441051
| ExtensionType::TransferFeeAmount
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use {
2+
crate::extension::{Extension, ExtensionType},
3+
spl_token_group_interface::state::TokenGroup,
4+
};
5+
6+
/// Instruction processor for the TokenGroup extensions
7+
pub mod processor;
8+
9+
impl Extension for TokenGroup {
10+
const TYPE: ExtensionType = ExtensionType::TokenGroup;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! Token-group processor
2+
3+
use {
4+
crate::{
5+
check_program_account,
6+
error::TokenError,
7+
extension::StateWithExtensions,
8+
state::Mint,
9+
},
10+
solana_program::{
11+
account_info::{next_account_info, AccountInfo},
12+
entrypoint::ProgramResult,
13+
msg,
14+
program_error::ProgramError,
15+
program_option::COption,
16+
pubkey::Pubkey,
17+
},
18+
spl_token_group_interface::{
19+
instruction::{
20+
InitializeGroup, TokenGroupInstruction,
21+
},
22+
state::TokenGroup,
23+
},
24+
spl_type_length_value::state::TlvStateMut,
25+
};
26+
27+
/// Processes a [InitializeGroup](enum.TokenGroupInstruction.html) instruction.
28+
pub fn process_initialize_group(
29+
_program_id: &Pubkey,
30+
accounts: &[AccountInfo],
31+
data: InitializeGroup,
32+
) -> ProgramResult {
33+
let account_info_iter = &mut accounts.iter();
34+
35+
let group_info = next_account_info(account_info_iter)?;
36+
let mint_info = next_account_info(account_info_iter)?;
37+
let mint_authority_info = next_account_info(account_info_iter)?;
38+
39+
// check that the mint and group accounts are the same, since the group
40+
// extension should only describe itself
41+
if group_info.key != mint_info.key {
42+
msg!("Group configurations for a mint must be initialized in the mint itself.");
43+
return Err(TokenError::MintMismatch.into());
44+
}
45+
46+
// scope the mint authority check, since the mint is in the same account!
47+
{
48+
// This check isn't really needed since we'll be writing into the account,
49+
// but auditors like it
50+
check_program_account(mint_info.owner)?;
51+
let mint_data = mint_info.try_borrow_data()?;
52+
let mint = StateWithExtensions::<Mint>::unpack(&mint_data)?;
53+
54+
if !mint_authority_info.is_signer {
55+
return Err(ProgramError::MissingRequiredSignature);
56+
}
57+
if mint.base.mint_authority.as_ref() != COption::Some(mint_authority_info.key) {
58+
return Err(TokenError::IncorrectMintAuthority.into());
59+
}
60+
}
61+
62+
// Allocate a TLV entry for the space and write it in
63+
// Assumes that there's enough SOL for the new rent-exemption
64+
let mut buffer = group_info.try_borrow_mut_data()?;
65+
let mut state = TlvStateMut::unpack(&mut buffer)?;
66+
let (group, _) = state.init_value::<TokenGroup>(false)?;
67+
*group = TokenGroup::new(data.update_authority, data.max_size.into());
68+
69+
Ok(())
70+
}
71+
72+
/// Processes an [Instruction](enum.Instruction.html).
73+
pub fn process_instruction(
74+
program_id: &Pubkey,
75+
accounts: &[AccountInfo],
76+
instruction: TokenGroupInstruction,
77+
) -> ProgramResult {
78+
match instruction {
79+
TokenGroupInstruction::InitializeGroup(data) => {
80+
msg!("TokenGroupInstruction: InitializeGroup");
81+
process_initialize_group(program_id, accounts, data)
82+
}
83+
_ => {
84+
Err(ProgramError::InvalidInstructionData)
85+
}
86+
}
87+
}

token/program-2022/src/processor.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use {
1818
mint_close_authority::MintCloseAuthority,
1919
non_transferable::{NonTransferable, NonTransferableAccount},
2020
permanent_delegate::{get_permanent_delegate, PermanentDelegate},
21-
reallocate, token_metadata,
21+
reallocate, token_group, token_metadata,
2222
transfer_fee::{self, TransferFeeAmount, TransferFeeConfig},
2323
transfer_hook::{self, TransferHook, TransferHookAccount},
2424
AccountType, BaseStateWithExtensions, ExtensionType, StateWithExtensions,
@@ -41,6 +41,7 @@ use {
4141
system_instruction, system_program,
4242
sysvar::{rent::Rent, Sysvar},
4343
},
44+
spl_token_group_interface::instruction::TokenGroupInstruction,
4445
spl_token_metadata_interface::instruction::TokenMetadataInstruction,
4546
std::convert::{TryFrom, TryInto},
4647
};
@@ -1664,6 +1665,8 @@ impl Processor {
16641665
}
16651666
} else if let Ok(instruction) = TokenMetadataInstruction::unpack(input) {
16661667
token_metadata::processor::process_instruction(program_id, accounts, instruction)
1668+
} else if let Ok(instruction) = TokenGroupInstruction::unpack(input) {
1669+
token_group::processor::process_instruction(program_id, accounts, instruction)
16671670
} else {
16681671
Err(TokenError::InvalidInstruction.into())
16691672
}

0 commit comments

Comments
 (0)