Skip to main content

pyra_redis/kamino/
typed.rs

1//! Typed fetch helpers for Kamino-specific Redis data.
2
3use std::collections::HashMap;
4
5use solana_pubkey::Pubkey;
6
7use pyra_types::{Cache, KaminoObligation, KaminoReserve};
8
9use crate::{RedisClient, RedisError, RedisKey, RedisResult};
10
11impl RedisClient {
12    /// Fetch a Kamino obligation by the vault (authority) address and lending market.
13    pub async fn fetch_kamino_obligation(
14        &self,
15        vault_address: &Pubkey,
16        lending_market: &Pubkey,
17    ) -> RedisResult<Option<KaminoObligation>> {
18        let key = RedisKey::kamino_obligation(vault_address, lending_market);
19        let cached: Option<Cache<KaminoObligation>> = self.get_json(key.as_str()).await?;
20        Ok(cached.map(|c| c.account))
21    }
22
23    /// Reverse lookup: Kamino Obligation account pubkey → vault authority (owner).
24    pub async fn fetch_kamino_obligation_by_pubkey(
25        &self,
26        obligation_pubkey: &Pubkey,
27    ) -> RedisResult<Pubkey> {
28        let key = RedisKey::kamino_obligation_by_pubkey(obligation_pubkey);
29        let raw = self
30            .get(key.as_str())
31            .await?
32            .ok_or_else(|| RedisError::NotFound("Kamino obligation reverse mapping".into()))?;
33        raw.parse::<Pubkey>().map_err(|_| {
34            RedisError::NotFound("Invalid pubkey in obligation reverse mapping".into())
35        })
36    }
37
38    /// Fetch a single Kamino reserve by its pubkey.
39    pub async fn fetch_kamino_reserve(
40        &self,
41        reserve_pubkey: &Pubkey,
42    ) -> RedisResult<Option<KaminoReserve>> {
43        let key = RedisKey::kamino_reserve(reserve_pubkey);
44        let cached: Option<Cache<KaminoReserve>> = self.get_json(key.as_str()).await?;
45        Ok(cached.map(|c| c.account))
46    }
47
48    /// Fetch multiple Kamino reserves by pubkey in a single MGET round-trip.
49    ///
50    /// Returns only the reserves that were found and successfully deserialized.
51    pub async fn fetch_kamino_reserves(
52        &self,
53        pubkeys: &[Pubkey],
54    ) -> RedisResult<HashMap<Pubkey, KaminoReserve>> {
55        if pubkeys.is_empty() {
56            return Ok(HashMap::new());
57        }
58
59        let keys: Vec<String> = pubkeys
60            .iter()
61            .map(|pk| RedisKey::kamino_reserve(pk).to_string())
62            .collect();
63
64        let values = self.mget(&keys).await?;
65        let mut result = HashMap::with_capacity(pubkeys.len());
66
67        for (pk, val) in pubkeys.iter().zip(values.into_iter()) {
68            if let Some(raw) = val {
69                if let Ok(cached) = serde_json::from_str::<Cache<KaminoReserve>>(&raw) {
70                    result.insert(*pk, cached.account);
71                }
72            }
73        }
74
75        Ok(result)
76    }
77
78    /// Fetch all Kamino reserves by scanning `account:kamino:reserve:*` keys.
79    ///
80    /// Uses SCAN + MGET for efficiency. Returns reserve_pubkey -> KaminoReserve.
81    pub async fn fetch_all_kamino_reserves(&self) -> RedisResult<HashMap<Pubkey, KaminoReserve>> {
82        let pattern = RedisKey::kamino_reserve_glob();
83        let keys = self.scan_keys(&pattern).await?;
84
85        if keys.is_empty() {
86            return Ok(HashMap::new());
87        }
88
89        let prefix_with_colon = format!("{}:", RedisKey::KAMINO_RESERVE_PREFIX);
90        let values = self.mget(&keys).await?;
91        let mut result = HashMap::with_capacity(keys.len());
92
93        for (key, val) in keys.iter().zip(values.into_iter()) {
94            if let Some(raw) = val {
95                if let Ok(cached) = serde_json::from_str::<Cache<KaminoReserve>>(&raw) {
96                    if let Some(pk_str) = key.strip_prefix(prefix_with_colon.as_str()) {
97                        if let Ok(pk) = pk_str.parse::<Pubkey>() {
98                            result.insert(pk, cached.account);
99                        }
100                    }
101                }
102            }
103        }
104
105        Ok(result)
106    }
107}