hypercall_signer/
signature.rs1use alloy::dyn_abi::TypedData;
2use hypercall_types::{directives, WalletAddress};
3
4use crate::RsmSignerError;
5
6pub fn verify_rsm_signature(
7 request_id: &str,
8 typed_data: &TypedData,
9 signature: &str,
10 expected: WalletAddress,
11 label: &str,
12) -> Result<(), RsmSignerError> {
13 let signature = decode_signature_hex(signature).map_err(|error| {
14 RsmSignerError::SigningFailed(format!(
15 "failed to decode signature for request {}: {}",
16 request_id, error
17 ))
18 })?;
19 verify_rsm_signature_bytes(request_id, typed_data, &signature, expected, label)
20}
21
22fn decode_signature_hex(signature: &str) -> Result<Vec<u8>, hex::FromHexError> {
23 hex::decode(signature.strip_prefix("0x").unwrap_or(signature))
24}
25
26pub fn verify_rsm_signature_bytes(
27 request_id: &str,
28 typed_data: &TypedData,
29 signature: &[u8],
30 expected: WalletAddress,
31 label: &str,
32) -> Result<(), RsmSignerError> {
33 let signing_hash = typed_data.eip712_signing_hash().map_err(|error| {
34 RsmSignerError::SigningFailed(format!(
35 "failed to compute typed-data signing hash: {}",
36 error
37 ))
38 })?;
39 let signing_hash_bytes: [u8; 32] = signing_hash.into();
40 let recovered =
41 directives::recover_address_from_signature_bytes(signature, &signing_hash_bytes).map_err(
42 |error| {
43 RsmSignerError::SigningFailed(format!(
44 "failed to recover signer for request {}: {}",
45 request_id, error
46 ))
47 },
48 )?;
49 if recovered != expected.inner() {
50 return Err(RsmSignerError::SigningFailed(format!(
51 "recovered signer {} does not match {} {}",
52 recovered, label, expected
53 )));
54 }
55 Ok(())
56}