hopr_api/chain/
accounts.rs

1use futures::{future::BoxFuture, stream::BoxStream};
2use hopr_crypto_types::prelude::{OffchainKeypair, OffchainPublicKey};
3pub use hopr_internal_types::prelude::AccountEntry;
4use hopr_primitive_types::prelude::Address;
5pub use hopr_primitive_types::prelude::{Balance, Currency};
6pub use multiaddr::Multiaddr;
7
8use crate::chain::ChainReceipt;
9
10/// Error that can occur when making a node announcement.
11///
12/// See [`ChainWriteAccountOperations::announce`]
13#[derive(Debug, strum::EnumIs, strum::EnumTryAs, thiserror::Error)]
14pub enum AnnouncementError<E> {
15    /// Special error when an account is already announced.
16    #[error("already announced")]
17    AlreadyAnnounced,
18    /// Error that can occur when processing an announcement.
19    #[error("account announcement error: {0}")]
20    ProcessingError(E),
21}
22/// Error that can occur when registering node with a Safe.
23#[derive(Debug, strum::EnumIs, strum::EnumTryAs, thiserror::Error)]
24pub enum SafeRegistrationError<E> {
25    /// Special error when a Safe is already registered.
26    #[error("safe {0} is already registered with this node")]
27    AlreadyRegistered(Address),
28    /// Error that can occur when processing a Safe registration.
29    #[error("safe registration error: {0}")]
30    ProcessingError(E),
31}
32
33/// On-chain write operations regarding on-chain node accounts.
34#[async_trait::async_trait]
35#[auto_impl::auto_impl(&, Box, Arc)]
36pub trait ChainWriteAccountOperations {
37    type Error: std::error::Error + Send + Sync + 'static;
38
39    /// Announces transport key and list of multi addresses.
40    async fn announce(
41        &self,
42        multiaddrs: &[Multiaddr],
43        key: &OffchainKeypair,
44    ) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, AnnouncementError<Self::Error>>;
45
46    /// Withdraws native or token currency.
47    async fn withdraw<C: Currency + Send>(
48        &self,
49        balance: Balance<C>,
50        recipient: &Address,
51    ) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, Self::Error>;
52
53    /// Registers Safe address with the current node.
54    async fn register_safe(
55        &self,
56        safe_address: &Address,
57    ) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, SafeRegistrationError<Self::Error>>;
58}
59
60/// Selector for on-chain node accounts.
61///
62/// See [`ChainReadAccountOperations::stream_accounts`].
63#[derive(Clone, Debug, PartialEq, Eq, Default)]
64pub struct AccountSelector {
65    /// Selects accounts that announced with publicly routable multi-addresses.
66    pub public_only: bool,
67    /// Selects accounts bound with the given chain key.
68    pub chain_key: Option<Address>,
69    /// Selects accounts bound with the given off-chain key.
70    pub offchain_key: Option<OffchainPublicKey>,
71}
72
73impl AccountSelector {
74    /// Selects only accounts that announced with publicly routable multi-addresses.
75    #[must_use]
76    pub fn with_public_only(mut self, public_only: bool) -> Self {
77        self.public_only = public_only;
78        self
79    }
80
81    /// Selects accounts bound with the given chain key.
82    #[must_use]
83    pub fn with_chain_key(mut self, chain_key: Address) -> Self {
84        self.chain_key = Some(chain_key);
85        self
86    }
87
88    /// Selects accounts bound with the given off-chain key.
89    #[must_use]
90    pub fn with_offchain_key(mut self, offchain_key: OffchainPublicKey) -> Self {
91        self.offchain_key = Some(offchain_key);
92        self
93    }
94
95    /// Checks if the given [`account`](AccountEntry) satisfies the selector.
96    pub fn satisfies(&self, account: &AccountEntry) -> bool {
97        if self.public_only && !account.has_announced_with_routing_info() {
98            return false;
99        }
100
101        if let Some(chain_key) = &self.chain_key {
102            if &account.chain_addr != chain_key {
103                return false;
104            }
105        }
106
107        if let Some(packet_key) = &self.offchain_key {
108            if &account.public_key != packet_key {
109                return false;
110            }
111        }
112
113        true
114    }
115}
116
117/// Chain operations that read on-chain node accounts.
118#[async_trait::async_trait]
119#[auto_impl::auto_impl(&, Box, Arc)]
120pub trait ChainReadAccountOperations {
121    type Error: std::error::Error + Send + Sync + 'static;
122
123    /// Returns the native or token currency balance of the given on-chain account.
124    async fn get_balance<C: Currency, A: Into<Address> + Send>(&self, address: A) -> Result<Balance<C>, Self::Error>;
125
126    /// Returns the native or token currency Safe allowance.
127    async fn safe_allowance<C: Currency, A: Into<Address> + Send>(
128        &self,
129        safe_address: A,
130    ) -> Result<Balance<C>, Self::Error>;
131
132    /// Returns on-chain node accounts with the given [`AccountSelector`].
133    async fn stream_accounts<'a>(
134        &'a self,
135        selector: AccountSelector,
136    ) -> Result<BoxStream<'a, AccountEntry>, Self::Error>;
137
138    /// Counts the accounts with the given [`AccountSelector`].
139    ///
140    /// This is potentially done more effectively than counting more elements of
141    /// the stream returned by [`ChainReadAccountOperations::stream_accounts`].
142    async fn count_accounts(&self, selector: AccountSelector) -> Result<usize, Self::Error>;
143}