Skip to content

Commit dac75f7

Browse files
committed
batch compress metas tested
1 parent 12d731d commit dac75f7

File tree

4 files changed

+219
-231
lines changed

4 files changed

+219
-231
lines changed

sdk-libs/compressed-token-sdk/src/instructions/batch_compress/account_metas.rs

Lines changed: 107 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,67 +4,90 @@ use solana_pubkey::Pubkey;
44
use crate::instructions::CTokenDefaultAccounts;
55

66
/// Account metadata configuration for batch compress instruction
7-
#[derive(Debug, Default, Copy, Clone)]
7+
#[derive(Debug, Copy, Clone)]
88
pub struct BatchCompressMetaConfig {
99
pub fee_payer: Option<Pubkey>,
1010
pub authority: Option<Pubkey>,
11-
pub token_pool_pda: Option<Pubkey>,
12-
pub sender_token_account: Option<Pubkey>,
13-
pub token_program: Option<Pubkey>,
14-
pub merkle_tree: Option<Pubkey>,
11+
pub token_pool_pda: Pubkey,
12+
pub sender_token_account: Pubkey,
13+
pub token_program: Pubkey,
14+
pub merkle_tree: Pubkey,
1515
pub sol_pool_pda: Option<Pubkey>,
1616
}
1717

1818
impl BatchCompressMetaConfig {
19+
/// Create a new BatchCompressMetaConfig for direct invocation
1920
pub fn new(
2021
fee_payer: Pubkey,
2122
authority: Pubkey,
2223
token_pool_pda: Pubkey,
2324
sender_token_account: Pubkey,
2425
token_program: Pubkey,
2526
merkle_tree: Pubkey,
27+
with_lamports: bool,
2628
) -> Self {
29+
let sol_pool_pda = if with_lamports {
30+
unimplemented!("TODO hardcode sol pool pda")
31+
} else {
32+
None
33+
};
2734
Self {
2835
fee_payer: Some(fee_payer),
2936
authority: Some(authority),
30-
token_pool_pda: Some(token_pool_pda),
31-
sender_token_account: Some(sender_token_account),
32-
token_program: Some(token_program),
33-
merkle_tree: Some(merkle_tree),
34-
sol_pool_pda: None,
37+
token_pool_pda,
38+
sender_token_account,
39+
token_program,
40+
merkle_tree,
41+
sol_pool_pda,
3542
}
3643
}
3744

45+
/// Create a new BatchCompressMetaConfig for client-side (CPI) usage
3846
pub fn new_client(
3947
token_pool_pda: Pubkey,
4048
sender_token_account: Pubkey,
4149
token_program: Pubkey,
4250
merkle_tree: Pubkey,
51+
with_lamports: bool,
4352
) -> Self {
53+
let sol_pool_pda = if with_lamports {
54+
unimplemented!("TODO hardcode sol pool pda")
55+
} else {
56+
None
57+
};
4458
Self {
4559
fee_payer: None,
4660
authority: None,
47-
token_pool_pda: Some(token_pool_pda),
48-
sender_token_account: Some(sender_token_account),
49-
token_program: Some(token_program),
50-
merkle_tree: Some(merkle_tree),
51-
sol_pool_pda: None,
61+
token_pool_pda,
62+
sender_token_account,
63+
token_program,
64+
merkle_tree,
65+
sol_pool_pda,
5266
}
5367
}
54-
55-
pub fn with_sol_pool_pda(mut self, sol_pool_pda: Pubkey) -> Self {
56-
self.sol_pool_pda = Some(sol_pool_pda);
57-
self
58-
}
5968
}
6069

