1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
use crate::Error;
use async_trait::async_trait;
use std::any::Any;
use std::fmt;
/// BlockchainConnector trait is used to connect to a blockchain and send and receive information to and from the blockchain.
#[async_trait]
pub trait BlockchainConnector {
/// ErrorType is the type of error that is returned by the BlockchainConnector
type ErrorType: std::error::Error + fmt::Display + Send + Sync + 'static;
/// new creates a new BlockchainConnector with a given url
fn new(url: &str) -> Result<Self, Self::ErrorType>
where
Self: Sized;
/// url returns the url of the BlockchainConnector
fn url(&self) -> &str;
// TODO(AS): return the fee estimates.. also consider adding functions to get common blockchain functions
/// Returns the builder that can be used to build a BlockchainConnector with custom options
fn builder() -> BlockchainConnectorBuilder<Self>
where
Self: Sized + Clone + BlockchainConnectorGeneral,
{
BlockchainConnectorBuilder::new()
}
}
/// BlockchainConnectorGeneral is a general trait that can work with any struct that implements the BlockchainConnector trait
pub trait BlockchainConnectorGeneral {
/// Returns a dyn Any reference to the BlockchainConnector
fn as_any(&self) -> &dyn Any;
/// Returns a clone in a box type
fn box_clone(&self) -> Box<dyn BlockchainConnectorGeneral>;
}
/// ConnectorType is an enum that represents the type of connector that is being used, the different enum variants are meant to bue used with different cryptocurrency types and the generic type T is meant to be a specific struct that implements the BlockchainConnector trait
#[derive(Debug, Clone, Copy)]
pub enum ConnectorType<T>
where
T: BlockchainConnector + Clone,
{
/// BTC is a variant that represents a connector that is used to connect to a Bitcoin blockchain
BTC(T),
/// ETH is a variant that represents a connector that is used to connect to an Ethereum blockchain
ETH(T),
}
/// BlockchainConnectorBuilder is a builder that can be used to build a BlockchainConnector with custom options
#[derive(Debug, Clone, Default)]
pub struct BlockchainConnectorBuilder<T>
where
T: BlockchainConnector + Clone,
{
url: Option<String>,
connector_type: Option<ConnectorType<T>>,
}
impl<T> BlockchainConnectorBuilder<T>
where
T: BlockchainConnector + BlockchainConnectorGeneral + Clone,
{
/// new creates a new BlockchainConnectorBuilder with default options (no url and no connector type specified)
pub fn new() -> Self {
Self {
url: None,
connector_type: None,
}
}
/// This function sets the url of the BlockchainConnectorBuilder
pub fn set_url(&mut self, url: String) -> Self {
self.url = Some(url);
self.clone()
}
/// This function sets the connector type of the BlockchainConnectorBuilder, this requires the associated BlockchainConnector struct to be fully defined with data
pub fn set_connector(&mut self, connector_type: ConnectorType<T>) -> Self {
self.connector_type = Some(connector_type);
self.clone()
}
/// This function builds the BlockchainConnectorBuilder using the options provided in the builder
///
/// It returns a [Box< dyn BlockchainConnectorGeneral >] that can be used to connect to a blockchain.
/// The result of that build later can be downcasted to a specific [BlockchainConnector] struct - any compatible struct that implements the [BlockchainConnector] trait.
pub fn build(&mut self) -> Result<Box<dyn BlockchainConnectorGeneral>, Error> {
match &self.connector_type {
Some(ConnectorType::BTC(connector) | ConnectorType::ETH(connector)) => {
Ok(connector.box_clone())
}
None => match self.url {
Some(ref url) => {
let client = T::new(url)
.map_err(|e| Error::BlockchainConnectorBuilder(e.to_string()))?;
let client_gen = client.box_clone();
Ok(client_gen)
}
None => Err(Error::BlockchainConnectorBuilder("url not set".into())),
},
}
}
}