Skip to main content

hypercall_signer/
signature.rs

1use 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}