6170
/// Get the standard account metas for a batch compress instruction
6271
/// Matches the MintToInstruction account structure used by batch_compress
63-
pub fn get_batch_compress_instruction_account_metas(config: BatchCompressMetaConfig) -> Vec<AccountMeta> {
72+
pub fn get_batch_compress_instruction_account_metas(
73+
config: BatchCompressMetaConfig,
74+
) -> Vec<AccountMeta> {
6475
let default_pubkeys = CTokenDefaultAccounts::default();
65-
76+
77+
// Calculate capacity based on whether fee_payer is provided
78+
// Base accounts: cpi_authority_pda + token_pool_pda + token_program + light_system_program +
79+
// registered_program_pda + noop_program + account_compression_authority +
80+
// account_compression_program + merkle_tree +
81+
// self_program + system_program
82+
let base_capacity = 10;
83+
84+
// Direct invoke accounts: fee_payer + authority + mint_placeholder + sol_pool_pda_or_placeholder
85+
let fee_payer_capacity = if config.fee_payer.is_some() { 4 } else { 0 };
86+
87+
let total_capacity = base_capacity + fee_payer_capacity;
88+
6689
// Start building the account metas to match MintToInstruction structure
67-
let mut metas = Vec::new();
90+
let mut metas = Vec::with_capacity(total_capacity);
6891

6992
// Add fee_payer and authority if provided (for direct invoke)
7093
if let Some(fee_payer) = config.fee_payer {
@@ -78,51 +101,79 @@ pub fn get_batch_compress_instruction_account_metas(config: BatchCompressMetaCon
78101
}
79102

80103
// cpi_authority_pda
81-
metas.push(AccountMeta::new_readonly(default_pubkeys.cpi_authority_pda, false));
82-
83-
// mint: Option<UncheckedAccount> - None for batch_compress, so we skip this account
84-
104+
metas.push(AccountMeta::new_readonly(
105+
default_pubkeys.cpi_authority_pda,
106+
false,
107+
));
108+
109+
// mint: Option<UncheckedAccount> - Always None for batch_compress, so we add a placeholder
110+
if config.fee_payer.is_some() {
111+
metas.push(AccountMeta::new_readonly(
112+
default_pubkeys.compressed_token_program,
113+
false,
114+
));
115+
}
116+
85117
// token_pool_pda (mut)
86-
let token_pool_pda = config.token_pool_pda.expect("Missing token_pool_pda");
87-
metas.push(AccountMeta::new(token_pool_pda, false));
88-
118+
metas.push(AccountMeta::new(config.token_pool_pda, false));
119+
89120
// token_program
90-
let token_program = config.token_program.expect("Missing token_program");
91-
metas.push(AccountMeta::new_readonly(token_program, false));
92-
121+
metas.push(AccountMeta::new_readonly(config.token_program, false));
122+
93123
// light_system_program
94-
metas.push(AccountMeta::new_readonly(default_pubkeys.light_system_program, false));
95-
124+
metas.push(AccountMeta::new_readonly(
125+
default_pubkeys.light_system_program,
126+
false,
127+
));
128+
96129
// registered_program_pda
97-
metas.push(AccountMeta::new_readonly(default_pubkeys.registered_program_pda, false));
98-
130+
metas.push(AccountMeta::new_readonly(
131+
default_pubkeys.registered_program_pda,
132+
false,
133+
));
134+
99135
// noop_program
100-
metas.push(AccountMeta::new_readonly(default_pubkeys.noop_program, false));
101-
102-
// account_compression_authority
103-
metas.push(AccountMeta::new_readonly(default_pubkeys.account_compression_authority, false));
104-
136+
metas.push(AccountMeta::new_readonly(
137+
default_pubkeys.noop_program,
138+
false,
139+
));
140+
141+
// account_compression_authority
142+
metas.push(AccountMeta::new_readonly(
143+
default_pubkeys.account_compression_authority,
144+
false,
145+
));
146+
105147
// account_compression_program
106-
metas.push(AccountMeta::new_readonly(default_pubkeys.account_compression_program, false));
107-
148+
metas.push(AccountMeta::new_readonly(
149+
default_pubkeys.account_compression_program,
150+
false,
151+
));
152+
108153
// merkle_tree (mut)
109-
let merkle_tree = config.merkle_tree.expect("Missing merkle_tree");
110-
metas.push(AccountMeta::new(merkle_tree, false));
111-
154+
metas.push(AccountMeta::new(config.merkle_tree, false));
155+
112156
// self_program (compressed token program)
113-
metas.push(AccountMeta::new_readonly(default_pubkeys.self_program, false));
114-
157+
metas.push(AccountMeta::new_readonly(
158+
default_pubkeys.self_program,
159+
false,
160+
));
161+
115162
// system_program
116-
metas.push(AccountMeta::new_readonly(default_pubkeys.system_program, false));
117-
118-
// sol_pool_pda (optional, mut)
163+
metas.push(AccountMeta::new_readonly(
164+
default_pubkeys.system_program,
165+
false,
166+
));
167+
168+
// sol_pool_pda (optional, mut) - add placeholder if None but fee_payer is present
119169
if let Some(sol_pool_pda) = config.sol_pool_pda {
120170
metas.push(AccountMeta::new(sol_pool_pda, false));
171+
} else if config.fee_payer.is_some() {
172+
metas.push(AccountMeta::new_readonly(
173+
default_pubkeys.compressed_token_program,
174+
false,
175+
));
121176
}
122-
123-
// Remaining accounts: sender_token_account (first remaining account for batch_compress)
124-
let sender_token_account = config.sender_token_account.expect("Missing sender_token_account");
125-
metas.push(AccountMeta::new(sender_token_account, false));
126177

127178
metas
128179
}
Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,73 @@
1-
use crate::{
2-
account::CTokenAccount,
3-
error::{Result, TokenSdkError},
4-
instructions::transfer::account_metas::{
5-
get_transfer_instruction_account_metas, TokenAccountsMetaConfig,
6-
},
7-
AnchorSerialize,
8-
};
9-
use light_compressed_token_types::{BatchCompressInstructionData, BATCH_COMPRESS};
1+
use borsh::BorshSerialize;
102
use solana_instruction::Instruction;
113
use solana_pubkey::Pubkey;
12-
#[derive()]
4+
5+
use crate::error::{Result, TokenSdkError};
6+
use crate::instructions::batch_compress::account_metas::{BatchCompressMetaConfig, get_batch_compress_instruction_account_metas};
7+
use light_compressed_token_types::instruction::batch_compress::BatchCompressInstructionData;
8+
9+
#[derive(Debug, Clone)]
1310
pub struct Recipient {
1411
pub pubkey: Pubkey,
1512
pub amount: u64,
1613
}
1714

18-
pub struct CompressInputs {
15+
#[derive(Debug, Clone)]
16+
pub struct BatchCompressInputs {
1917
pub fee_payer: Pubkey,
2018
pub authority: Pubkey,
21-
pub mint: Pubkey,
22-
pub recipient: Pubkey,
19+
pub token_pool_pda: Pubkey,
2320
pub sender_token_account: Pubkey,
21+
pub token_program: Pubkey,
22+
pub merkle_tree: Pubkey,
2423
pub recipients: Vec<Recipient>,
25-
pub output_queue_pubkey: Pubkey,
26-
pub token_pool_pda: Pubkey,
27-
pub spl_token_program: Pubkey,
2824
pub lamports: Option<u64>,
25+
pub token_pool_index: u8,
2926
pub token_pool_bump: u8,
27+
pub sol_pool_pda: Option<Pubkey>,
3028
}
3129

32-
pub fn batch_compress(inputs: CompressInputs) -> Result<Instruction> {
30+
pub fn create_batch_compress_instruction(inputs: BatchCompressInputs) -> Result<Instruction> {
3331
let mut pubkeys = Vec::with_capacity(inputs.recipients.len());
3432
let mut amounts = Vec::with_capacity(inputs.recipients.len());
33+
3534
inputs.recipients.iter().for_each(|recipient| {
3635
pubkeys.push(recipient.pubkey.to_bytes());
3736
amounts.push(recipient.amount);
3837
});
38+
3939
// Create instruction data
4040
let instruction_data = BatchCompressInstructionData {
4141
pubkeys,
4242
amounts: Some(amounts),
4343
amount: None,
44-
index: 0,
44+
index: inputs.token_pool_index,
4545
lamports: inputs.lamports,
4646
bump: inputs.token_pool_bump,
4747
};
4848

49-
// TODO: calculate exact len.
50-
let serialized = instruction_data
49+
// Serialize instruction data
50+
let serialized_data = instruction_data
5151
.try_to_vec()
5252
.map_err(|_| TokenSdkError::SerializationError)?;
5353

54-
// Serialize instruction data
55-
let mut data = Vec::with_capacity(8 + 4 + serialized.len()); // rough estimate
56-
data.extend_from_slice(&BATCH_COMPRESS);
57-
data.extend(u32::try_from(serialized.len()).unwrap().to_le_bytes());
58-
data.extend(serialized);
59-
solana_msg::msg!("meta config1 {:?}", meta_config);
60-
let mut account_metas = get_transfer_instruction_account_metas(meta_config);
54+
// Create account meta config for batch_compress (uses MintToInstruction accounts)
55+
let meta_config = BatchCompressMetaConfig {
56+
fee_payer: Some(inputs.fee_payer),
57+
authority: Some(inputs.authority),
58+
token_pool_pda: inputs.token_pool_pda,
59+
sender_token_account: inputs.sender_token_account,
60+
token_program: inputs.token_program,
61+
merkle_tree: inputs.merkle_tree,
62+
sol_pool_pda: inputs.sol_pool_pda,
63+
};
64+
65+
// Get account metas that match MintToInstruction structure
66+
let account_metas = get_batch_compress_instruction_account_metas(meta_config);
6167

6268
Ok(Instruction {
63-
program_id: Pubkey::from(COMPRESSED_TOKEN_PROGRAM_ID),
69+
program_id: Pubkey::new_from_array(light_compressed_token_types::PROGRAM_ID),
6470
accounts: account_metas,
65-
data,
71+
data: serialized_data,
6672
})
6773
}

sdk-libs/compressed-token-sdk/src/instructions/batch_compress/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ pub mod account_metas;
22
pub mod instruction;
33

44
pub use account_metas::{BatchCompressMetaConfig, get_batch_compress_instruction_account_metas};
5-
pub use instruction::{BatchCompressConfig, create_batch_compress_instruction};
5+
pub use instruction::{Recipient, BatchCompressInputs, create_batch_compress_instruction};

0 commit comments

Comments
 (0)