reth_rpc_eth_api/helpers/
signer.rs1use alloy_dyn_abi::TypedData;
4use alloy_primitives::{Address, Signature};
5use alloy_rpc_types_eth::TransactionRequest;
6use dyn_clone::DynClone;
7use reth_rpc_eth_types::SignError;
8use std::result;
9
10pub type Result<T> = result::Result<T, SignError>;
12
13#[async_trait::async_trait]
15pub trait EthSigner<T, TxReq = TransactionRequest>: Send + Sync + DynClone {
16 fn accounts(&self) -> Vec<Address>;
18
19 fn is_signer_for(&self, addr: &Address) -> bool {
21 self.accounts().contains(addr)
22 }
23
24 async fn sign(&self, address: Address, message: &[u8]) -> Result<Signature>;
26
27 async fn sign_transaction(&self, request: TxReq, address: &Address) -> Result<T>;
29
30 fn sign_typed_data(&self, address: Address, payload: &TypedData) -> Result<Signature>;
32}
33
34dyn_clone::clone_trait_object!(<T, TxReq> EthSigner<T, TxReq>);
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[derive(Clone)]
41 struct MockSigner;
42
43 struct MockSignedTx;
44 struct MockTxReq;
45
46 #[async_trait::async_trait]
47 impl EthSigner<MockSignedTx, MockTxReq> for MockSigner {
48 fn accounts(&self) -> Vec<Address> {
49 Vec::new()
50 }
51
52 async fn sign(&self, _address: Address, _message: &[u8]) -> Result<Signature> {
53 Err(SignError::NoAccount)
54 }
55
56 async fn sign_transaction(
57 &self,
58 _request: MockTxReq,
59 _address: &Address,
60 ) -> Result<MockSignedTx> {
61 Err(SignError::NoAccount)
62 }
63
64 fn sign_typed_data(&self, _address: Address, _payload: &TypedData) -> Result<Signature> {
65 Err(SignError::NoAccount)
66 }
67 }
68
69 #[test]
70 fn clones_trait_object_with_custom_tx_request_type() {
71 let signer: Box<dyn EthSigner<MockSignedTx, MockTxReq>> = Box::new(MockSigner);
72 let cloned: Box<dyn EthSigner<MockSignedTx, MockTxReq>> = dyn_clone::clone_box(&*signer);
73
74 assert!(cloned.accounts().is_empty());
75 }
76}