@@ -152,4 +152,269 @@ pub mod tests {
152
152
153
153
println ! ( "Balance is {:?}" , balance) ;
154
154
}
155
+
156
+ #[ cfg( test) ]
157
+ mod tests {
158
+ use super :: * ;
159
+ use alloy:: primitives:: { Address , U256 } ;
160
+ use executor_primitives:: { EthereumToken , SolanaToken } ;
161
+ use solana_account_decoder_client_types:: { ParsedAccount , UiAccount , UiAccountData } ;
162
+ use solana_client:: rpc_request:: TokenAccountsFilter ;
163
+ use solana_client:: rpc_response:: RpcKeyedAccount ;
164
+ use solana_sdk:: pubkey:: Pubkey ;
165
+
166
+ #[ tokio:: test]
167
+ async fn test_query_solana_native_success ( ) {
168
+ let mut mock_client = solana:: mocks:: MockSolanaRpcClient :: new ( ) ;
169
+ let pubkey = Pubkey :: new_unique ( ) ;
170
+ let expected_balance = 1000000000u64 ; // 1 SOL in lamports
171
+
172
+ mock_client
173
+ . expect_get_balance ( )
174
+ . with ( mockall:: predicate:: eq ( pubkey) )
175
+ . times ( 1 )
176
+ . returning ( move |_| Ok ( expected_balance) ) ;
177
+
178
+ let result = query_solana ( & mock_client, & pubkey, & SolanaToken :: Native ) . await ;
179
+
180
+ assert_eq ! ( result, Ok ( expected_balance) ) ;
181
+ }
182
+
183
+ #[ tokio:: test]
184
+ async fn test_query_solana_native_error ( ) {
185
+ let mut mock_client = solana:: mocks:: MockSolanaRpcClient :: new ( ) ;
186
+ let pubkey = Pubkey :: new_unique ( ) ;
187
+
188
+ mock_client
189
+ . expect_get_balance ( )
190
+ . with ( mockall:: predicate:: eq ( pubkey) )
191
+ . times ( 1 )
192
+ . returning ( |_| Err ( ( ) ) ) ;
193
+
194
+ let result = query_solana ( & mock_client, & pubkey, & SolanaToken :: Native ) . await ;
195
+
196
+ assert_eq ! ( result, Err ( ( ) ) ) ;
197
+ }
198
+
199
+ #[ tokio:: test]
200
+ async fn test_query_solana_spl_success_json_format ( ) {
201
+ let mut mock_client = solana:: mocks:: MockSolanaRpcClient :: new ( ) ;
202
+ let pubkey = Pubkey :: new_unique ( ) ;
203
+ let mint_pubkey = Pubkey :: new_unique ( ) ;
204
+ let token = SolanaToken :: SPL ( mint_pubkey. to_bytes ( ) . into ( ) ) ;
205
+
206
+ // Create JSON response structure
207
+ let parsed_json = serde_json:: json!( {
208
+ "info" : {
209
+ "tokenAmount" : {
210
+ "amount" : "500"
211
+ }
212
+ }
213
+ } ) ;
214
+
215
+ let parsed_account =
216
+ ParsedAccount { parsed : parsed_json, program : "spl-token" . to_string ( ) , space : 165 } ;
217
+
218
+ let account_data = UiAccountData :: Json ( parsed_account) ;
219
+
220
+ let rpc_account = RpcKeyedAccount {
221
+ pubkey : Pubkey :: new_unique ( ) . to_string ( ) ,
222
+ account : UiAccount {
223
+ lamports : 2039280 ,
224
+ data : account_data,
225
+ owner : "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" . to_string ( ) ,
226
+ executable : false ,
227
+ rent_epoch : 361 ,
228
+ space : Some ( 165 ) ,
229
+ } ,
230
+ } ;
231
+
232
+ mock_client
233
+ . expect_get_token_accounts_by_owner ( )
234
+ . with (
235
+ mockall:: predicate:: eq ( pubkey) ,
236
+ mockall:: predicate:: function ( move |filter : & TokenAccountsFilter | {
237
+ matches ! ( filter, TokenAccountsFilter :: Mint ( mint) if * mint == mint_pubkey)
238
+ } ) ,
239
+ )
240
+ . times ( 1 )
241
+ . returning ( move |_, _| Ok ( vec ! [ rpc_account. clone( ) ] ) ) ;
242
+
243
+ let result = query_solana ( & mock_client, & pubkey, & token) . await ;
244
+
245
+ assert_eq ! ( result, Ok ( 500 ) ) ;
246
+ }
247
+
248
+ #[ tokio:: test]
249
+ async fn test_query_solana_spl_multiple_accounts ( ) {
250
+ let mut mock_client = solana:: mocks:: MockSolanaRpcClient :: new ( ) ;
251
+ let pubkey = Pubkey :: new_unique ( ) ;
252
+ let mint_pubkey = Pubkey :: new_unique ( ) ;
253
+ let token = SolanaToken :: SPL ( mint_pubkey. to_bytes ( ) . into ( ) ) ;
254
+
255
+ // First account with 300 tokens
256
+ let parsed_json1 = serde_json:: json!( {
257
+ "info" : {
258
+ "tokenAmount" : {
259
+ "amount" : "300"
260
+ }
261
+ }
262
+ } ) ;
263
+
264
+ let parsed_account1 = ParsedAccount {
265
+ parsed : parsed_json1,
266
+ program : "spl-token" . to_string ( ) ,
267
+ space : 165 ,
268
+ } ;
269
+
270
+ let account_data1 = UiAccountData :: Json ( parsed_account1) ;
271
+
272
+ // Second account with 700 tokens
273
+ let parsed_json2 = serde_json:: json!( {
274
+ "info" : {
275
+ "tokenAmount" : {
276
+ "amount" : "700"
277
+ }
278
+ }
279
+ } ) ;
280
+
281
+ let parsed_account2 = ParsedAccount {
282
+ parsed : parsed_json2,
283
+ program : "spl-token" . to_string ( ) ,
284
+ space : 165 ,
285
+ } ;
286
+
287
+ let account_data2 = UiAccountData :: Json ( parsed_account2) ;
288
+
289
+ let accounts = vec ! [
290
+ RpcKeyedAccount {
291
+ pubkey: Pubkey :: new_unique( ) . to_string( ) ,
292
+ account: UiAccount {
293
+ lamports: 2039280 ,
294
+ data: account_data1,
295
+ owner: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" . to_string( ) ,
296
+ executable: false ,
297
+ rent_epoch: 361 ,
298
+ space: Some ( 165 ) ,
299
+ } ,
300
+ } ,
301
+ RpcKeyedAccount {
302
+ pubkey: Pubkey :: new_unique( ) . to_string( ) ,
303
+ account: UiAccount {
304
+ lamports: 2039280 ,
305
+ data: account_data2,
306
+ owner: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" . to_string( ) ,
307
+ executable: false ,
308
+ rent_epoch: 361 ,
309
+ space: Some ( 165 ) ,
310
+ } ,
311
+ } ,
312
+ ] ;
313
+
314
+ mock_client
315
+ . expect_get_token_accounts_by_owner ( )
316
+ . with (
317
+ mockall:: predicate:: eq ( pubkey) ,
318
+ mockall:: predicate:: function ( move |filter : & TokenAccountsFilter | {
319
+ matches ! ( filter, TokenAccountsFilter :: Mint ( mint) if * mint == mint_pubkey)
320
+ } ) ,
321
+ )
322
+ . times ( 1 )
323
+ . returning ( move |_, _| Ok ( accounts. clone ( ) ) ) ;
324
+
325
+ let result = query_solana ( & mock_client, & pubkey, & token) . await ;
326
+
327
+ assert_eq ! ( result, Ok ( 1000 ) ) ; // 300 + 700
328
+ }
329
+
330
+ #[ tokio:: test]
331
+ async fn test_query_solana_spl_error ( ) {
332
+ let mut mock_client = solana:: mocks:: MockSolanaRpcClient :: new ( ) ;
333
+ let pubkey = Pubkey :: new_unique ( ) ;
334
+ let mint_pubkey = Pubkey :: new_unique ( ) ;
335
+ let token = SolanaToken :: SPL ( mint_pubkey. to_bytes ( ) . into ( ) ) ;
336
+
337
+ mock_client
338
+ . expect_get_token_accounts_by_owner ( )
339
+ . with (
340
+ mockall:: predicate:: eq ( pubkey) ,
341
+ mockall:: predicate:: function ( move |filter : & TokenAccountsFilter | {
342
+ matches ! ( filter, TokenAccountsFilter :: Mint ( mint) if * mint == mint_pubkey)
343
+ } ) ,
344
+ )
345
+ . times ( 1 )
346
+ . returning ( |_, _| Err ( ( ) ) ) ;
347
+
348
+ let result = query_solana ( & mock_client, & pubkey, & token) . await ;
349
+
350
+ assert_eq ! ( result, Err ( ( ) ) ) ;
351
+ }
352
+
353
+ #[ tokio:: test]
354
+ async fn test_query_ethereum_native_success ( ) {
355
+ let mut mock_provider = ethereum_rpc:: mocks:: MockRpcProvider :: new ( ) ;
356
+ let address = Address :: from_str ( "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ) . unwrap ( ) ;
357
+ let expected_balance = U256 :: from ( 1000000000000000000u64 ) ; // 1 ETH in wei
358
+
359
+ mock_provider
360
+ . expect_get_balance ( )
361
+ . with ( mockall:: predicate:: eq ( address) )
362
+ . times ( 1 )
363
+ . returning ( move |_| Ok ( expected_balance) ) ;
364
+
365
+ let result = query_ethereum ( & mock_provider, address, & EthereumToken :: Native ) . await ;
366
+
367
+ assert_eq ! ( result, Ok ( expected_balance) ) ;
368
+ }
369
+
370
+ #[ tokio:: test]
371
+ async fn test_query_ethereum_native_error ( ) {
372
+ let mut mock_provider = ethereum_rpc:: mocks:: MockRpcProvider :: new ( ) ;
373
+ let address = Address :: from_str ( "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ) . unwrap ( ) ;
374
+
375
+ mock_provider
376
+ . expect_get_balance ( )
377
+ . with ( mockall:: predicate:: eq ( address) )
378
+ . times ( 1 )
379
+ . returning ( |_| Err ( ( ) ) ) ;
380
+
381
+ let result = query_ethereum ( & mock_provider, address, & EthereumToken :: Native ) . await ;
382
+
383
+ assert_eq ! ( result, Err ( ( ) ) ) ;
384
+ }
385
+
386
+ #[ tokio:: test]
387
+ async fn test_query_ethereum_erc20_success ( ) {
388
+ let mut mock_provider = ethereum_rpc:: mocks:: MockRpcProvider :: new ( ) ;
389
+ let account = Address :: from_str ( "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ) . unwrap ( ) ;
390
+ let token_address = hex ! ( "5FC8d32690cc91D4c39d9d3abcBD16989F875707" ) ;
391
+ let token = EthereumToken :: ERC20 ( token_address. try_into ( ) . unwrap ( ) ) ;
392
+ let expected_balance = U256 :: from ( 500000000u64 ) ; // 500 tokens (with 6 decimals)
393
+
394
+ // Mock the call method to return the balance
395
+ let balance_bytes = expected_balance. to_be_bytes_vec ( ) ;
396
+ mock_provider
397
+ . expect_call ( )
398
+ . times ( 1 )
399
+ . returning ( move |_| Ok ( balance_bytes. clone ( ) ) ) ;
400
+
401
+ let result = query_ethereum ( & mock_provider, account, & token) . await ;
402
+
403
+ assert_eq ! ( result, Ok ( expected_balance) ) ;
404
+ }
405
+
406
+ #[ tokio:: test]
407
+ async fn test_query_ethereum_erc20_error ( ) {
408
+ let mut mock_provider = ethereum_rpc:: mocks:: MockRpcProvider :: new ( ) ;
409
+ let account = Address :: from_str ( "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" ) . unwrap ( ) ;
410
+ let token_address = hex ! ( "5FC8d32690cc91D4c39d9d3abcBD16989F875707" ) ;
411
+ let token = EthereumToken :: ERC20 ( token_address. try_into ( ) . unwrap ( ) ) ;
412
+
413
+ mock_provider. expect_call ( ) . times ( 1 ) . returning ( |_| Err ( ( ) ) ) ;
414
+
415
+ let result = query_ethereum ( & mock_provider, account, & token) . await ;
416
+
417
+ assert_eq ! ( result, Err ( ( ) ) ) ;
418
+ }
419
+ }
155
420
}
0 commit comments