polyoxide_relay/
account.rs1use crate::config::BuilderConfig;
2use crate::error::RelayError;
3use alloy::primitives::Address;
4use alloy::signers::local::PrivateKeySigner;
5
6#[derive(Clone, Debug)]
7pub struct BuilderAccount {
8 pub(crate) signer: PrivateKeySigner,
9 pub(crate) config: Option<BuilderConfig>,
10}
11
12impl BuilderAccount {
13 pub fn new(
14 private_key: impl Into<String>,
15 config: Option<BuilderConfig>,
16 ) -> Result<Self, RelayError> {
17 let signer = private_key
18 .into()
19 .parse::<PrivateKeySigner>()
20 .map_err(|e| RelayError::Signer(format!("Failed to parse private key: {}", e)))?;
21
22 Ok(Self { signer, config })
23 }
24
25 pub fn address(&self) -> Address {
26 self.signer.address()
27 }
28
29 pub fn signer(&self) -> &PrivateKeySigner {
30 &self.signer
31 }
32
33 pub fn config(&self) -> Option<&BuilderConfig> {
34 self.config.as_ref()
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 const TEST_PRIVATE_KEY: &str =
45 "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
46
47 #[test]
48 fn test_new_valid_private_key() {
49 let account = BuilderAccount::new(TEST_PRIVATE_KEY, None);
50 assert!(account.is_ok());
51 }
52
53 #[test]
54 fn test_new_with_0x_prefix() {
55 let key = format!("0x{}", TEST_PRIVATE_KEY);
56 let account = BuilderAccount::new(key, None);
57 assert!(account.is_ok());
59 }
60
61 #[test]
62 fn test_new_invalid_private_key() {
63 let result = BuilderAccount::new("not_a_valid_key", None);
64 assert!(result.is_err());
65 let err = result.unwrap_err();
66 match err {
67 RelayError::Signer(msg) => {
68 assert!(
69 msg.contains("Failed to parse private key"),
70 "unexpected: {msg}"
71 );
72 }
73 other => panic!("Expected Signer error, got: {other:?}"),
74 }
75 }
76
77 #[test]
78 fn test_new_empty_key() {
79 let result = BuilderAccount::new("", None);
80 assert!(result.is_err());
81 }
82
83 #[test]
84 fn test_address_derivation_deterministic() {
85 let a1 = BuilderAccount::new(TEST_PRIVATE_KEY, None).unwrap();
86 let a2 = BuilderAccount::new(TEST_PRIVATE_KEY, None).unwrap();
87 assert_eq!(a1.address(), a2.address());
88 }
89
90 #[test]
91 fn test_address_matches_known_value() {
92 let account = BuilderAccount::new(TEST_PRIVATE_KEY, None).unwrap();
94 let expected: Address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
95 .parse()
96 .unwrap();
97 assert_eq!(account.address(), expected);
98 }
99
100 #[test]
101 fn test_config_none() {
102 let account = BuilderAccount::new(TEST_PRIVATE_KEY, None).unwrap();
103 assert!(account.config().is_none());
104 }
105
106 #[test]
107 fn test_config_some() {
108 let config = BuilderConfig::new("key".into(), "secret".into(), None);
109 let account = BuilderAccount::new(TEST_PRIVATE_KEY, Some(config)).unwrap();
110 assert!(account.config().is_some());
111 }
112}