@@ -5,21 +5,24 @@ use anchor_spl::token::TokenAccount;
5
5
use light_compressed_token_sdk:: {
6
6
instruction:: { get_transfer_instruction_account_metas, TokenAccountsMetaConfig } ,
7
7
token_pool:: get_token_pool_pda,
8
+ InputTokenDataWithContext , PackedMerkleContext ,
8
9
} ;
9
- use light_program_test:: { LightProgramTest , ProgramTestConfig , Rpc } ;
10
+ use light_program_test:: { Indexer , LightProgramTest , ProgramTestConfig , Rpc } ;
10
11
use light_sdk:: instruction:: PackedAccounts ;
11
12
use light_test_utils:: {
12
13
spl:: { create_mint_helper, create_token_account, mint_spl_tokens} ,
13
14
RpcError ,
14
15
} ;
15
16
use solana_sdk:: {
16
- instruction:: { AccountMeta , Instruction } ,
17
+ instruction:: Instruction ,
17
18
pubkey:: Pubkey ,
18
19
signature:: { Keypair , Signature , Signer } ,
19
20
} ;
20
21
22
+ use light_client:: indexer:: CompressedTokenAccount ;
23
+
21
24
#[ tokio:: test]
22
- async fn test_compress_spl_tokens ( ) {
25
+ async fn test ( ) {
23
26
// Initialize the test environment
24
27
let mut rpc = LightProgramTest :: new ( ProgramTestConfig :: new_v2 (
25
28
false ,
@@ -78,12 +81,16 @@ async fn test_compress_spl_tokens() {
78
81
79
82
// Now compress the SPL tokens
80
83
let compress_amount = 500_000 ; // Compress half of the tokens
81
- let recipient = payer. pubkey ( ) ; // Compress to the same owner
84
+ let compression_recipient = payer. pubkey ( ) ; // Compress to the same owner
85
+
86
+ // Declare transfer parameters early
87
+ let transfer_recipient = Keypair :: new ( ) ;
88
+ let transfer_amount = 10 ;
82
89
83
90
compress_spl_tokens (
84
91
& mut rpc,
85
92
& payer,
86
- recipient ,
93
+ compression_recipient ,
87
94
mint_pubkey,
88
95
compress_amount,
89
96
token_account_keypair. pubkey ( ) ,
@@ -93,11 +100,87 @@ async fn test_compress_spl_tokens() {
93
100
94
101
println ! ( "Compressed {} tokens successfully" , compress_amount) ;
95
102
96
- // TODO: Add verification of compressed token accounts
97
- // This would require checking the compressed account state tree
98
- // and verifying the token balance was reduced in the SPL account
103
+ // Get the compressed token account from indexer
104
+ let compressed_accounts = rpc
105
+ . indexer ( )
106
+ . unwrap ( )
107
+ . get_compressed_token_accounts_by_owner ( & payer. pubkey ( ) , None , None )
108
+ . await
109
+ . unwrap ( )
110
+ . value
111
+ . items ;
112
+
113
+ let compressed_account = & compressed_accounts[ 0 ] ;
114
+
115
+ // Assert the compressed token account properties
116
+ assert_eq ! ( compressed_account. token. owner, payer. pubkey( ) ) ;
117
+ assert_eq ! ( compressed_account. token. mint, mint_pubkey) ;
118
+
119
+ // Verify the token amount (should match the compressed amount)
120
+ let amount = compressed_account. token . amount ;
121
+ assert_eq ! ( amount, compress_amount) ;
122
+
123
+ println ! (
124
+ "Verified compressed token account: owner={}, mint={}, amount={}" ,
125
+ payer. pubkey( ) ,
126
+ mint_pubkey,
127
+ amount
128
+ ) ;
129
+ println ! ( "compressed_account {:?}" , compressed_account) ;
130
+ // Now transfer some compressed tokens to a recipient
131
+ transfer_compressed_tokens (
132
+ & mut rpc,
133
+ & payer,
134
+ transfer_recipient. pubkey ( ) ,
135
+ compressed_account,
136
+ )
137
+ . await
138
+ . unwrap ( ) ;
139
+
140
+ println ! (
141
+ "Transferred {} compressed tokens to recipient successfully" ,
142
+ transfer_amount
143
+ ) ;
144
+
145
+ // Verify the transfer by checking both sender and recipient accounts
146
+ let updated_accounts = rpc
147
+ . indexer ( )
148
+ . unwrap ( )
149
+ . get_compressed_token_accounts_by_owner ( & payer. pubkey ( ) , None , None )
150
+ . await
151
+ . unwrap ( )
152
+ . value
153
+ . items ;
154
+
155
+ let recipient_accounts = rpc
156
+ . indexer ( )
157
+ . unwrap ( )
158
+ . get_compressed_token_accounts_by_owner ( & transfer_recipient. pubkey ( ) , None , None )
159
+ . await
160
+ . unwrap ( )
161
+ . value
162
+ . items ;
163
+
164
+ // Sender should have (compress_amount - transfer_amount) remaining
165
+ if !updated_accounts. is_empty ( ) {
166
+ let sender_account = & updated_accounts[ 0 ] ;
167
+ let sender_amount = sender_account. token . amount ;
168
+ assert_eq ! ( sender_amount, compress_amount - transfer_amount) ;
169
+ println ! ( "Verified sender remaining balance: {}" , sender_amount) ;
170
+ }
171
+
172
+ // Recipient should have transfer_amount
173
+ assert ! (
174
+ !recipient_accounts. is_empty( ) ,
175
+ "Recipient should have compressed token account"
176
+ ) ;
177
+ let recipient_account = & recipient_accounts[ 0 ] ;
178
+ assert_eq ! ( recipient_account. token. owner, transfer_recipient. pubkey( ) ) ;
179
+ let recipient_amount = recipient_account. token . amount ;
180
+ assert_eq ! ( recipient_amount, transfer_amount) ;
181
+ println ! ( "Verified recipient balance: {}" , recipient_amount) ;
99
182
100
- println ! ( "Compression test completed successfully!" ) ;
183
+ println ! ( "Compression and transfer test completed successfully!" ) ;
101
184
}
102
185
103
186
async fn compress_spl_tokens (
@@ -147,3 +230,70 @@ async fn compress_spl_tokens(
147
230
rpc. create_and_send_transaction ( & [ instruction] , & payer. pubkey ( ) , & [ payer] )
148
231
. await
149
232
}
233
+
234
+ async fn transfer_compressed_tokens (
235
+ rpc : & mut LightProgramTest ,
236
+ payer : & Keypair ,
237
+ recipient : Pubkey ,
238
+ compressed_account : & CompressedTokenAccount ,
239
+ ) -> Result < Signature , RpcError > {
240
+ let mut remaining_accounts = PackedAccounts :: default ( ) ;
241
+ let config = TokenAccountsMetaConfig :: new ( payer. pubkey ( ) , payer. pubkey ( ) ) ;
242
+ remaining_accounts. add_pre_accounts_signer_mut ( payer. pubkey ( ) ) ;
243
+ let metas = get_transfer_instruction_account_metas ( config) ;
244
+ remaining_accounts. add_pre_accounts_metas ( metas. as_slice ( ) ) ;
245
+
246
+ // Get validity proof from RPC
247
+ let rpc_result = rpc
248
+ . get_validity_proof ( vec ! [ compressed_account. account. hash] , vec ! [ ] , None )
249
+ . await ?
250
+ . value ;
251
+
252
+ let packed_tree_info = rpc_result. pack_tree_infos ( & mut remaining_accounts) ;
253
+ let output_tree_index = packed_tree_info
254
+ . state_trees
255
+ . as_ref ( )
256
+ . unwrap ( )
257
+ . output_tree_index ;
258
+
259
+ // Use the tree info from the validity proof result
260
+ let tree_info = packed_tree_info
261
+ . state_trees
262
+ . as_ref ( )
263
+ . unwrap ( )
264
+ . packed_tree_infos [ 0 ] ;
265
+ println ! ( "Transfer tree_info: {:?}" , tree_info) ;
266
+
267
+ // Create input token data
268
+ let token_data = vec ! [ InputTokenDataWithContext {
269
+ amount: compressed_account. token. amount,
270
+ delegate_index: None ,
271
+ merkle_context: PackedMerkleContext {
272
+ merkle_tree_pubkey_index: tree_info. merkle_tree_pubkey_index,
273
+ nullifier_queue_pubkey_index: tree_info. queue_pubkey_index,
274
+ leaf_index: tree_info. leaf_index,
275
+ proof_by_index: tree_info. prove_by_index,
276
+ } ,
277
+ root_index: tree_info. root_index,
278
+ lamports: None ,
279
+ tlv: None ,
280
+ } ] ;
281
+
282
+ let ( remaining_accounts, _, _) = remaining_accounts. to_account_metas ( ) ;
283
+ println ! ( "remaining_accounts {:?}" , remaining_accounts) ;
284
+ let instruction = Instruction {
285
+ program_id : sdk_token_test:: ID ,
286
+ accounts : [ remaining_accounts] . concat ( ) ,
287
+ data : sdk_token_test:: instruction:: Transfer {
288
+ validity_proof : rpc_result. proof ,
289
+ token_data,
290
+ output_tree_index,
291
+ mint : compressed_account. token . mint ,
292
+ recipient,
293
+ }
294
+ . data ( ) ,
295
+ } ;
296
+
297
+ rpc. create_and_send_transaction ( & [ instruction] , & payer. pubkey ( ) , & [ payer] )
298
+ . await
299
+ }
0 commit comments