use futures::{future::BoxFuture, stream::BoxStream};
use hopr_types::{
crypto::prelude::{OffchainKeypair, OffchainPublicKey},
primitive::prelude::Address,
};
pub use hopr_types::{
internal::prelude::AccountEntry,
primitive::prelude::{Balance, Currency},
};
pub use multiaddr::Multiaddr;
use crate::chain::ChainReceipt;
#[derive(Debug, strum::EnumIs, strum::EnumTryAs, thiserror::Error)]
pub enum AnnouncementError<E> {
#[error("already announced")]
AlreadyAnnounced,
#[error("account announcement error: {0}")]
ProcessingError(E),
}
impl<E> AnnouncementError<E> {
pub fn processing<F: Into<E>>(error: F) -> Self {
Self::ProcessingError(error.into())
}
}
#[derive(Debug, strum::EnumIs, strum::EnumTryAs, thiserror::Error)]
pub enum SafeRegistrationError<E> {
#[error("node is already registered with safe {0}")]
AlreadyRegistered(Address),
#[error("safe registration error: {0}")]
ProcessingError(E),
}
impl<E> SafeRegistrationError<E> {
pub fn processing<F: Into<E>>(error: F) -> Self {
Self::ProcessingError(error.into())
}
}
#[async_trait::async_trait]
#[auto_impl::auto_impl(&, Box, Arc)]
pub trait ChainWriteAccountOperations {
type Error: std::error::Error + Send + Sync + 'static;
async fn announce(
&self,
multiaddrs: &[Multiaddr],
key: &OffchainKeypair,
) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, AnnouncementError<Self::Error>>;
async fn withdraw<C: Currency + Send>(
&self,
balance: Balance<C>,
recipient: &Address,
) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, Self::Error>;
async fn register_safe(
&self,
safe_address: &Address,
) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, SafeRegistrationError<Self::Error>>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct AccountSelector {
pub public_only: bool,
pub chain_key: Option<Address>,
pub offchain_key: Option<OffchainPublicKey>,
}
impl AccountSelector {
#[must_use]
pub fn with_public_only(mut self, public_only: bool) -> Self {
self.public_only = public_only;
self
}
#[must_use]
pub fn with_chain_key(mut self, chain_key: Address) -> Self {
self.chain_key = Some(chain_key);
self
}
#[must_use]
pub fn with_offchain_key(mut self, offchain_key: OffchainPublicKey) -> Self {
self.offchain_key = Some(offchain_key);
self
}
pub fn satisfies(&self, account: &AccountEntry) -> bool {
if self.public_only && !account.has_announced_with_routing_info() {
return false;
}
if let Some(chain_key) = &self.chain_key
&& &account.chain_addr != chain_key
{
return false;
}
if let Some(packet_key) = &self.offchain_key
&& &account.public_key != packet_key
{
return false;
}
true
}
}
#[async_trait::async_trait]
#[auto_impl::auto_impl(&, Box, Arc)]
pub trait ChainReadAccountOperations {
type Error: std::error::Error + Send + Sync + 'static;
fn stream_accounts<'a>(&'a self, selector: AccountSelector) -> Result<BoxStream<'a, AccountEntry>, Self::Error>;
async fn count_accounts(&self, selector: AccountSelector) -> Result<usize, Self::Error>;
async fn await_key_binding(
&self,
offchain_key: &OffchainPublicKey,
timeout: std::time::Duration,
) -> Result<AccountEntry, Self::Error>;
}