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