@@ -180,7 +180,99 @@ async fn test() {
180
180
assert_eq ! ( recipient_amount, transfer_amount) ;
181
181
println ! ( "Verified recipient balance: {}" , recipient_amount) ;
182
182
183
- println ! ( "Compression and transfer test completed successfully!" ) ;
183
+ // Now decompress some tokens from the recipient back to SPL token account
184
+ let decompress_token_account_keypair = Keypair :: new ( ) ;
185
+ let decompress_amount = 10 ; // Decompress a small amount
186
+ rpc. airdrop_lamports ( & transfer_recipient. pubkey ( ) , 10_000_000_000 )
187
+ . await
188
+ . unwrap ( ) ;
189
+ // Create a new SPL token account for decompression
190
+ create_token_account (
191
+ & mut rpc,
192
+ & mint_pubkey,
193
+ & decompress_token_account_keypair,
194
+ & transfer_recipient,
195
+ )
196
+ . await
197
+ . unwrap ( ) ;
198
+
199
+ println ! (
200
+ "Created decompress token account: {}" ,
201
+ decompress_token_account_keypair. pubkey( )
202
+ ) ;
203
+
204
+ // Get the recipient's compressed token account after transfer
205
+ let recipient_compressed_accounts = rpc
206
+ . indexer ( )
207
+ . unwrap ( )
208
+ . get_compressed_token_accounts_by_owner ( & transfer_recipient. pubkey ( ) , None , None )
209
+ . await
210
+ . unwrap ( )
211
+ . value
212
+ . items ;
213
+
214
+ let recipient_compressed_account = & recipient_compressed_accounts[ 0 ] ;
215
+
216
+ // Decompress tokens from recipient's compressed account to SPL token account
217
+ decompress_compressed_tokens (
218
+ & mut rpc,
219
+ & transfer_recipient,
220
+ recipient_compressed_account,
221
+ decompress_token_account_keypair. pubkey ( ) ,
222
+ decompress_amount,
223
+ )
224
+ . await
225
+ . unwrap ( ) ;
226
+
227
+ println ! (
228
+ "Decompressed {} tokens from recipient successfully" ,
229
+ decompress_amount
230
+ ) ;
231
+
232
+ // Verify the decompression worked
233
+ let decompress_token_account_data = rpc
234
+ . get_account ( decompress_token_account_keypair. pubkey ( ) )
235
+ . await
236
+ . unwrap ( )
237
+ . unwrap ( ) ;
238
+
239
+ let decompress_token_account =
240
+ TokenAccount :: try_deserialize ( & mut decompress_token_account_data. data . as_slice ( ) ) . unwrap ( ) ;
241
+
242
+ // Assert the SPL token account has the decompressed amount
243
+ assert_eq ! ( decompress_token_account. amount, decompress_amount) ;
244
+ assert_eq ! ( decompress_token_account. mint, mint_pubkey) ;
245
+ assert_eq ! ( decompress_token_account. owner, transfer_recipient. pubkey( ) ) ;
246
+
247
+ println ! (
248
+ "Verified SPL token account after decompression: amount={}" ,
249
+ decompress_token_account. amount
250
+ ) ;
251
+
252
+ // Verify the compressed account balance was reduced
253
+ let updated_recipient_accounts = rpc
254
+ . indexer ( )
255
+ . unwrap ( )
256
+ . get_compressed_token_accounts_by_owner ( & transfer_recipient. pubkey ( ) , None , None )
257
+ . await
258
+ . unwrap ( )
259
+ . value
260
+ . items ;
261
+
262
+ if !updated_recipient_accounts. is_empty ( ) {
263
+ let updated_recipient_account = & updated_recipient_accounts[ 0 ] ;
264
+ let remaining_compressed_amount = updated_recipient_account. token . amount ;
265
+ assert_eq ! (
266
+ remaining_compressed_amount,
267
+ transfer_amount - decompress_amount
268
+ ) ;
269
+ println ! (
270
+ "Verified remaining compressed balance: {}" ,
271
+ remaining_compressed_amount
272
+ ) ;
273
+ }
274
+
275
+ println ! ( "Compression, transfer, and decompress test completed successfully!" ) ;
184
276
}
185
277
186
278
async fn compress_spl_tokens (
@@ -193,13 +285,7 @@ async fn compress_spl_tokens(
193
285
) -> Result < Signature , RpcError > {
194
286
let mut remaining_accounts = PackedAccounts :: default ( ) ;
195
287
let token_pool_pda = get_token_pool_pda ( & mint) ;
196
- let config = TokenAccountsMetaConfig :: compress (
197
- payer. pubkey ( ) ,
198
- payer. pubkey ( ) ,
199
- token_pool_pda,
200
- token_account,
201
- false ,
202
- ) ;
288
+ let config = TokenAccountsMetaConfig :: compress ( token_pool_pda, token_account, false ) ;
203
289
remaining_accounts. add_pre_accounts_signer_mut ( payer. pubkey ( ) ) ;
204
290
let metas = get_transfer_instruction_account_metas ( config) ;
205
291
println ! ( "metas {:?}" , metas. to_vec( ) ) ;
@@ -238,7 +324,7 @@ async fn transfer_compressed_tokens(
238
324
compressed_account : & CompressedTokenAccount ,
239
325
) -> Result < Signature , RpcError > {
240
326
let mut remaining_accounts = PackedAccounts :: default ( ) ;
241
- let config = TokenAccountsMetaConfig :: new ( payer . pubkey ( ) , payer . pubkey ( ) ) ;
327
+ let config = TokenAccountsMetaConfig :: new ( ) ;
242
328
remaining_accounts. add_pre_accounts_signer_mut ( payer. pubkey ( ) ) ;
243
329
let metas = get_transfer_instruction_account_metas ( config) ;
244
330
remaining_accounts. add_pre_accounts_metas ( metas. as_slice ( ) ) ;
@@ -297,3 +383,72 @@ async fn transfer_compressed_tokens(
297
383
rpc. create_and_send_transaction ( & [ instruction] , & payer. pubkey ( ) , & [ payer] )
298
384
. await
299
385
}
386
+
387
+ async fn decompress_compressed_tokens (
388
+ rpc : & mut LightProgramTest ,
389
+ payer : & Keypair ,
390
+ compressed_account : & CompressedTokenAccount ,
391
+ decompress_token_account : Pubkey ,
392
+ decompress_amount : u64 ,
393
+ ) -> Result < Signature , RpcError > {
394
+ let mut remaining_accounts = PackedAccounts :: default ( ) ;
395
+ let token_pool_pda = get_token_pool_pda ( & compressed_account. token . mint ) ;
396
+ let config =
397
+ TokenAccountsMetaConfig :: decompress ( token_pool_pda, decompress_token_account, false ) ;
398
+ remaining_accounts. add_pre_accounts_signer_mut ( payer. pubkey ( ) ) ;
399
+ let metas = get_transfer_instruction_account_metas ( config) ;
400
+ remaining_accounts. add_pre_accounts_metas ( metas. as_slice ( ) ) ;
401
+
402
+ // Get validity proof from RPC
403
+ let rpc_result = rpc
404
+ . get_validity_proof ( vec ! [ compressed_account. account. hash] , vec ! [ ] , None )
405
+ . await ?
406
+ . value ;
407
+
408
+ let packed_tree_info = rpc_result. pack_tree_infos ( & mut remaining_accounts) ;
409
+ let output_tree_index = packed_tree_info
410
+ . state_trees
411
+ . as_ref ( )
412
+ . unwrap ( )
413
+ . output_tree_index ;
414
+
415
+ // Use the tree info from the validity proof result
416
+ let tree_info = packed_tree_info
417
+ . state_trees
418
+ . as_ref ( )
419
+ . unwrap ( )
420
+ . packed_tree_infos [ 0 ] ;
421
+
422
+ // Create input token data
423
+ let token_data = vec ! [ InputTokenDataWithContext {
424
+ amount: compressed_account. token. amount,
425
+ delegate_index: None ,
426
+ merkle_context: PackedMerkleContext {
427
+ merkle_tree_pubkey_index: tree_info. merkle_tree_pubkey_index,
428
+ nullifier_queue_pubkey_index: tree_info. queue_pubkey_index,
429
+ leaf_index: tree_info. leaf_index,
430
+ proof_by_index: tree_info. prove_by_index,
431
+ } ,
432
+ root_index: tree_info. root_index,
433
+ lamports: None ,
434
+ tlv: None ,
435
+ } ] ;
436
+
437
+ let ( remaining_accounts, _, _) = remaining_accounts. to_account_metas ( ) ;
438
+ println ! ( " remaining_accounts: {:?}" , remaining_accounts) ;
439
+
440
+ let instruction = Instruction {
441
+ program_id : sdk_token_test:: ID ,
442
+ accounts : [ remaining_accounts] . concat ( ) ,
443
+ data : sdk_token_test:: instruction:: Decompress {
444
+ validity_proof : rpc_result. proof ,
445
+ token_data,
446
+ output_tree_index,
447
+ mint : compressed_account. token . mint ,
448
+ }
449
+ . data ( ) ,
450
+ } ;
451
+
452
+ rpc. create_and_send_transaction ( & [ instruction] , & payer. pubkey ( ) , & [ payer] )
453
+ . await
454
+ }
0 commit comments