1use alloy_primitives::{Address, B256, Bytes, Signature, hex};
4use alloy_sol_types::SolType;
5use r402_core::error::VerificationError;
6use r402_core::wire::UnixTimestamp;
7#[cfg(feature = "telemetry")]
8use tracing::instrument;
9
10use crate::chain::contracts::Sig6492;
11
12const EIP6492_MAGIC_SUFFIX: [u8; 32] =
14 hex!("6492649264926492649264926492649264926492649264926492649264926492");
15
16#[derive(Debug, Clone)]
22pub(crate) enum StructuredSignature {
23 EIP6492 {
25 factory: Address,
26 factory_calldata: Bytes,
27 inner: Bytes,
28 original: Bytes,
29 },
30 Eoa(Signature),
32 EIP1271(Bytes),
34}
35
36#[derive(Debug, thiserror::Error)]
38pub enum StructuredSignatureFormatError {
39 #[error(transparent)]
41 InvalidEIP6492Format(alloy_sol_types::Error),
42}
43
44#[allow(
49 clippy::indexing_slicing,
50 reason = "bounds checked by len() >= 32 guard"
51)]
52fn decode_eip6492(
53 bytes: Bytes,
54) -> Result<Option<StructuredSignature>, StructuredSignatureFormatError> {
55 let has_suffix = bytes.len() >= 32 && bytes[bytes.len() - 32..] == EIP6492_MAGIC_SUFFIX;
56 if !has_suffix {
57 return Ok(None);
58 }
59 let body = &bytes[..bytes.len() - 32];
60 let sig6492 = Sig6492::abi_decode_params(body)
61 .map_err(StructuredSignatureFormatError::InvalidEIP6492Format)?;
62 Ok(Some(StructuredSignature::EIP6492 {
63 factory: sig6492.factory,
64 factory_calldata: sig6492.factoryCalldata,
65 inner: sig6492.innerSig,
66 original: bytes,
67 }))
68}
69
70impl StructuredSignature {
71 pub(crate) fn try_from_bytes(
72 bytes: Bytes,
73 expected_signer: Address,
74 prehash: &B256,
75 ) -> Result<Self, StructuredSignatureFormatError> {
76 if let Some(eip6492) = decode_eip6492(bytes.clone())? {
77 return Ok(eip6492);
78 }
79 let eoa_signature = if bytes.len() == 65 {
80 Signature::from_raw(&bytes)
81 .ok()
82 .map(Signature::normalized_s)
83 } else if bytes.len() == 64 {
84 Some(Signature::from_erc2098(&bytes).normalized_s())
85 } else {
86 None
87 };
88 let signature = match eoa_signature {
89 None => Self::EIP1271(bytes),
90 Some(s) => {
91 let is_expected_signer = s
92 .recover_address_from_prehash(prehash)
93 .is_ok_and(|r| r == expected_signer);
94 if is_expected_signer {
95 Self::Eoa(s)
96 } else {
97 Self::EIP1271(bytes)
98 }
99 }
100 };
101 Ok(signature)
102 }
103}
104
105#[cfg_attr(feature = "telemetry", instrument(skip_all, err))]
114pub(crate) fn assert_time(
115 valid_after: UnixTimestamp,
116 valid_before: UnixTimestamp,
117 clock_skew_tolerance: u64,
118) -> Result<(), VerificationError> {
119 let now = UnixTimestamp::now();
120 if valid_before < now + clock_skew_tolerance {
121 return Err(VerificationError::Expired);
122 }
123 if valid_after > now + clock_skew_tolerance {
124 return Err(VerificationError::Early);
125 }
126 Ok(())
127}