Skip to content

Commit 6cfa334

Browse files
authored
Merge pull request #26 from burhankhaja/token-group
token-2022: Add token group extension
2 parents bde8488 + 1f6804f commit 6cfa334

File tree

7 files changed

+401
-0
lines changed

7 files changed

+401
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use {
2+
crate::instructions::extensions::token_group::state::{
3+
offset_token_group_initialize_group as OFFSET, InstructionDiscriminatorTokenGroup,
4+
},
5+
pinocchio::{
6+
account_info::AccountInfo,
7+
cpi::invoke_signed,
8+
instruction::{AccountMeta, Instruction, Signer},
9+
pubkey::Pubkey,
10+
ProgramResult,
11+
},
12+
};
13+
14+
/// Initialize a new `Group`
15+
///
16+
/// Assumes one has already initialized a mint for the group.
17+
///
18+
/// Accounts expected by this instruction:
19+
///
20+
/// 0. `[writable]` Group
21+
/// 1. `[]` Mint
22+
/// 2. `[signer]` Mint authority
23+
pub struct InitializeGroup<'a, 'b> {
24+
/// Group Account
25+
pub group: &'a AccountInfo,
26+
/// Mint Account
27+
pub mint: &'a AccountInfo,
28+
/// Mint authority
29+
pub mint_authority: &'a AccountInfo,
30+
/// Update authority for the group
31+
pub update_authority: Option<&'b Pubkey>,
32+
/// The maximum number of group members
33+
pub max_size: u64,
34+
/// Token Group Program
35+
pub program_id: &'b Pubkey,
36+
}
37+
38+
impl InitializeGroup<'_, '_> {
39+
#[inline(always)]
40+
pub fn invoke(&self) -> ProgramResult {
41+
self.invoke_signed(&[])
42+
}
43+
44+
#[inline(always)]
45+
pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
46+
let account_metas = [
47+
AccountMeta::writable(self.group.key()),
48+
AccountMeta::readonly(self.mint.key()),
49+
AccountMeta::readonly_signer(self.mint_authority.key()),
50+
];
51+
52+
let mut buffer = [0u8; OFFSET::END as usize];
53+
let data =
54+
initialize_group_instruction_data(&mut buffer, self.update_authority, self.max_size);
55+
56+
let instruction = Instruction {
57+
program_id: self.program_id,
58+
accounts: &account_metas,
59+
data,
60+
};
61+
62+
invoke_signed(
63+
&instruction,
64+
&[self.group, self.mint, self.mint_authority],
65+
signers,
66+
)
67+
}
68+
}
69+
70+
#[inline(always)]
71+
fn initialize_group_instruction_data<'a>(
72+
buffer: &'a mut [u8],
73+
update_authority: Option<&Pubkey>,
74+
max_size: u64,
75+
) -> &'a [u8] {
76+
let mut offset = OFFSET::START as usize;
77+
78+
// Set discriminators
79+
buffer[..offset].copy_from_slice(
80+
&(InstructionDiscriminatorTokenGroup::InitializeGroup as u64).to_le_bytes(),
81+
);
82+
83+
// Set update_authority
84+
if let Some(x) = update_authority {
85+
buffer[offset..offset + OFFSET::UPDATE_AUTHORITY as usize].copy_from_slice(x);
86+
}
87+
offset += OFFSET::UPDATE_AUTHORITY as usize;
88+
89+
// Set max_size
90+
buffer[offset..offset + OFFSET::MAX_SIZE as usize].copy_from_slice(&max_size.to_le_bytes());
91+
92+
buffer
93+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use {
2+
crate::instructions::extensions::token_group::state::{
3+
offset_token_group_initialize_member as OFFSET, InstructionDiscriminatorTokenGroup,
4+
},
5+
pinocchio::{
6+
account_info::AccountInfo,
7+
cpi::invoke_signed,
8+
instruction::{AccountMeta, Instruction, Signer},
9+
pubkey::Pubkey,
10+
ProgramResult,
11+
},
12+
};
13+
14+
/// Initialize a new `Member` of a `Group`
15+
///
16+
/// Assumes the `Group` has already been initialized,
17+
/// as well as the mint for the member.
18+
///
19+
/// Accounts expected by this instruction:
20+
///
21+
/// 0. `[writable]` Member
22+
/// 1. `[]` Member mint
23+
/// 2. `[signer]` Member mint authority
24+
/// 3. `[writable]` Group
25+
/// 4. `[signer]` Group update authority
26+
pub struct InitializeMember<'a, 'b> {
27+
/// Member Account
28+
pub member: &'a AccountInfo,
29+
/// Member mint
30+
pub member_mint: &'a AccountInfo,
31+
/// Member mint authority
32+
pub member_mint_authority: &'a AccountInfo,
33+
/// Group Account
34+
pub group: &'a AccountInfo,
35+
/// Group update authority
36+
pub group_update_authority: &'a AccountInfo,
37+
/// Token Group Program
38+
pub program_id: &'b Pubkey,
39+
}
40+
41+
impl InitializeMember<'_, '_> {
42+
#[inline(always)]
43+
pub fn invoke(&self) -> ProgramResult {
44+
self.invoke_signed(&[])
45+
}
46+
47+
#[inline(always)]
48+
pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
49+
let account_metas = [
50+
AccountMeta::writable(self.member.key()),
51+
AccountMeta::readonly(self.member_mint.key()),
52+
AccountMeta::readonly_signer(self.member_mint_authority.key()),
53+
AccountMeta::writable(self.group.key()),
54+
AccountMeta::readonly_signer(self.group_update_authority.key()),
55+
];
56+
57+
let mut buffer = [0u8; OFFSET::END as usize];
58+
let data = initialize_member_instruction_data(&mut buffer);
59+
60+
let instruction = Instruction {
61+
program_id: self.program_id,
62+
accounts: &account_metas,
63+
data,
64+
};
65+
66+
invoke_signed(
67+
&instruction,
68+
&[
69+
self.member,
70+
self.member_mint,
71+
self.member_mint_authority,
72+
self.group,
73+
self.group_update_authority,
74+
],
75+
signers,
76+
)
77+
}
78+
}
79+
80+
#[inline(always)]
81+
fn initialize_member_instruction_data<'a>(buffer: &'a mut [u8]) -> &'a [u8] {
82+
let offset = OFFSET::START as usize;
83+
84+
// Set discriminators
85+
buffer[..offset].copy_from_slice(
86+
&(InstructionDiscriminatorTokenGroup::InitializeMember as u64).to_le_bytes(),
87+
);
88+
89+
buffer
90+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
mod initialize_group;
2+
mod initialize_member;
3+
mod update_group_authority;
4+
mod update_max_size;
5+
6+
pub use initialize_group::*;
7+
pub use initialize_member::*;
8+
pub use update_group_authority::*;
9+
pub use update_max_size::*;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use {
2+
crate::instructions::extensions::token_group::state::{
3+
offset_token_group_update_authority as OFFSET, InstructionDiscriminatorTokenGroup,
4+
},
5+
pinocchio::{
6+
account_info::AccountInfo,
7+
cpi::invoke_signed,
8+
instruction::{AccountMeta, Instruction, Signer},
9+
pubkey::Pubkey,
10+
ProgramResult,
11+
},
12+
};
13+
14+
/// Update the authority of a `Group`
15+
///
16+
/// Accounts expected by this instruction:
17+
///
18+
/// 0. `[writable]` Group
19+
/// 1. `[signer]` Current update authority
20+
pub struct UpdateGroupAuthority<'a, 'b> {
21+
/// Group Account
22+
pub group: &'a AccountInfo,
23+
/// Current update authority
24+
pub current_authority: &'a AccountInfo,
25+
/// New authority for the group, or None to unset
26+
pub new_authority: Option<&'b Pubkey>,
27+
/// Token Group Program
28+
pub program_id: &'b Pubkey,
29+
}
30+
31+
impl UpdateGroupAuthority<'_, '_> {
32+
#[inline(always)]
33+
pub fn invoke(&self) -> ProgramResult {
34+
self.invoke_signed(&[])
35+
}
36+
37+
#[inline(always)]
38+
pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
39+
let account_metas = [
40+
AccountMeta::writable(self.group.key()),
41+
AccountMeta::readonly_signer(self.current_authority.key()),
42+
];
43+
44+
let mut buffer = [0u8; OFFSET::END as usize];
45+
let data = update_group_authority_instruction_data(&mut buffer, self.new_authority);
46+
47+
let instruction = Instruction {
48+
program_id: self.program_id,
49+
accounts: &account_metas,
50+
data,
51+
};
52+
53+
invoke_signed(&instruction, &[self.group, self.current_authority], signers)
54+
}
55+
}
56+
57+
#[inline(always)]
58+
fn update_group_authority_instruction_data<'a>(
59+
buffer: &'a mut [u8],
60+
new_authority: Option<&Pubkey>,
61+
) -> &'a [u8] {
62+
let offset = OFFSET::START as usize;
63+
64+
// Set discriminators
65+
buffer[..offset].copy_from_slice(
66+
&(InstructionDiscriminatorTokenGroup::UpdateGroupAuthority as u64).to_le_bytes(),
67+
);
68+
69+
// Set new_authority (optional)
70+
if let Some(authority) = new_authority {
71+
buffer[offset..offset + OFFSET::NEW_AUTHORITY as usize].copy_from_slice(authority.as_ref());
72+
}
73+
74+
buffer
75+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use {
2+
crate::instructions::extensions::token_group::state::{
3+
offset_token_group_update_max_size as OFFSET, InstructionDiscriminatorTokenGroup,
4+
},
5+
pinocchio::{
6+
account_info::AccountInfo,
7+
cpi::invoke_signed,
8+
instruction::{AccountMeta, Instruction, Signer},
9+
pubkey::Pubkey,
10+
ProgramResult,
11+
},
12+
};
13+
14+
/// Update the max size of a `Group`
15+
///
16+
/// Accounts expected by this instruction:
17+
///
18+
/// 0. `[writable]` Group
19+
/// 1. `[signer]` Update authority
20+
pub struct UpdateGroupMaxSize<'a, 'b> {
21+
/// Group Account
22+
pub group: &'a AccountInfo,
23+
// /// Update authority
24+
pub update_authority: &'a AccountInfo,
25+
/// New max size for the group
26+
pub max_size: u64,
27+
/// Token Group Program
28+
pub program_id: &'b Pubkey,
29+
}
30+
31+
impl UpdateGroupMaxSize<'_, '_> {
32+
#[inline(always)]
33+
pub fn invoke(&self) -> ProgramResult {
34+
self.invoke_signed(&[])
35+
}
36+
37+
#[inline(always)]
38+
pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
39+
let account_metas = [
40+
AccountMeta::writable(self.group.key()),
41+
AccountMeta::readonly_signer(self.update_authority.key()),
42+
];
43+
44+
let mut buffer = [0u8; OFFSET::END as usize];
45+
let data = update_group_max_size_instruction_data(&mut buffer, self.max_size);
46+
47+
let instruction = Instruction {
48+
program_id: self.program_id,
49+
accounts: &account_metas,
50+
data,
51+
};
52+
53+
invoke_signed(&instruction, &[self.group, self.update_authority], signers)
54+
}
55+
}
56+
57+
#[inline(always)]
58+
fn update_group_max_size_instruction_data<'a>(buffer: &'a mut [u8], max_size: u64) -> &'a [u8] {
59+
let offset = OFFSET::START as usize;
60+
61+
// Set discriminators
62+
buffer[..offset].copy_from_slice(
63+
&(InstructionDiscriminatorTokenGroup::UpdateGroupMaxSize as u64).to_le_bytes(),
64+
);
65+
66+
// Set max_size
67+
buffer[offset..offset + OFFSET::MAX_SIZE as usize].copy_from_slice(&max_size.to_le_bytes());
68+
69+
buffer
70+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod instructions;
2+
pub mod state;
3+
4+
pub use instructions::*;
5+
pub use state::*;

0 commit comments

Comments
 (0)