use anchor_lang::{AccountDeserialize, Discriminator}; use mango_v4::state::{Bank, MangoAccount, MangoAccountValue, MintInfo, PerpMarket, Serum3Market}; use solana_account_decoder::UiAccountEncoding; use solana_client::nonblocking::rpc_client::RpcClient as RpcClientAsync; use solana_client::rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}; use solana_client::rpc_filter::{Memcmp, RpcFilterType}; use solana_sdk::account::AccountSharedData; use solana_sdk::pubkey::Pubkey; pub async fn fetch_mango_accounts( rpc: &RpcClientAsync, program: Pubkey, group: Pubkey, owner: Pubkey, ) -> anyhow::Result> { let config = RpcProgramAccountsConfig { filters: Some(vec![ RpcFilterType::Memcmp(Memcmp::new_raw_bytes( 0, MangoAccount::discriminator().to_vec(), )), RpcFilterType::Memcmp(Memcmp::new_raw_bytes(8, group.to_bytes().to_vec())), RpcFilterType::Memcmp(Memcmp::new_raw_bytes(40, owner.to_bytes().to_vec())), ]), account_config: RpcAccountInfoConfig { encoding: Some(UiAccountEncoding::Base64), ..RpcAccountInfoConfig::default() }, ..RpcProgramAccountsConfig::default() }; rpc.get_program_accounts_with_config(&program, config) .await? .into_iter() .map(|(key, account)| Ok((key, MangoAccountValue::from_bytes(&account.data[8..])?))) .collect::, _>>() } pub async fn fetch_anchor_account( rpc: &RpcClientAsync, address: &Pubkey, ) -> anyhow::Result { let account = rpc.get_account(address).await?; Ok(T::try_deserialize(&mut (&account.data as &[u8]))?) } async fn fetch_anchor_accounts( rpc: &RpcClientAsync, program: Pubkey, filters: Vec, ) -> anyhow::Result> { let account_type_filter = RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, T::discriminator().to_vec())); let config = RpcProgramAccountsConfig { filters: Some([vec![account_type_filter], filters].concat()), account_config: RpcAccountInfoConfig { encoding: Some(UiAccountEncoding::Base64), ..RpcAccountInfoConfig::default() }, ..RpcProgramAccountsConfig::default() }; rpc.get_program_accounts_with_config(&program, config) .await? .into_iter() .map(|(key, account)| Ok((key, T::try_deserialize(&mut (&account.data as &[u8]))?))) .collect() } pub async fn fetch_banks( rpc: &RpcClientAsync, program: Pubkey, group: Pubkey, ) -> anyhow::Result> { fetch_anchor_accounts::( rpc, program, vec![RpcFilterType::Memcmp(Memcmp::new_raw_bytes( 8, group.to_bytes().to_vec(), ))], ) .await } pub async fn fetch_mint_infos( rpc: &RpcClientAsync, program: Pubkey, group: Pubkey, ) -> anyhow::Result> { fetch_anchor_accounts::( rpc, program, vec![RpcFilterType::Memcmp(Memcmp::new_raw_bytes( 8, group.to_bytes().to_vec(), ))], ) .await } pub async fn fetch_serum3_markets( rpc: &RpcClientAsync, program: Pubkey, group: Pubkey, ) -> anyhow::Result> { fetch_anchor_accounts::( rpc, program, vec![RpcFilterType::Memcmp(Memcmp::new_raw_bytes( 8, group.to_bytes().to_vec(), ))], ) .await } pub async fn fetch_perp_markets( rpc: &RpcClientAsync, program: Pubkey, group: Pubkey, ) -> anyhow::Result> { fetch_anchor_accounts::( rpc, program, vec![RpcFilterType::Memcmp(Memcmp::new_raw_bytes( 8, group.to_bytes().to_vec(), ))], ) .await } pub async fn fetch_multiple_accounts( rpc: &RpcClientAsync, keys: &[Pubkey], ) -> anyhow::Result> { let config = RpcAccountInfoConfig { encoding: Some(UiAccountEncoding::Base64), ..RpcAccountInfoConfig::default() }; Ok(rpc .get_multiple_accounts_with_config(keys, config) .await? .value .into_iter() .zip(keys.iter()) .filter(|(maybe_acc, _)| maybe_acc.is_some()) .map(|(acc, key)| (*key, acc.unwrap().into())) .collect()) }