hopr_chain_connector/connector/
values.rs1use std::time::Duration;
2
3use blokli_client::api::BlokliQueryClient;
4use futures::TryFutureExt;
5use hopr_api::chain::{ChainInfo, DomainSeparators};
6use hopr_internal_types::prelude::WinningProbability;
7use hopr_primitive_types::prelude::*;
8
9use crate::{
10 HoprBlockchainReader,
11 connector::HoprBlockchainConnector,
12 errors::ConnectorError,
13 utils::{ParsedChainInfo, model_to_chain_info},
14};
15
16pub(crate) const CHAIN_INFO_CACHE_KEY: u32 = 0;
17
18impl<B, C, P, R> HoprBlockchainConnector<C, R, B, P>
19where
20 C: BlokliQueryClient + Send + Sync + 'static,
21{
22 pub(crate) async fn query_cached_chain_info(&self) -> Result<ParsedChainInfo, ConnectorError> {
23 Ok(self
24 .values
25 .try_get_with(
26 CHAIN_INFO_CACHE_KEY,
27 self.client
28 .query_chain_info()
29 .map_err(ConnectorError::from)
30 .and_then(|model| futures::future::ready(model_to_chain_info(model))),
31 )
32 .await?)
33 }
34}
35
36#[async_trait::async_trait]
37impl<B, R, C, P> hopr_api::chain::ChainValues for HoprBlockchainConnector<C, B, P, R>
38where
39 B: Send + Sync,
40 C: BlokliQueryClient + Send + Sync + 'static,
41 P: Send + Sync,
42 R: Send + Sync,
43{
44 type Error = ConnectorError;
45
46 #[inline]
49 async fn balance<Cy: Currency, A: Into<Address> + Send>(&self, address: A) -> Result<Balance<Cy>, Self::Error> {
50 HoprBlockchainReader(self.client.clone()).balance(address).await
51 }
52
53 async fn domain_separators(&self) -> Result<DomainSeparators, Self::Error> {
54 Ok(self.query_cached_chain_info().await?.domain_separators)
55 }
56
57 async fn minimum_incoming_ticket_win_prob(&self) -> Result<WinningProbability, Self::Error> {
58 Ok(self.query_cached_chain_info().await?.ticket_win_prob)
59 }
60
61 async fn minimum_ticket_price(&self) -> Result<HoprBalance, Self::Error> {
62 Ok(self.query_cached_chain_info().await?.ticket_price)
63 }
64
65 async fn key_binding_fee(&self) -> Result<HoprBalance, Self::Error> {
66 Ok(self.query_cached_chain_info().await?.key_binding_fee)
67 }
68
69 async fn channel_closure_notice_period(&self) -> Result<Duration, Self::Error> {
70 Ok(self.query_cached_chain_info().await?.channel_closure_grace_period)
71 }
72
73 async fn chain_info(&self) -> Result<ChainInfo, Self::Error> {
74 Ok(self.query_cached_chain_info().await?.info)
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use std::str::FromStr;
81
82 use hopr_api::chain::ChainValues;
83 use hopr_crypto_types::prelude::*;
84 use hopr_internal_types::account::{AccountEntry, AccountType};
85
86 use super::*;
87 use crate::{connector::tests::create_connector, testing::BlokliTestStateBuilder};
88
89 #[tokio::test]
90 async fn connector_should_get_balance() -> anyhow::Result<()> {
91 let account = AccountEntry {
92 public_key: *OffchainKeypair::random().public(),
93 chain_addr: [1u8; Address::SIZE].into(),
94 entry_type: AccountType::NotAnnounced,
95 safe_address: Some([2u8; Address::SIZE].into()),
96 key_id: 1.into(),
97 };
98
99 let blokli_client = BlokliTestStateBuilder::default()
100 .with_accounts([(account.clone(), HoprBalance::new_base(100), XDaiBalance::new_base(1))])
101 .with_safe_allowances([(account.safe_address.unwrap(), HoprBalance::new_base(10000))])
102 .build_static_client();
103
104 let mut connector = create_connector(blokli_client)?;
105 connector.connect().await?;
106
107 assert_eq!(
108 connector.balance(account.safe_address.unwrap()).await?,
109 HoprBalance::new_base(100)
110 );
111 assert_eq!(connector.balance(account.chain_addr).await?, XDaiBalance::new_base(1));
112
113 Ok(())
114 }
115
116 #[tokio::test]
117 async fn connector_should_query_chain_info() -> anyhow::Result<()> {
118 let blokli_client = BlokliTestStateBuilder::default()
119 .with_hopr_network_chain_info("rotsee")
120 .build_static_client();
121
122 let mut connector = create_connector(blokli_client)?;
123 connector.connect().await?;
124
125 let chain_info = connector.chain_info().await?;
126
127 assert_eq!(100, chain_info.chain_id);
128 assert_eq!("rotsee", &chain_info.hopr_network_name);
129
130 assert_eq!(Duration::from_mins(5), connector.channel_closure_notice_period().await?);
131 assert_eq!(HoprBalance::new_base(1), connector.minimum_ticket_price().await?);
132 assert!(WinningProbability::ALWAYS.approx_eq(&connector.minimum_incoming_ticket_win_prob().await?));
133 assert_eq!(Hash::default(), connector.domain_separators().await?.channel);
134 assert_eq!(
135 HoprBalance::from_str("0.01 wxHOPR")?,
136 connector.key_binding_fee().await?
137 );
138
139 Ok(())
140 }
141
142 #[tokio::test]
143 async fn connector_should_query_chain_info_without_calling_connect_first() -> anyhow::Result<()> {
144 let blokli_client = BlokliTestStateBuilder::default()
145 .with_hopr_network_chain_info("rotsee")
146 .build_static_client();
147
148 let connector = create_connector(blokli_client)?;
149
150 let chain_info = connector.chain_info().await?;
151
152 assert_eq!(100, chain_info.chain_id);
153 assert_eq!("rotsee", &chain_info.hopr_network_name);
154
155 assert_eq!(Duration::from_mins(5), connector.channel_closure_notice_period().await?);
156 assert_eq!(HoprBalance::new_base(1), connector.minimum_ticket_price().await?);
157 assert!(WinningProbability::ALWAYS.approx_eq(&connector.minimum_incoming_ticket_win_prob().await?));
158 assert_eq!(Hash::default(), connector.domain_separators().await?.channel);
159 assert_eq!(
160 HoprBalance::from_str("0.01 wxHOPR")?,
161 connector.key_binding_fee().await?
162 );
163
164 Ok(())
165 }
166}