penumbra_sdk_dex/component/
lqt.rs

1use crate::lp::position;
2use crate::state_key::lqt;
3use anyhow::Result;
4use async_trait::async_trait;
5use cnidarium::StateRead;
6use futures::StreamExt;
7use penumbra_sdk_asset::asset;
8use penumbra_sdk_num::Amount;
9use penumbra_sdk_proto::StateReadProto;
10use penumbra_sdk_sct::component::clock::EpochRead;
11use std::pin::Pin;
12
13/// Provides public read access to LQT data.
14#[async_trait]
15pub trait LqtRead: StateRead {
16    /// Returns the cumulative volume of staking token for a trading pair.
17    /// This is the sum of the outflows of the staking token from all positions in the pair.
18    ///
19    /// Default to zero if no volume is found.
20    async fn get_volume_for_pair(&self, asset: asset::Id) -> Amount {
21        let epoch = self.get_current_epoch().await.expect("epoch is always set");
22        let key = lqt::v1::pair::lookup::volume_by_pair(epoch.index, asset);
23        let value = self.nonverifiable_get(&key).await.unwrap_or_default();
24        value.unwrap_or_default()
25    }
26
27    /// Returns the cumulative volume of staking token for a given position id.
28    /// This is the sum of the outflows of the staking token from the position.
29    ///
30    /// Default to zero if no volume is found.
31    async fn get_volume_for_position(&self, position_id: &position::Id) -> Amount {
32        let epoch = self.get_current_epoch().await.expect("epoch is always set");
33        let key = lqt::v1::lp::lookup::volume_by_position(epoch.index, position_id);
34        let value = self.nonverifiable_get(&key).await.unwrap_or_default();
35        value.unwrap_or_default()
36    }
37
38    /// Returns a stream of position ids sorted by descending volume.
39    /// The volume is the sum of the outflows of the staking token from the position.
40    fn positions_by_volume_stream(
41        &self,
42        epoch_index: u64,
43        asset_id: asset::Id,
44    ) -> Result<
45        Pin<
46            Box<
47                dyn futures::Stream<Item = Result<(asset::Id, position::Id, Amount)>>
48                    + Send
49                    + 'static,
50            >,
51        >,
52    > {
53        let key = lqt::v1::lp::by_volume::prefix_with_asset(epoch_index, &asset_id);
54        Ok(self
55            .nonverifiable_prefix_raw(&key)
56            .map(|res| {
57                res.map(|(raw_entry, _)| {
58                    let (asset, volume, position_id) =
59                        lqt::v1::lp::by_volume::parse_key(&raw_entry).expect("internal invariant failed: failed to parse state key for lqt::v1::lp::by_volume");
60                    (asset, position_id, volume)
61                })
62            })
63            .boxed())
64    }
65}
66
67impl<T: StateRead + ?Sized> LqtRead for T {}