1use crate::Error;
4use proto::ethereum::{signer_server::Signer, SignDigestRequest, SignEip155Request, Signature};
5use signing::{
6 signature::{ecdsa::secp256k1::RecoverableSignature, hazmat::PrehashSigner},
7 KeyRing,
8};
9use tonic::{Request, Response, Status};
10use tracing::trace;
11use types::ethereum::Address;
12
13type H256 = [u8; 32];
15
16pub struct SignerService {
18 keyring: KeyRing,
20}
21
22impl SignerService {
23 pub fn new(keyring: KeyRing) -> Self {
25 Self { keyring }
26 }
27
28 fn sign_digest(&self, address: &str, digest: &[u8]) -> Result<Signature, Error> {
31 let address = address.parse::<Address>().map_err(Error::from)?;
32
33 let signing_key = self
34 .keyring
35 .find_by_eth_address(&address)
36 .map_err(Error::from)?;
37
38 let digest = H256::try_from(digest).map_err(|_| Error::DigestMalformed)?;
39 let signature: RecoverableSignature =
40 signing_key.sign_prehash(&digest).map_err(Error::from)?;
41
42 let r = signature.r().to_bytes().to_vec();
43 let s = signature.s().to_bytes().to_vec();
44 let v = u8::from(signature.recovery_id()) + 27;
45
46 Ok(Signature { r, s, v: v.into() })
47 }
48}
49
50#[tonic::async_trait]
51impl Signer for SignerService {
52 async fn sign_digest(
53 &self,
54 request: Request<SignDigestRequest>,
55 ) -> Result<Response<Signature>, Status> {
56 trace!("sign_digest[{:?}]: {:?}", request.remote_addr(), request);
57
58 let request = request.into_inner();
59 Ok(self
60 .sign_digest(&request.address, &request.digest)
61 .map(Response::new)
62 .map_err(Error::from)?)
63 }
64
65 async fn sign_eip155(
66 &self,
67 request: Request<SignEip155Request>,
68 ) -> Result<Response<Signature>, Status> {
69 trace!("sign_eip155[{:?}]: {:?}", request.remote_addr(), request);
70
71 let request = request.into_inner();
72 let mut signature = self
73 .sign_digest(&request.address, &request.digest)
74 .map_err(Error::from)?;
75
76 signature.v = (request.chain_id * 2 + 35) + ((signature.v - 1) % 2);
78 Ok(Response::new(signature))
79 }
80}