use crate::{
error::{Error, Result},
sdk::ApexSDK,
};
use std::time::Duration;
#[cfg(feature = "substrate")]
use apex_sdk_substrate::SubstrateAdapter;
#[cfg(feature = "evm")]
use apex_sdk_evm::EvmAdapter;
#[derive(Default)]
pub struct ApexSDKBuilder {
#[cfg(feature = "substrate")]
substrate_endpoint: Option<String>,
#[cfg(feature = "substrate")]
substrate_wallet: Option<apex_sdk_substrate::Wallet>,
#[cfg(feature = "evm")]
evm_endpoint: Option<String>,
#[cfg(feature = "evm")]
evm_wallet: Option<apex_sdk_evm::wallet::Wallet>,
timeout: Option<Duration>,
config: Option<crate::sdk::SdkConfig>,
}
impl ApexSDKBuilder {
pub fn new() -> Self {
Self::default()
}
#[cfg(feature = "substrate")]
pub fn with_substrate_endpoint(mut self, endpoint: impl Into<String>) -> Self {
self.substrate_endpoint = Some(endpoint.into());
self
}
#[cfg(feature = "evm")]
pub fn with_evm_endpoint(mut self, endpoint: impl Into<String>) -> Self {
self.evm_endpoint = Some(endpoint.into());
self
}
#[cfg(feature = "substrate")]
pub fn with_substrate_wallet(mut self, wallet: apex_sdk_substrate::Wallet) -> Self {
self.substrate_wallet = Some(wallet);
self
}
#[cfg(feature = "evm")]
pub fn with_evm_wallet(mut self, wallet: apex_sdk_evm::wallet::Wallet) -> Self {
self.evm_wallet = Some(wallet);
self
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub fn with_config(mut self, config: crate::sdk::SdkConfig) -> Self {
self.config = Some(config);
self
}
pub fn with_confirmation_strategy(
mut self,
strategy: crate::sdk::ConfirmationStrategy,
) -> Self {
let mut config = self.config.unwrap_or_default();
config.confirmation_strategy = strategy;
self.config = Some(config);
self
}
pub async fn build(self) -> Result<ApexSDK> {
let timeout = self.timeout.unwrap_or(Duration::from_secs(30));
#[cfg(feature = "substrate")]
let substrate_adapter = if let Some(endpoint) = self.substrate_endpoint {
Some(
SubstrateAdapter::connect(&endpoint)
.await
.map_err(|e| Error::Connection(e.to_string()))?,
)
} else {
None
};
#[cfg(feature = "evm")]
let evm_adapter = if let Some(endpoint) = self.evm_endpoint {
Some(
EvmAdapter::connect(&endpoint)
.await
.map_err(|e| Error::Connection(e.to_string()))?,
)
} else {
None
};
#[cfg(all(feature = "substrate", feature = "evm"))]
{
if substrate_adapter.is_none() && evm_adapter.is_none() {
return Err(Error::Config(
"At least one blockchain adapter must be configured".to_string(),
));
}
}
#[cfg(all(feature = "substrate", not(feature = "evm")))]
{
if substrate_adapter.is_none() {
return Err(Error::Config(
"Substrate adapter must be configured when EVM feature is disabled".to_string(),
));
}
}
#[cfg(all(not(feature = "substrate"), feature = "evm"))]
{
if evm_adapter.is_none() {
return Err(Error::Config(
"EVM adapter must be configured when Substrate feature is disabled".to_string(),
));
}
}
ApexSDK::new(
#[cfg(feature = "substrate")]
substrate_adapter,
#[cfg(feature = "substrate")]
self.substrate_wallet,
#[cfg(feature = "evm")]
evm_adapter,
#[cfg(feature = "evm")]
self.evm_wallet,
timeout,
self.config.unwrap_or_default(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_new_creates_default_builder() {
let builder = ApexSDKBuilder::new();
assert!(builder.timeout.is_none());
#[cfg(feature = "substrate")]
assert!(builder.substrate_endpoint.is_none());
#[cfg(feature = "evm")]
assert!(builder.evm_endpoint.is_none());
}
#[test]
fn test_builder_default_trait() {
let builder = ApexSDKBuilder::default();
assert!(builder.timeout.is_none());
}
#[test]
fn test_builder_chaining() {
let builder = ApexSDKBuilder::new().with_timeout(Duration::from_secs(60));
assert_eq!(builder.timeout, Some(Duration::from_secs(60)));
}
#[cfg(feature = "substrate")]
#[test]
fn test_builder_with_substrate_endpoint() {
let endpoint = "wss://polkadot.api.onfinality.io/public-ws";
let builder = ApexSDKBuilder::new().with_substrate_endpoint(endpoint);
assert_eq!(builder.substrate_endpoint, Some(endpoint.to_string()));
}
#[cfg(feature = "evm")]
#[test]
fn test_builder_with_evm_endpoint() {
let endpoint = "https://mainnet.infura.io/v3/YOUR_KEY";
let builder = ApexSDKBuilder::new().with_evm_endpoint(endpoint);
assert_eq!(builder.evm_endpoint, Some(endpoint.to_string()));
}
#[test]
fn test_builder_with_timeout() {
let timeout = Duration::from_secs(45);
let builder = ApexSDKBuilder::new().with_timeout(timeout);
assert_eq!(builder.timeout, Some(timeout));
}
#[tokio::test]
async fn test_builder_requires_at_least_one_adapter() {
let result = ApexSDKBuilder::new().build().await;
assert!(result.is_err());
if let Err(Error::Config(msg)) = result {
assert!(msg.contains("adapter"));
}
}
}