@@ -62,19 +62,18 @@ pub struct DecompressParams {
62
62
63
63
/// Create a compress instruction
64
64
///
65
- /// This instruction transfers tokens from an SPL token account to compressed token accounts .
65
+ /// This instruction compresses tokens from an SPL token account to N recipients .
66
66
pub fn create_compress_instruction (
67
67
params : CompressParams ,
68
68
) -> Result < Instruction , CompressedTokenError > {
69
69
let token_program = params. token_program_id . unwrap_or ( anchor_spl:: token:: ID ) ;
70
70
71
- // Create output compressed accounts
72
- let output_compressed_accounts = if let Some ( batch_recipients) = params. batch_recipients {
71
+ let output_compressed_accounts = if let Some ( ref batch_recipients) = params. batch_recipients {
73
72
batch_recipients
74
- . into_iter ( )
73
+ . iter ( )
75
74
. map ( |( recipient, amount) | TokenTransferOutputData {
76
- owner : recipient,
77
- amount,
75
+ owner : * recipient,
76
+ amount : * amount ,
78
77
lamports : None ,
79
78
merkle_tree : params. output_state_tree ,
80
79
} )
@@ -87,41 +86,46 @@ pub fn create_compress_instruction(
87
86
merkle_tree: params. output_state_tree,
88
87
} ]
89
88
} ;
90
-
91
- // Calculate total amount
92
89
let total_amount: u64 = output_compressed_accounts. iter ( ) . map ( |x| x. amount ) . sum ( ) ;
93
90
94
- // Create the instruction using the transfer SDK
95
- transfer_sdk:: create_transfer_instruction (
91
+ // TODO: refactor.
92
+ let ix = match transfer_sdk:: create_transfer_instruction (
96
93
& params. payer ,
97
94
& params. owner ,
98
- & [ ] , // empty input merkle context for compression
95
+ & [ ] ,
99
96
& output_compressed_accounts,
100
- & [ ] , // empty root indices for compression
101
- & None , // no proof needed for compression
102
- & [ ] , // empty input token data for compression
103
- & [ ] , // empty input compressed accounts for compression
97
+ & [ ] ,
98
+ & None ,
99
+ & [ ] ,
100
+ & [ ] ,
104
101
params. mint ,
105
- None , // no delegate
106
- true , // is_compress = true
107
- Some ( total_amount) , // compress_or_decompress_amount
108
- Some ( crate :: get_token_pool_pda ( & params. mint ) ) , // token_pool_pda
109
- Some ( params. source ) , // compress_or_decompress_token_account
110
- false , // don't sort outputs
111
- None , // no delegate change account
112
- None , // no lamports change account
113
- token_program == spl_token_2022:: ID , // is_token_22
114
- & [ ] , // no additional token pools
115
- false , // with_transaction_hash = false
116
- )
117
- . map_err ( |e| {
118
- CompressedTokenError :: SerializationError ( format ! ( "Failed to create instruction: {:?}" , e) )
119
- } )
102
+ None ,
103
+ true ,
104
+ Some ( total_amount) ,
105
+ Some ( crate :: get_token_pool_pda ( & params. mint ) ) ,
106
+ Some ( params. source ) ,
107
+ false ,
108
+ None ,
109
+ None ,
110
+ token_program == spl_token_2022:: ID ,
111
+ & [ ] ,
112
+ false ,
113
+ ) {
114
+ Ok ( ix) => ix,
115
+ Err ( e) => {
116
+ return Err ( CompressedTokenError :: SerializationError ( format ! (
117
+ "Failed to create instruction: {:?}" ,
118
+ e
119
+ ) ) )
120
+ }
121
+ } ;
122
+
123
+ Ok ( ix)
120
124
}
121
125
122
126
/// Create a decompress instruction
123
127
///
124
- /// This instruction transfers tokens from compressed token accounts to an SPL token account.
128
+ /// This instruction decompresses compressed tokens to an SPL token account.
125
129
pub fn create_decompress_instruction (
126
130
params : DecompressParams ,
127
131
) -> Result < Instruction , CompressedTokenError > {
@@ -133,7 +137,6 @@ pub fn create_decompress_instruction(
133
137
134
138
let token_program = params. token_program_id . unwrap_or ( anchor_spl:: token:: ID ) ;
135
139
136
- // Extract components from input accounts
137
140
let ( compressed_accounts, token_data, merkle_contexts) : ( Vec < _ > , Vec < _ > , Vec < _ > ) = params
138
141
. input_compressed_token_accounts
139
142
. into_iter ( )
@@ -148,13 +151,9 @@ pub fn create_decompress_instruction(
148
151
} ,
149
152
) ;
150
153
151
- // Get mint from first token data
152
154
let mint = token_data[ 0 ] . mint ;
153
-
154
- // Get owner from first token data
155
155
let owner = token_data[ 0 ] . owner ;
156
156
157
- // Create output state for remaining tokens (if any)
158
157
let input_total: u64 = token_data. iter ( ) . map ( |td| td. amount ) . sum ( ) ;
159
158
let remaining_amount = input_total. saturating_sub ( params. amount ) ;
160
159
@@ -171,7 +170,7 @@ pub fn create_decompress_instruction(
171
170
vec ! [ ]
172
171
} ;
173
172
174
- // Create the instruction using the transfer SDK
173
+ // TODO: refactor.
175
174
transfer_sdk:: create_transfer_instruction (
176
175
& params. payer ,
177
176
& owner,
@@ -182,26 +181,24 @@ pub fn create_decompress_instruction(
182
181
& token_data,
183
182
& compressed_accounts,
184
183
mint,
185
- None , // no delegate
186
- false , // is_compress = false
187
- Some ( params. amount ) , // compress_or_decompress_amount
188
- Some ( crate :: get_token_pool_pda ( & mint) ) , // token_pool_pda
189
- Some ( params. to_address ) , // compress_or_decompress_token_account
190
- false , // don't sort outputs
191
- None , // no delegate change account
192
- None , // no lamports change account
193
- token_program == spl_token_2022:: ID , // is_token_22
194
- & [ ] , // no additional token pools
195
- false , // with_transaction_hash = false
184
+ None ,
185
+ false ,
186
+ Some ( params. amount ) ,
187
+ Some ( crate :: get_token_pool_pda ( & mint) ) ,
188
+ Some ( params. to_address ) ,
189
+ false ,
190
+ None ,
191
+ None ,
192
+ token_program == spl_token_2022:: ID ,
193
+ & [ ] ,
194
+ false ,
196
195
)
197
196
. map_err ( |e| {
198
197
CompressedTokenError :: SerializationError ( format ! ( "Failed to create instruction: {:?}" , e) )
199
198
} )
200
199
}
201
200
202
- /// Helper function to create a simple compress instruction
203
- ///
204
- /// This is a convenience function for the most common compress use case.
201
+ /// Create a compress instruction with a single recipient.
205
202
pub fn compress (
206
203
payer : Pubkey ,
207
204
owner : Pubkey ,
@@ -224,27 +221,32 @@ pub fn compress(
224
221
} )
225
222
}
226
223
227
- /// Helper function to create a batch compress instruction
228
- ///
229
- /// Compress tokens to multiple recipients in a single transaction.
224
+ /// Creates a compress instruction to compress tokens to multiple recipients.
230
225
pub fn batch_compress (
231
226
payer : Pubkey ,
232
227
owner : Pubkey ,
233
228
source_token_account : Pubkey ,
234
229
mint : Pubkey ,
235
- recipients : Vec < ( Pubkey , u64 ) > ,
230
+ recipients : Vec < Pubkey > ,
231
+ amounts : Vec < u64 > ,
236
232
output_state_tree : Pubkey ,
237
233
) -> Result < Instruction , CompressedTokenError > {
234
+ if recipients. len ( ) != amounts. len ( ) {
235
+ return Err ( CompressedTokenError :: InvalidParams (
236
+ "Recipients and amounts must have the same length" . to_string ( ) ,
237
+ ) ) ;
238
+ }
239
+
238
240
create_compress_instruction ( CompressParams {
239
241
payer,
240
242
owner,
241
243
source : source_token_account,
242
- to_address : Pubkey :: default ( ) , // Not used in batch mode
244
+ to_address : Pubkey :: default ( ) ,
243
245
mint,
244
- amount : 0 , // Not used in batch mode
246
+ amount : 0 ,
245
247
output_state_tree,
246
248
token_program_id : None ,
247
- batch_recipients : Some ( recipients) ,
249
+ batch_recipients : Some ( recipients. into_iter ( ) . zip ( amounts ) . collect ( ) ) ,
248
250
} )
249
251
}
250
252
@@ -286,12 +288,21 @@ mod tests {
286
288
let output_state_tree = Pubkey :: new_unique ( ) ;
287
289
288
290
let recipients = vec ! [
289
- ( Pubkey :: new_unique( ) , 500 ) ,
290
- ( Pubkey :: new_unique( ) , 300 ) ,
291
- ( Pubkey :: new_unique( ) , 200 ) ,
291
+ Pubkey :: new_unique( ) ,
292
+ Pubkey :: new_unique( ) ,
293
+ Pubkey :: new_unique( ) ,
292
294
] ;
295
+ let amounts = vec ! [ 500 , 300 , 200 ] ;
293
296
294
- let result = batch_compress ( payer, owner, source, mint, recipients, output_state_tree) ;
297
+ let result = batch_compress (
298
+ payer,
299
+ owner,
300
+ source,
301
+ mint,
302
+ recipients,
303
+ amounts,
304
+ output_state_tree,
305
+ ) ;
295
306
296
307
assert ! ( result. is_ok( ) ) ;
297
308
let instruction = result. unwrap ( ) ;
0 commit comments