use std::sync::Arc;
use alloy::dyn_abi::TypedData;
use alloy::{consensus::TypedTransaction, signers::Signature};
use async_trait::async_trait;
use crate::{
network::ChainId,
shared::common_types::EvmAddress,
wallet::{WalletError, WalletManagerTrait},
};
pub struct CompositeWalletManager {
primary_manager: Arc<dyn WalletManagerTrait>,
private_key_manager: Option<Arc<dyn WalletManagerTrait>>,
}
impl CompositeWalletManager {
pub fn new(
primary_manager: Arc<dyn WalletManagerTrait>,
private_key_manager: Option<Arc<dyn WalletManagerTrait>>,
) -> Self {
CompositeWalletManager { primary_manager, private_key_manager }
}
fn is_private_key_index(&self, wallet_index: u32) -> bool {
wallet_index >= u32::MAX - 1000
}
fn get_manager_for_index(
&self,
wallet_index: u32,
) -> Result<&Arc<dyn WalletManagerTrait>, WalletError> {
if self.is_private_key_index(wallet_index) {
if let Some(ref manager) = self.private_key_manager {
Ok(manager)
} else {
Err(WalletError::UnsupportedOperation(format!(
"Private key wallet index {} requested but no private key manager configured",
wallet_index
)))
}
} else {
Ok(&self.primary_manager)
}
}
}
#[async_trait]
impl WalletManagerTrait for CompositeWalletManager {
async fn create_wallet(
&self,
wallet_index: u32,
chain_id: &ChainId,
) -> Result<EvmAddress, WalletError> {
let manager = self.get_manager_for_index(wallet_index)?;
manager.create_wallet(wallet_index, chain_id).await
}
async fn get_address(
&self,
wallet_index: u32,
chain_id: &ChainId,
) -> Result<EvmAddress, WalletError> {
let manager = self.get_manager_for_index(wallet_index)?;
manager.get_address(wallet_index, chain_id).await
}
async fn sign_transaction(
&self,
wallet_index: u32,
transaction: &TypedTransaction,
chain_id: &ChainId,
) -> Result<Signature, WalletError> {
let manager = self.get_manager_for_index(wallet_index)?;
manager.sign_transaction(wallet_index, transaction, chain_id).await
}
async fn sign_text(
&self,
wallet_index: u32,
text: &str,
chain_id: &ChainId,
) -> Result<Signature, WalletError> {
let manager = self.get_manager_for_index(wallet_index)?;
manager.sign_text(wallet_index, text, chain_id).await
}
async fn sign_typed_data(
&self,
wallet_index: u32,
typed_data: &TypedData,
chain_id: &ChainId,
) -> Result<Signature, WalletError> {
let manager = self.get_manager_for_index(wallet_index)?;
manager.sign_typed_data(wallet_index, typed_data, chain_id).await
}
fn supports_blobs(&self) -> bool {
let primary_supports = self.primary_manager.supports_blobs();
let private_key_supports =
self.private_key_manager.as_ref().is_some_and(|m| m.supports_blobs());
primary_supports || private_key_supports
}
}