mango-v4/lib/client/src/gpa.rs

151 lines
4.5 KiB
Rust

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<Vec<(Pubkey, MangoAccountValue)>> {
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::<Result<Vec<_>, _>>()
}
pub async fn fetch_anchor_account<T: AccountDeserialize>(
rpc: &RpcClientAsync,
address: &Pubkey,
) -> anyhow::Result<T> {
let account = rpc.get_account(address).await?;
Ok(T::try_deserialize(&mut (&account.data as &[u8]))?)
}
async fn fetch_anchor_accounts<T: AccountDeserialize + Discriminator>(
rpc: &RpcClientAsync,
program: Pubkey,
filters: Vec<RpcFilterType>,
) -> anyhow::Result<Vec<(Pubkey, T)>> {
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<Vec<(Pubkey, Bank)>> {
fetch_anchor_accounts::<Bank>(
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<Vec<(Pubkey, MintInfo)>> {
fetch_anchor_accounts::<MintInfo>(
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<Vec<(Pubkey, Serum3Market)>> {
fetch_anchor_accounts::<Serum3Market>(
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<Vec<(Pubkey, PerpMarket)>> {
fetch_anchor_accounts::<PerpMarket>(
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<Vec<(Pubkey, AccountSharedData)>> {
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())
}