use std::sync::{Arc, OnceLock};
use alloy_primitives::Address;
use crate::error::CowError;
type AdapterArc = Arc<dyn ProviderAdapter>;
static GLOBAL_ADAPTER: OnceLock<AdapterArc> = OnceLock::new();
pub trait ProviderAdapter: Send + Sync {
fn signer_address(&self) -> Result<Address, CowError>;
fn sign_typed_data(
&self,
domain_separator: [u8; 32],
struct_hash: [u8; 32],
) -> Result<Vec<u8>, CowError>;
fn sign_message(&self, message: &[u8]) -> Result<Vec<u8>, CowError>;
}
pub fn set_global_adapter(adapter: AdapterArc) {
let _already_set = GLOBAL_ADAPTER.set(adapter);
}
pub fn get_global_adapter() -> Result<AdapterArc, CowError> {
GLOBAL_ADAPTER.get().cloned().ok_or_else(|| {
CowError::Config(
"Provider adapter is not configured. Call set_global_adapter() first.".to_owned(),
)
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_global_adapter_returns_error_when_unset() {
let _result = get_global_adapter();
}
struct MockAdapter;
impl ProviderAdapter for MockAdapter {
fn signer_address(&self) -> Result<Address, CowError> {
Ok(Address::ZERO)
}
fn sign_typed_data(
&self,
_domain_separator: [u8; 32],
_struct_hash: [u8; 32],
) -> Result<Vec<u8>, CowError> {
Ok(vec![0u8; 65])
}
fn sign_message(&self, _message: &[u8]) -> Result<Vec<u8>, CowError> {
Ok(vec![0u8; 65])
}
}
#[test]
fn set_global_adapter_accepts_arc() {
let adapter = Arc::new(MockAdapter);
set_global_adapter(adapter);
let result = get_global_adapter();
assert!(result.is_ok());
}
#[test]
fn mock_adapter_signer_address() {
let adapter = MockAdapter;
assert_eq!(adapter.signer_address().unwrap(), Address::ZERO);
}
#[test]
fn mock_adapter_sign_typed_data() {
let adapter = MockAdapter;
let result = adapter.sign_typed_data([0u8; 32], [0u8; 32]).unwrap();
assert_eq!(result.len(), 65);
}
#[test]
fn mock_adapter_sign_message() {
let adapter = MockAdapter;
let result = adapter.sign_message(b"hello").unwrap();
assert_eq!(result.len(), 65);
}
}