Skip to main content

nucypher_core/
signature_request.rs

1use alloc::boxed::Box;
2use alloc::string::{String, ToString};
3use alloc::vec::Vec;
4use alloc::{format, vec};
5use core::fmt;
6use core::str::FromStr;
7
8use ethers::abi::{encode, Token};
9use serde::{Deserialize, Serialize};
10use serde_json::Value as JsonValue;
11use sha3::{digest::Update, Digest, Keccak256};
12use umbral_pre::serde_bytes;
13
14use crate::address::Address;
15use crate::conditions::Context;
16use crate::prim_types::Uint256;
17use crate::session::{
18    decrypt_with_shared_secret, encrypt_with_shared_secret,
19    key::{SessionSharedSecret, SessionStaticKey},
20    DecryptionError,
21};
22use crate::versioning::{
23    messagepack_deserialize, messagepack_serialize, DeserializationError, ProtocolObject,
24    ProtocolObjectInner,
25};
26
27/// Enum for different signature types.
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
29#[serde(rename_all = "kebab-case")]
30pub enum SignatureRequestType {
31    /// UserOperation signature request
32    UserOp = 0,
33    /// Packed UserOperation signature request
34    PackedUserOp = 1,
35}
36
37impl SignatureRequestType {
38    /// Convert to u8
39    pub fn as_u8(&self) -> u8 {
40        *self as u8
41    }
42
43    /// Create from a u8
44    pub fn from_u8(i: u8) -> Result<Self, String> {
45        match i {
46            0 => Ok(Self::UserOp),
47            1 => Ok(Self::PackedUserOp),
48            _ => Err(format!("Invalid signature request type: {}", i)),
49        }
50    }
51}
52
53impl fmt::Display for SignatureRequestType {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        match self {
56            Self::UserOp => write!(f, "userop"),
57            Self::PackedUserOp => write!(f, "packedUserOp"),
58        }
59    }
60}
61
62/// AA v0.8.0 entryPoint address
63pub const ENTRYPOINT_V08: &str = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108";
64/// AA v0.7.0 entryPoint address
65pub const ENTRYPOINT_V07: &str = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
66
67/// AA version enum for Account Abstraction versions
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
69pub enum AAVersion {
70    /// Version 0.7.0
71    #[serde(rename = "0.7.0")]
72    V07,
73    /// Version 0.8.0
74    #[serde(rename = "0.8.0")]
75    V08,
76    /// MDT version
77    #[serde(rename = "mdt")]
78    MDT,
79}
80
81impl AAVersion {
82    /// Return the string representation
83    pub fn as_str(&self) -> &'static str {
84        match self {
85            Self::V07 => "0.7.0",
86            Self::V08 => "0.8.0",
87            Self::MDT => "mdt",
88        }
89    }
90}
91
92impl FromStr for AAVersion {
93    type Err = String;
94
95    fn from_str(s: &str) -> Result<Self, Self::Err> {
96        match s {
97            "0.7.0" => Ok(Self::V07),
98            "0.8.0" => Ok(Self::V08),
99            "mdt" => Ok(Self::MDT),
100            _ => Err(format!("Invalid AA version: {}", s)),
101        }
102    }
103}
104
105impl fmt::Display for AAVersion {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        match self {
108            Self::V07 => write!(f, "{}", Self::V07.as_str()),
109            Self::V08 => write!(f, "{}", Self::V08.as_str()),
110            Self::MDT => write!(f, "{}", Self::MDT.as_str()),
111        }
112    }
113}
114
115/// Base trait for signature requests
116pub trait BaseSignatureRequest: Serialize + for<'de> Deserialize<'de> {
117    /// Returns the cohort ID for this signature request
118    fn cohort_id(&self) -> u32;
119    /// Returns the chain ID for this signature request
120    fn chain_id(&self) -> u64;
121    /// Returns the signature type for this signature request
122    fn signature_type(&self) -> SignatureRequestType;
123    /// Returns the optional context for this signature request
124    fn context(&self) -> Option<&Context>;
125    /// Encrypts the signature request.
126    fn encrypt(
127        &self,
128        shared_secret: &SessionSharedSecret,
129        requester_public_key: &SessionStaticKey,
130    ) -> EncryptedThresholdSignatureRequest;
131}
132
133/// UserOperation for signature requests - https://eips.ethereum.org/EIPS/eip-4337
134#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
135pub struct UserOperation {
136    /// Address of the sender (smart contract account)
137    pub sender: Address,
138    /// Nonce for replay protection
139    pub nonce: Uint256,
140    /// The calldata to execute
141    #[serde(with = "serde_bytes::as_base64")]
142    pub call_data: Box<[u8]>,
143    /// Gas limit for the call
144    pub call_gas_limit: u128,
145    /// Gas limit for verification
146    pub verification_gas_limit: u128,
147    /// Gas to cover overhead
148    pub pre_verification_gas: u128,
149    /// Maximum fee per gas unit
150    pub max_fee_per_gas: u128,
151    /// Maximum priority fee per gas unit
152    pub max_priority_fee_per_gas: u128,
153    /// Address of factory contract for account creation (optional)
154    pub factory: Option<Address>,
155    /// Data for factory contract account creation (optional); can't use base64 due to optionality
156    pub factory_data: Option<Box<[u8]>>,
157    /// Paymaster address (optional)
158    pub paymaster: Option<Address>,
159    /// Gas limit for paymaster verification (optional)
160    pub paymaster_verification_gas_limit: Option<u128>,
161    /// Gas limit for paymaster post-operation (optional)
162    pub paymaster_post_op_gas_limit: Option<u128>,
163    /// Paymaster-specific data (optional); can't use base64 due to optionality
164    pub paymaster_data: Option<Box<[u8]>>,
165}
166
167impl UserOperation {
168    /// Creates a new UserOperation
169    #[allow(clippy::too_many_arguments)]
170    pub fn new(
171        sender: Address,
172        nonce: Uint256,
173        call_data: &[u8],
174        call_gas_limit: u128,
175        verification_gas_limit: u128,
176        pre_verification_gas: u128,
177        max_fee_per_gas: u128,
178        max_priority_fee_per_gas: u128,
179        factory: Option<Address>,
180        factory_data: Option<&[u8]>,
181        paymaster: Option<Address>,
182        paymaster_verification_gas_limit: Option<u128>,
183        paymaster_post_op_gas_limit: Option<u128>,
184        paymaster_data: Option<&[u8]>,
185    ) -> Self {
186        Self {
187            sender,
188            nonce,
189            call_data: call_data.to_vec().into_boxed_slice(),
190            call_gas_limit,
191            verification_gas_limit,
192            pre_verification_gas,
193            max_fee_per_gas,
194            max_priority_fee_per_gas,
195            factory,
196            factory_data: factory_data.map(|data| data.to_vec().into_boxed_slice()),
197            paymaster,
198            paymaster_verification_gas_limit,
199            paymaster_post_op_gas_limit,
200            paymaster_data: paymaster_data.map(|data| data.to_vec().into_boxed_slice()),
201        }
202    }
203}
204
205/// UserOperation signature request
206#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
207pub struct UserOperationSignatureRequest {
208    /// User operation to sign
209    pub user_op: UserOperation,
210    /// Cohort ID
211    pub cohort_id: u32,
212    /// Chain ID
213    pub chain_id: u64,
214    /// AA version
215    pub aa_version: AAVersion,
216    /// Optional context
217    pub context: Option<Context>,
218    /// Signature type (always UserOp)
219    pub signature_type: SignatureRequestType,
220}
221
222impl UserOperationSignatureRequest {
223    /// Creates a new UserOperation signature request
224    pub fn new(
225        user_op: UserOperation,
226        cohort_id: u32,
227        chain_id: u64,
228        aa_version: AAVersion,
229        context: Option<&Context>,
230    ) -> Self {
231        Self {
232            user_op,
233            cohort_id,
234            chain_id,
235            aa_version,
236            context: context.cloned(),
237            signature_type: SignatureRequestType::UserOp,
238        }
239    }
240}
241
242impl BaseSignatureRequest for UserOperationSignatureRequest {
243    fn cohort_id(&self) -> u32 {
244        self.cohort_id
245    }
246
247    fn chain_id(&self) -> u64 {
248        self.chain_id
249    }
250
251    fn signature_type(&self) -> SignatureRequestType {
252        self.signature_type
253    }
254
255    fn context(&self) -> Option<&Context> {
256        self.context.as_ref()
257    }
258
259    fn encrypt(
260        &self,
261        shared_secret: &SessionSharedSecret,
262        requester_public_key: &SessionStaticKey,
263    ) -> EncryptedThresholdSignatureRequest {
264        EncryptedThresholdSignatureRequest::new(
265            &DirectSignatureRequest::UserOp(self.clone()),
266            shared_secret,
267            requester_public_key,
268        )
269    }
270}
271
272/// Packed UserOperation for signature requests
273#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
274pub struct PackedUserOperation {
275    /// Address of the sender (smart contract account)
276    pub sender: Address,
277    /// Nonce for replay protection
278    pub nonce: Uint256,
279    /// Factory and data for account creation
280    #[serde(with = "serde_bytes::as_base64")]
281    pub init_code: Box<[u8]>,
282    /// The calldata to execute
283    #[serde(with = "serde_bytes::as_base64")]
284    pub call_data: Box<[u8]>,
285    /// Packed gas limits (verification gas limit << 128 | call gas limit)
286    #[serde(with = "serde_bytes::as_base64")]
287    pub account_gas_limits: Box<[u8]>,
288    /// Gas to cover overhead
289    pub pre_verification_gas: u128,
290    /// Packed gas fees (max priority fee << 128 | max fee)
291    #[serde(with = "serde_bytes::as_base64")]
292    pub gas_fees: Box<[u8]>,
293    /// Packed paymaster data (address, verification gas limit, post-op gas limit, data)
294    #[serde(with = "serde_bytes::as_base64")]
295    pub paymaster_and_data: Box<[u8]>,
296}
297
298impl PackedUserOperation {
299    /// Creates a new PackedUserOperation
300    #[allow(clippy::too_many_arguments)]
301    pub fn new(
302        sender: Address,
303        nonce: Uint256,
304        init_code: &[u8],
305        call_data: &[u8],
306        account_gas_limits: &[u8],
307        pre_verification_gas: u128,
308        gas_fees: &[u8],
309        paymaster_and_data: &[u8],
310    ) -> Self {
311        Self {
312            sender,
313            nonce,
314            init_code: init_code.to_vec().into_boxed_slice(),
315            call_data: call_data.to_vec().into_boxed_slice(),
316            account_gas_limits: account_gas_limits.to_vec().into_boxed_slice(),
317            pre_verification_gas,
318            gas_fees: gas_fees.to_vec().into_boxed_slice(),
319            paymaster_and_data: paymaster_and_data.to_vec().into_boxed_slice(),
320        }
321    }
322
323    /// Packs account gas limits into a 32-byte value (u128 verification_gas_limit << 128 | u128 call_gas_limit)
324    fn pack_account_gas_limits(call_gas_limit: u128, verification_gas_limit: u128) -> [u8; 32] {
325        let mut result = [0u8; 32];
326        // Pack as: verification_gas_limit << 128 | call_gas_limit
327        // Each value is u128, so verification goes in upper 16 bytes, call in lower 16 bytes
328        result[0..16].copy_from_slice(&verification_gas_limit.to_be_bytes());
329        result[16..32].copy_from_slice(&call_gas_limit.to_be_bytes());
330        result
331    }
332
333    /// Packs gas fees into a 32-byte value (u128 max_priority_fee_per_gas << 128 | u128 max_fee_per_gas)
334    fn pack_gas_fees(max_fee_per_gas: u128, max_priority_fee_per_gas: u128) -> [u8; 32] {
335        let mut result = [0u8; 32];
336        // Pack as: max_priority_fee_per_gas << 128 | max_fee_per_gas
337        // Each value is u128, so priority goes in upper 16 bytes, max_fee in lower 16 bytes
338        result[0..16].copy_from_slice(&max_priority_fee_per_gas.to_be_bytes());
339        result[16..32].copy_from_slice(&max_fee_per_gas.to_be_bytes());
340        result
341    }
342
343    /// Packs paymaster data with u128 gas limits
344    fn pack_paymaster_and_data(
345        paymaster: Option<&Address>,
346        paymaster_verification_gas_limit: Option<u128>,
347        paymaster_post_op_gas_limit: Option<u128>,
348        paymaster_data: Option<&[u8]>,
349    ) -> Vec<u8> {
350        match paymaster {
351            None => Vec::new(),
352            Some(addr) => {
353                let unwrapped_paymaster_data = match paymaster_data {
354                    None => &[][..],
355                    Some(data) => data,
356                };
357                let mut result = Vec::with_capacity(20 + 16 + 16 + unwrapped_paymaster_data.len());
358                result.extend_from_slice(addr.as_ref());
359
360                // Verification gas limit as 16 bytes big-endian (full u128)
361                result.extend_from_slice(
362                    &paymaster_verification_gas_limit.unwrap_or(0).to_be_bytes(),
363                );
364
365                // Post-op gas limit as 16 bytes big-endian (full u128)
366                result.extend_from_slice(&paymaster_post_op_gas_limit.unwrap_or(0).to_be_bytes());
367
368                result.extend_from_slice(unwrapped_paymaster_data);
369                result
370            }
371        }
372    }
373
374    fn pack_init_code(factory: Option<&Address>, factory_data: Option<&[u8]>) -> Vec<u8> {
375        match factory {
376            None => Vec::new(),
377            Some(addr) => {
378                let unwrapped_factory_data = match factory_data {
379                    None => &[][..],
380                    Some(data) => data,
381                };
382                let mut result = Vec::with_capacity(20 + unwrapped_factory_data.len());
383                result.extend_from_slice(addr.as_ref());
384                result.extend_from_slice(unwrapped_factory_data.as_ref());
385                result
386            }
387        }
388    }
389
390    /// Creates a PackedUserOperation from a UserOperation
391    pub fn from_user_operation(user_op: &UserOperation) -> Self {
392        let account_gas_limits =
393            Self::pack_account_gas_limits(user_op.call_gas_limit, user_op.verification_gas_limit);
394
395        let gas_fees =
396            Self::pack_gas_fees(user_op.max_fee_per_gas, user_op.max_priority_fee_per_gas);
397
398        let paymaster_and_data = Self::pack_paymaster_and_data(
399            user_op.paymaster.as_ref(),
400            user_op.paymaster_verification_gas_limit,
401            user_op.paymaster_post_op_gas_limit,
402            user_op.paymaster_data.as_ref().map(|data| data.as_ref()),
403        );
404
405        let init_code = Self::pack_init_code(
406            user_op.factory.as_ref(),
407            user_op.factory_data.as_ref().map(|data| data.as_ref()),
408        );
409
410        Self {
411            sender: user_op.sender,
412            nonce: user_op.nonce.clone(),
413            init_code: init_code.to_vec().into_boxed_slice(),
414            call_data: user_op.call_data.clone(),
415            account_gas_limits: account_gas_limits.to_vec().into_boxed_slice(),
416            pre_verification_gas: user_op.pre_verification_gas,
417            gas_fees: gas_fees.to_vec().into_boxed_slice(),
418            paymaster_and_data: paymaster_and_data.into_boxed_slice(),
419        }
420    }
421
422    /// Converts to EIP-712 message format
423    pub fn to_eip712_message(&self, aa_version: &AAVersion) -> serde_json::Map<String, JsonValue> {
424        let mut message = serde_json::Map::new();
425        message.insert(
426            "sender".into(),
427            JsonValue::String(format!("0x{}", hex::encode(self.sender.as_ref()))),
428        );
429
430        // Convert U256 nonce to decimal string for JSON representation (since JsonNumber does not provide sufficient precision)
431        message.insert("nonce".into(), JsonValue::String(self.nonce.to_string()));
432
433        message.insert(
434            "initCode".into(),
435            JsonValue::String(format!("0x{}", hex::encode(&self.init_code))),
436        );
437        message.insert(
438            "callData".into(),
439            JsonValue::String(format!("0x{}", hex::encode(&self.call_data))),
440        );
441        message.insert(
442            "accountGasLimits".into(),
443            JsonValue::String(format!("0x{}", hex::encode(&self.account_gas_limits))),
444        );
445        message.insert(
446            "preVerificationGas".into(),
447            JsonValue::String(self.pre_verification_gas.to_string()),
448        );
449        message.insert(
450            "gasFees".into(),
451            JsonValue::String(format!("0x{}", hex::encode(&self.gas_fees))),
452        );
453        message.insert(
454            "paymasterAndData".into(),
455            JsonValue::String(format!("0x{}", hex::encode(&self.paymaster_and_data))),
456        );
457
458        if *aa_version == AAVersion::MDT {
459            message.insert(
460                "entryPoint".into(),
461                JsonValue::String(ENTRYPOINT_V07.into()),
462            );
463        }
464
465        message
466    }
467
468    /// Gets the EIP-712 domain
469    pub fn get_domain(
470        &self,
471        aa_version: &AAVersion,
472        chain_id: u64,
473    ) -> serde_json::Map<String, JsonValue> {
474        let mut domain = serde_json::Map::new();
475
476        let name = if *aa_version != AAVersion::MDT {
477            "ERC4337"
478        } else {
479            "MultiSigDeleGator"
480        };
481        domain.insert("name".into(), JsonValue::String(name.into()));
482        domain.insert("version".into(), JsonValue::String("1".into()));
483        domain.insert("chainId".into(), JsonValue::Number(chain_id.into()));
484
485        let verifying_contract = if *aa_version != AAVersion::MDT {
486            ENTRYPOINT_V08.into()
487        } else {
488            format!("0x{}", hex::encode(self.sender.as_ref()))
489        };
490        domain.insert(
491            "verifyingContract".into(),
492            JsonValue::String(verifying_contract),
493        );
494
495        domain
496    }
497
498    /// Converts to EIP-712 struct format
499    pub fn to_eip712_struct(
500        &self,
501        aa_version: &AAVersion,
502        chain_id: u64,
503    ) -> Result<serde_json::Map<String, JsonValue>, String> {
504        if *aa_version == AAVersion::V07 {
505            return Err(
506                "Not supported for AA v0.7.0 since it does not use EIP-712 signatures".into(),
507            );
508        }
509
510        let mut result = serde_json::Map::new();
511
512        // Create types
513        let mut types = serde_json::Map::new();
514
515        // EIP712Domain type
516        let mut domain_type = Vec::new();
517        let mut name_field = serde_json::Map::new();
518        name_field.insert("name".into(), JsonValue::String("name".into()));
519        name_field.insert("type".into(), JsonValue::String("string".into()));
520        domain_type.push(JsonValue::Object(name_field));
521
522        let mut version_field = serde_json::Map::new();
523        version_field.insert("name".into(), JsonValue::String("version".into()));
524        version_field.insert("type".into(), JsonValue::String("string".into()));
525        domain_type.push(JsonValue::Object(version_field));
526
527        let mut chain_id_field = serde_json::Map::new();
528        chain_id_field.insert("name".into(), JsonValue::String("chainId".into()));
529        chain_id_field.insert("type".into(), JsonValue::String("uint256".into()));
530        domain_type.push(JsonValue::Object(chain_id_field));
531
532        let mut verifying_contract_field = serde_json::Map::new();
533        verifying_contract_field
534            .insert("name".into(), JsonValue::String("verifyingContract".into()));
535        verifying_contract_field.insert("type".into(), JsonValue::String("address".into()));
536        domain_type.push(JsonValue::Object(verifying_contract_field));
537
538        types.insert("EIP712Domain".into(), JsonValue::Array(domain_type));
539
540        // PackedUserOperation type
541        let mut packed_user_op_type = Vec::new();
542
543        let field_specs = vec![
544            ("sender", "address"),
545            ("nonce", "uint256"),
546            ("initCode", "bytes"),
547            ("callData", "bytes"),
548            ("accountGasLimits", "bytes32"),
549            ("preVerificationGas", "uint256"),
550            ("gasFees", "bytes32"),
551            ("paymasterAndData", "bytes"),
552        ];
553
554        for (name, type_str) in field_specs {
555            let mut field = serde_json::Map::new();
556            field.insert("name".into(), JsonValue::String(name.into()));
557            field.insert("type".into(), JsonValue::String(type_str.into()));
558            packed_user_op_type.push(JsonValue::Object(field));
559        }
560
561        if *aa_version == AAVersion::MDT {
562            let mut entry_point_field = serde_json::Map::new();
563            entry_point_field.insert("name".into(), JsonValue::String("entryPoint".into()));
564            entry_point_field.insert("type".into(), JsonValue::String("address".into()));
565            packed_user_op_type.push(JsonValue::Object(entry_point_field));
566        }
567
568        types.insert(
569            "PackedUserOperation".into(),
570            JsonValue::Array(packed_user_op_type),
571        );
572
573        // Build final result
574        result.insert("types".into(), JsonValue::Object(types));
575        result.insert(
576            "primaryType".into(),
577            JsonValue::String("PackedUserOperation".into()),
578        );
579        result.insert(
580            "domain".into(),
581            JsonValue::Object(self.get_domain(aa_version, chain_id)),
582        );
583        result.insert(
584            "message".into(),
585            JsonValue::Object(self.to_eip712_message(aa_version)),
586        );
587
588        Ok(result)
589    }
590
591    /// Converts PackedUserOperation fields to ABI encoded data format
592    pub fn to_v07_abi_encoded_fields(&self) -> Vec<u8> {
593        // ABI encode PackedUserOperation values for V07 entryPoint
594        let init_code_hash = Keccak256::new().chain(self.init_code.as_ref()).finalize();
595        let call_data_hash = Keccak256::new().chain(self.call_data.as_ref()).finalize();
596        let paymaster_and_data_hash = Keccak256::new()
597            .chain(self.paymaster_and_data.as_ref())
598            .finalize();
599
600        let tokens = vec![
601            Token::Address(ethers::types::H160::from_slice(self.sender.as_ref())),
602            Token::Uint(ethers::types::U256::from_big_endian(
603                &self.nonce.to_be_bytes(),
604            )),
605            Token::FixedBytes(init_code_hash.to_vec()),
606            Token::FixedBytes(call_data_hash.to_vec()),
607            Token::FixedBytes(self.account_gas_limits.as_ref().to_vec()),
608            Token::Uint(ethers::types::U256::from(self.pre_verification_gas)),
609            Token::FixedBytes(self.gas_fees.as_ref().to_vec()),
610            Token::FixedBytes(paymaster_and_data_hash.to_vec()),
611        ];
612        encode(&tokens)
613    }
614
615    /// Converts to AA v07 encoded data format
616    pub fn to_v07_hash(&self, chain_id: u64) -> Vec<u8> {
617        let hashed_packed_user_op = Keccak256::new()
618            .chain(self.to_v07_abi_encoded_fields())
619            .finalize()
620            .to_vec();
621        let tokens = vec![
622            Token::FixedBytes(hashed_packed_user_op),
623            Token::Address(ethers::types::H160::from_slice(
624                Address::from_str(ENTRYPOINT_V07)
625                    .expect("Invalid entry point address")
626                    .as_ref(),
627            )),
628            Token::Uint(ethers::types::U256::from(chain_id)),
629        ];
630        Keccak256::new().chain(encode(&tokens)).finalize().to_vec()
631    }
632}
633
634/// Packed UserOperation signature request
635#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
636pub struct PackedUserOperationSignatureRequest {
637    /// Packed user operation to sign
638    pub packed_user_op: PackedUserOperation,
639    /// Cohort ID
640    pub cohort_id: u32,
641    /// Chain ID
642    pub chain_id: u64,
643    /// AA version
644    pub aa_version: AAVersion,
645    /// Optional context
646    pub context: Option<Context>,
647    /// Signature type (always PackedUserOp)
648    pub signature_type: SignatureRequestType,
649}
650
651impl PackedUserOperationSignatureRequest {
652    /// Creates a new PackedUserOperation signature request
653    pub fn new(
654        packed_user_op: PackedUserOperation,
655        cohort_id: u32,
656        chain_id: u64,
657        aa_version: AAVersion,
658        context: Option<&Context>,
659    ) -> Self {
660        Self {
661            packed_user_op,
662            cohort_id,
663            chain_id,
664            aa_version,
665            context: context.cloned(),
666            signature_type: SignatureRequestType::PackedUserOp,
667        }
668    }
669}
670
671impl BaseSignatureRequest for PackedUserOperationSignatureRequest {
672    fn cohort_id(&self) -> u32 {
673        self.cohort_id
674    }
675
676    fn chain_id(&self) -> u64 {
677        self.chain_id
678    }
679
680    fn signature_type(&self) -> SignatureRequestType {
681        self.signature_type
682    }
683
684    fn context(&self) -> Option<&Context> {
685        self.context.as_ref()
686    }
687
688    fn encrypt(
689        &self,
690        shared_secret: &SessionSharedSecret,
691        requester_public_key: &SessionStaticKey,
692    ) -> EncryptedThresholdSignatureRequest {
693        EncryptedThresholdSignatureRequest::new(
694            &DirectSignatureRequest::PackedUserOp(self.clone()),
695            shared_secret,
696            requester_public_key,
697        )
698    }
699}
700
701/// Signature response
702#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
703pub struct SignatureResponse {
704    /// Signer
705    pub signer: Address,
706    /// Message hash
707    #[serde(rename = "message_hash", with = "serde_bytes::as_base64")]
708    pub hash: Box<[u8]>,
709    /// Signature
710    #[serde(with = "serde_bytes::as_base64")]
711    pub signature: Box<[u8]>,
712    /// Signature type
713    pub signature_type: SignatureRequestType,
714}
715
716impl SignatureResponse {
717    /// Creates a new signature response
718    pub fn new(
719        signer: Address,
720        hash: &[u8],
721        signature: &[u8],
722        signature_type: SignatureRequestType,
723    ) -> Self {
724        Self {
725            signer,
726            hash: hash.to_vec().into_boxed_slice(),
727            signature: signature.to_vec().into_boxed_slice(),
728            signature_type,
729        }
730    }
731
732    /// Encrypts the signature response.
733    pub fn encrypt(
734        &self,
735        shared_secret: &SessionSharedSecret,
736    ) -> EncryptedThresholdSignatureResponse {
737        EncryptedThresholdSignatureResponse::new(self, shared_secret)
738    }
739}
740
741// ProtocolObject implementations
742
743impl<'a> ProtocolObjectInner<'a> for UserOperationSignatureRequest {
744    fn brand() -> [u8; 4] {
745        *b"UOSR"
746    }
747
748    fn version() -> (u16, u16) {
749        (1, 0)
750    }
751
752    fn unversioned_to_bytes(&self) -> Box<[u8]> {
753        messagepack_serialize(&self)
754    }
755
756    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
757        if minor_version == 0 {
758            Some(messagepack_deserialize(bytes))
759        } else {
760            None
761        }
762    }
763}
764
765impl<'a> ProtocolObject<'a> for UserOperationSignatureRequest {}
766
767impl<'a> ProtocolObjectInner<'a> for PackedUserOperationSignatureRequest {
768    fn brand() -> [u8; 4] {
769        *b"PUOS"
770    }
771
772    fn version() -> (u16, u16) {
773        (1, 0)
774    }
775
776    fn unversioned_to_bytes(&self) -> Box<[u8]> {
777        messagepack_serialize(&self)
778    }
779
780    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
781        if minor_version == 0 {
782            Some(messagepack_deserialize(bytes))
783        } else {
784            None
785        }
786    }
787}
788
789impl<'a> ProtocolObject<'a> for PackedUserOperationSignatureRequest {}
790
791impl<'a> ProtocolObjectInner<'a> for SignatureResponse {
792    fn brand() -> [u8; 4] {
793        *b"SigR"
794    }
795
796    fn version() -> (u16, u16) {
797        (1, 0)
798    }
799
800    fn unversioned_to_bytes(&self) -> Box<[u8]> {
801        messagepack_serialize(&self)
802    }
803
804    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
805        if minor_version == 0 {
806            Some(messagepack_deserialize(bytes))
807        } else {
808            None
809        }
810    }
811}
812
813impl<'a> ProtocolObject<'a> for SignatureResponse {}
814
815impl<'a> ProtocolObjectInner<'a> for UserOperation {
816    fn brand() -> [u8; 4] {
817        *b"UOPR"
818    }
819
820    fn version() -> (u16, u16) {
821        (1, 0)
822    }
823
824    fn unversioned_to_bytes(&self) -> Box<[u8]> {
825        messagepack_serialize(&self)
826    }
827
828    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
829        if minor_version == 0 {
830            Some(messagepack_deserialize(bytes))
831        } else {
832            None
833        }
834    }
835}
836
837impl<'a> ProtocolObject<'a> for UserOperation {}
838
839impl<'a> ProtocolObjectInner<'a> for PackedUserOperation {
840    fn brand() -> [u8; 4] {
841        *b"PUOP"
842    }
843
844    fn version() -> (u16, u16) {
845        (1, 0)
846    }
847
848    fn unversioned_to_bytes(&self) -> Box<[u8]> {
849        messagepack_serialize(&self)
850    }
851
852    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
853        if minor_version == 0 {
854            Some(messagepack_deserialize(bytes))
855        } else {
856            None
857        }
858    }
859}
860
861impl<'a> ProtocolObject<'a> for PackedUserOperation {}
862
863/// Enum to hold any type of signature request for direct returns
864#[derive(Debug, Clone, PartialEq, Eq)]
865pub enum DirectSignatureRequest {
866    /// UserOperation signature request
867    UserOp(UserOperationSignatureRequest),
868    /// PackedUserOperation signature request
869    PackedUserOp(PackedUserOperationSignatureRequest),
870}
871
872impl DirectSignatureRequest {
873    /// Deserialize any signature request from bytes by checking the brand identifier
874    pub fn from_bytes(bytes: &[u8]) -> Result<Self, String> {
875        if bytes.len() < 4 {
876            return Err("Insufficient bytes for brand identifier".into());
877        }
878
879        // Extract the 4-byte brand identifier
880        let brand = [bytes[0], bytes[1], bytes[2], bytes[3]];
881
882        match &brand {
883            b"UOSR" => UserOperationSignatureRequest::from_bytes(bytes)
884                .map(Self::UserOp)
885                .map_err(|e| format!("Failed to deserialize UserOperationSignatureRequest: {}", e)),
886            b"PUOS" => PackedUserOperationSignatureRequest::from_bytes(bytes)
887                .map(Self::PackedUserOp)
888                .map_err(|e| {
889                    format!(
890                        "Failed to deserialize PackedUserOperationSignatureRequest: {}",
891                        e
892                    )
893                }),
894            _ => Err(format!("Unknown signature request brand: {:?}", brand)),
895        }
896    }
897
898    /// Get the signature type for this request
899    pub fn signature_type(&self) -> SignatureRequestType {
900        match self {
901            Self::UserOp(req) => req.signature_type(),
902            Self::PackedUserOp(req) => req.signature_type(),
903        }
904    }
905
906    /// Get the cohort ID for this request
907    pub fn cohort_id(&self) -> u32 {
908        match self {
909            Self::UserOp(req) => req.cohort_id(),
910            Self::PackedUserOp(req) => req.cohort_id(),
911        }
912    }
913
914    /// Get the chain ID for this request
915    pub fn chain_id(&self) -> u64 {
916        match self {
917            Self::UserOp(req) => req.chain_id(),
918            Self::PackedUserOp(req) => req.chain_id(),
919        }
920    }
921
922    /// Get the optional context for this request
923    pub fn context(&self) -> Option<&Context> {
924        match self {
925            Self::UserOp(req) => req.context(),
926            Self::PackedUserOp(req) => req.context(),
927        }
928    }
929
930    /// Encrypts the signature request.
931    pub fn encrypt(
932        &self,
933        shared_secret: &SessionSharedSecret,
934        requester_public_key: &SessionStaticKey,
935    ) -> EncryptedThresholdSignatureRequest {
936        match self {
937            Self::UserOp(req) => req.encrypt(shared_secret, requester_public_key),
938            Self::PackedUserOp(req) => req.encrypt(shared_secret, requester_public_key),
939        }
940    }
941}
942
943/// Utility function to deserialize any signature request from bytes
944pub fn deserialize_signature_request(bytes: &[u8]) -> Result<DirectSignatureRequest, String> {
945    DirectSignatureRequest::from_bytes(bytes)
946}
947
948/// Utility function to serialize any signature request from bytes
949pub fn serialize_signature_request(request: &DirectSignatureRequest) -> Box<[u8]> {
950    match request {
951        DirectSignatureRequest::UserOp(req) => req.to_bytes(),
952        DirectSignatureRequest::PackedUserOp(req) => req.to_bytes(),
953    }
954}
955
956/// An encrypted signature request for Ursula to process and sign.
957#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
958pub struct EncryptedThresholdSignatureRequest {
959    /// ID of the cohort
960    pub cohort_id: u32,
961
962    /// Public key of requester
963    pub requester_public_key: SessionStaticKey,
964
965    #[serde(with = "serde_bytes::as_base64")]
966    /// Encrypted request
967    ciphertext: Box<[u8]>,
968}
969
970impl EncryptedThresholdSignatureRequest {
971    fn new(
972        request: &DirectSignatureRequest,
973        shared_secret: &SessionSharedSecret,
974        requester_public_key: &SessionStaticKey,
975    ) -> Self {
976        let serialization_bytes = serialize_signature_request(request);
977        let ciphertext = encrypt_with_shared_secret(shared_secret, &serialization_bytes)
978            .expect("Encryption failed - out of memory?");
979        Self {
980            cohort_id: request.cohort_id(),
981            requester_public_key: *requester_public_key,
982            ciphertext,
983        }
984    }
985
986    /// Decrypts the decryption request
987    pub fn decrypt(
988        &self,
989        shared_secret: &SessionSharedSecret,
990    ) -> Result<DirectSignatureRequest, DecryptionError> {
991        let decryption_request_bytes = decrypt_with_shared_secret(shared_secret, &self.ciphertext)?;
992        let decryption_request =
993            deserialize_signature_request(&decryption_request_bytes).map_err(|err| {
994                DecryptionError::DeserializationFailed(DeserializationError::BadPayload {
995                    error_msg: err.to_string(),
996                })
997            })?;
998        Ok(decryption_request)
999    }
1000}
1001
1002impl<'a> ProtocolObjectInner<'a> for EncryptedThresholdSignatureRequest {
1003    fn version() -> (u16, u16) {
1004        (1, 0)
1005    }
1006
1007    fn brand() -> [u8; 4] {
1008        *b"ETSR"
1009    }
1010
1011    fn unversioned_to_bytes(&self) -> Box<[u8]> {
1012        messagepack_serialize(&self)
1013    }
1014
1015    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
1016        if minor_version == 0 {
1017            Some(messagepack_deserialize(bytes))
1018        } else {
1019            None
1020        }
1021    }
1022}
1023
1024impl<'a> ProtocolObject<'a> for EncryptedThresholdSignatureRequest {}
1025
1026/// An encrypted response from Ursula with a signature.
1027#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
1028pub struct EncryptedThresholdSignatureResponse {
1029    #[serde(with = "serde_bytes::as_base64")]
1030    ciphertext: Box<[u8]>,
1031}
1032
1033impl EncryptedThresholdSignatureResponse {
1034    fn new(response: &SignatureResponse, shared_secret: &SessionSharedSecret) -> Self {
1035        let ciphertext = encrypt_with_shared_secret(shared_secret, &response.to_bytes())
1036            .expect("Encryption failed - out of memory?");
1037        Self { ciphertext }
1038    }
1039
1040    /// Decrypts the decryption request
1041    pub fn decrypt(
1042        &self,
1043        shared_secret: &SessionSharedSecret,
1044    ) -> Result<SignatureResponse, DecryptionError> {
1045        let decryption_response_bytes =
1046            decrypt_with_shared_secret(shared_secret, &self.ciphertext)?;
1047        let decryption_response = SignatureResponse::from_bytes(&decryption_response_bytes)
1048            .map_err(DecryptionError::DeserializationFailed)?;
1049        Ok(decryption_response)
1050    }
1051}
1052
1053impl<'a> ProtocolObjectInner<'a> for EncryptedThresholdSignatureResponse {
1054    fn version() -> (u16, u16) {
1055        (1, 0)
1056    }
1057
1058    fn brand() -> [u8; 4] {
1059        *b"ETRe"
1060    }
1061
1062    fn unversioned_to_bytes(&self) -> Box<[u8]> {
1063        messagepack_serialize(&self)
1064    }
1065
1066    fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
1067        if minor_version == 0 {
1068            Some(messagepack_deserialize(bytes))
1069        } else {
1070            None
1071        }
1072    }
1073}
1074
1075impl<'a> ProtocolObject<'a> for EncryptedThresholdSignatureResponse {}
1076
1077#[cfg(test)]
1078mod tests {
1079    use super::*;
1080    use crate::session::key::SessionStaticSecret;
1081    use alloc::string::ToString;
1082
1083    #[test]
1084    fn test_signature_type() {
1085        assert_eq!(SignatureRequestType::UserOp.as_u8(), 0,);
1086        assert_eq!(SignatureRequestType::PackedUserOp.as_u8(), 1,);
1087
1088        assert_eq!(
1089            SignatureRequestType::from_u8(0).unwrap(),
1090            SignatureRequestType::UserOp,
1091        );
1092        assert_eq!(
1093            SignatureRequestType::from_u8(1).unwrap(),
1094            SignatureRequestType::PackedUserOp,
1095        );
1096
1097        let result = SignatureRequestType::from_u8(22);
1098        assert!(result
1099            .unwrap_err()
1100            .contains("Invalid signature request type"));
1101
1102        assert_eq!(SignatureRequestType::UserOp.to_string(), "userop",);
1103        assert_eq!(
1104            SignatureRequestType::PackedUserOp.to_string(),
1105            "packedUserOp",
1106        );
1107    }
1108
1109    #[test]
1110    fn test_aa_version() {
1111        assert_eq!(AAVersion::from_str("0.7.0").unwrap(), AAVersion::V07);
1112        assert_eq!(AAVersion::from_str("0.8.0").unwrap(), AAVersion::V08);
1113        assert_eq!(AAVersion::from_str("mdt").unwrap(), AAVersion::MDT);
1114
1115        let result = AAVersion::from_str("invalid_version");
1116        assert!(result.unwrap_err().contains("Invalid AA version"));
1117
1118        assert_eq!(AAVersion::V07.to_string(), "0.7.0",);
1119        assert_eq!(AAVersion::V08.to_string(), "0.8.0",);
1120        assert_eq!(AAVersion::MDT.to_string(), "mdt",);
1121    }
1122
1123    #[test]
1124    fn test_user_operation() {
1125        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1126        let paymaster =
1127            Some(Address::from_str("0xabcdefabcdefabcdefabcdefabcdefabcdefabcd").unwrap());
1128        let factory =
1129            Some(Address::from_str("0x12345678901234567890abcdefabcdefabcdefab").unwrap());
1130
1131        let user_op = UserOperation::new(
1132            sender,
1133            Uint256::from(42),
1134            b"call_data",
1135            100000,
1136            200000,
1137            50000,
1138            20_000_000_000, // 20 gwei
1139            1_000_000_000,  // 1 gwei
1140            factory,
1141            Some(b"factory_data"),
1142            paymaster,
1143            Some(300000),
1144            Some(100000),
1145            Some(b"paymaster_data"),
1146        );
1147
1148        assert_eq!(user_op.sender, sender);
1149        assert_eq!(user_op.nonce, Uint256::from(42));
1150        assert_eq!(user_op.call_data.as_ref(), b"call_data");
1151        assert_eq!(user_op.call_gas_limit, 100000);
1152        assert_eq!(user_op.verification_gas_limit, 200000);
1153        assert_eq!(user_op.pre_verification_gas, 50000);
1154        assert_eq!(user_op.max_fee_per_gas, 20_000_000_000);
1155        assert_eq!(user_op.max_priority_fee_per_gas, 1_000_000_000);
1156        assert_eq!(user_op.factory, factory);
1157        assert_eq!(
1158            user_op.factory_data.clone().unwrap(),
1159            b"factory_data".to_vec().into_boxed_slice()
1160        );
1161        assert_eq!(user_op.paymaster, paymaster);
1162        assert_eq!(user_op.paymaster_verification_gas_limit.unwrap(), 300000);
1163        assert_eq!(user_op.paymaster_post_op_gas_limit.unwrap(), 100000);
1164        assert_eq!(
1165            user_op.paymaster_data.clone().unwrap(),
1166            b"paymaster_data".to_vec().into_boxed_slice()
1167        );
1168
1169        let serialized_user_op = user_op.to_bytes();
1170        let deserialized_user_op = UserOperation::from_bytes(&serialized_user_op).unwrap();
1171        assert_eq!(user_op, deserialized_user_op);
1172    }
1173
1174    #[test]
1175    fn test_packed_user_operation() {
1176        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1177
1178        let packed_user_op = PackedUserOperation::new(
1179            sender,
1180            Uint256::from(42),
1181            b"init_code",
1182            b"call_data",
1183            b"account_gas_limits",
1184            50000,
1185            b"gas_fees",
1186            b"paymaster_and_data",
1187        );
1188        assert_eq!(packed_user_op.sender, sender);
1189        assert_eq!(packed_user_op.nonce, Uint256::from(42));
1190        assert_eq!(packed_user_op.init_code.as_ref(), b"init_code");
1191        assert_eq!(packed_user_op.call_data.as_ref(), b"call_data");
1192        assert_eq!(
1193            packed_user_op.account_gas_limits.as_ref(),
1194            b"account_gas_limits"
1195        );
1196        assert_eq!(packed_user_op.pre_verification_gas, 50000);
1197        assert_eq!(packed_user_op.gas_fees.as_ref(), b"gas_fees");
1198        assert_eq!(
1199            packed_user_op.paymaster_and_data.as_ref(),
1200            b"paymaster_and_data"
1201        );
1202
1203        let serialized_packed_user_op = packed_user_op.to_bytes();
1204        let deserialized_packed_user_op =
1205            PackedUserOperation::from_bytes(&serialized_packed_user_op).unwrap();
1206        assert_eq!(packed_user_op, deserialized_packed_user_op);
1207
1208        // pack account gas limits
1209        let packed_gas_limits = PackedUserOperation::pack_account_gas_limits(100000, 200000);
1210        let mut expected_gas_limits = [0u8; 32];
1211        expected_gas_limits[0..16].copy_from_slice(&200000u128.to_be_bytes());
1212        expected_gas_limits[16..32].copy_from_slice(&100000u128.to_be_bytes());
1213        assert_eq!(packed_gas_limits, expected_gas_limits);
1214
1215        // pack gas fees
1216        let packed_gas_fees = PackedUserOperation::pack_gas_fees(20_000_000_000, 1_000_000_000);
1217        let mut expected_gas_fees = [0u8; 32];
1218        expected_gas_fees[0..16].copy_from_slice(&1_000_000_000u128.to_be_bytes());
1219        expected_gas_fees[16..32].copy_from_slice(&20_000_000_000u128.to_be_bytes());
1220        assert_eq!(packed_gas_fees, expected_gas_fees);
1221
1222        // pack init code without factory data
1223        let packed_init_code = PackedUserOperation::pack_init_code(Some(&sender), None);
1224        assert_eq!(packed_init_code, sender.as_ref().to_vec());
1225
1226        // pack init code with factory data
1227        let packed_init_code_with_data =
1228            PackedUserOperation::pack_init_code(Some(&sender), Some(b"data"));
1229        let mut expected = sender.as_ref().to_vec();
1230        expected.extend_from_slice(b"data");
1231        assert_eq!(packed_init_code_with_data, expected);
1232
1233        // pack paymaster and data without paymaster_data
1234        let packed_paymaster_and_data = PackedUserOperation::pack_paymaster_and_data(
1235            Some(&sender),
1236            Some(300000),
1237            Some(100000),
1238            None,
1239        );
1240        let mut expected_paymaster = Vec::new();
1241        expected_paymaster.extend_from_slice(sender.as_ref());
1242        expected_paymaster.extend_from_slice(&300000u128.to_be_bytes());
1243        expected_paymaster.extend_from_slice(&100000u128.to_be_bytes());
1244        assert_eq!(packed_paymaster_and_data, expected_paymaster);
1245
1246        // pack paymaster and data with paymaster_data
1247        let packed_paymaster_and_data_with_data = PackedUserOperation::pack_paymaster_and_data(
1248            Some(&sender),
1249            Some(300000),
1250            Some(100000),
1251            Some(b"data"),
1252        );
1253        let mut expected_paymaster_with_data = Vec::new();
1254        expected_paymaster_with_data.extend_from_slice(sender.as_ref());
1255        expected_paymaster_with_data.extend_from_slice(&300000u128.to_be_bytes());
1256        expected_paymaster_with_data.extend_from_slice(&100000u128.to_be_bytes());
1257        expected_paymaster_with_data.extend_from_slice(b"data");
1258        assert_eq!(
1259            packed_paymaster_and_data_with_data,
1260            expected_paymaster_with_data
1261        );
1262    }
1263
1264    #[test]
1265    fn test_signature_response_serialization() {
1266        let signer = Address::from_str("0x789abcdef0123456789abcdef0123456789abcde").unwrap();
1267        let hash = b"test_hash";
1268        let signature = b"test_signature";
1269        let response =
1270            SignatureResponse::new(signer, hash, signature, SignatureRequestType::UserOp);
1271
1272        let bytes = response.to_bytes();
1273        let deserialized = SignatureResponse::from_bytes(&bytes).unwrap();
1274
1275        assert_eq!(response, deserialized);
1276        assert_eq!(deserialized.signer, signer);
1277        assert_eq!(deserialized.hash.as_ref(), hash);
1278        assert_eq!(deserialized.signature.as_ref(), signature);
1279        assert_eq!(deserialized.signature_type, SignatureRequestType::UserOp);
1280    }
1281
1282    #[test]
1283    fn test_aa_version_serialization() {
1284        // Test V08
1285        let sender = Address::from_str("0x789abcdef0123456789abcdef0123456789abcde").unwrap();
1286        let user_op = UserOperation::new(
1287            sender,
1288            Uint256::from(1),
1289            b"",
1290            0,
1291            0,
1292            0,
1293            0,
1294            0,
1295            None,
1296            Some(b""),
1297            None,
1298            Some(0),
1299            Some(0),
1300            Some(b""),
1301        );
1302        let request_v08 = UserOperationSignatureRequest::new(
1303            user_op,
1304            1,
1305            137,
1306            AAVersion::V08,
1307            Some(&Context::new("test_context")),
1308        );
1309
1310        let bytes = request_v08.to_bytes();
1311        let deserialized_v08 = UserOperationSignatureRequest::from_bytes(&bytes).unwrap();
1312        assert_eq!(deserialized_v08.aa_version, AAVersion::V08);
1313
1314        // Test V07
1315        let user_op = UserOperation::new(
1316            sender,
1317            Uint256::from(1),
1318            b"",
1319            0,
1320            0,
1321            0,
1322            0,
1323            0,
1324            None,
1325            Some(b""),
1326            None,
1327            Some(0),
1328            Some(0),
1329            Some(b""),
1330        );
1331        let request_v07 = UserOperationSignatureRequest::new(
1332            user_op,
1333            1,
1334            137,
1335            AAVersion::V07,
1336            Some(&Context::new("test_context")),
1337        );
1338
1339        let bytes = request_v07.to_bytes();
1340        let deserialized_v07 = UserOperationSignatureRequest::from_bytes(&bytes).unwrap();
1341        assert_eq!(deserialized_v07.aa_version, AAVersion::V07);
1342
1343        // Test MDT
1344        let sender_mdt = Address::from_str("0xabcdef0123456789abcdef0123456789abcdef01").unwrap();
1345        let user_op_mdt = UserOperation::new(
1346            sender_mdt,
1347            Uint256::from(2),
1348            b"call_data_mdt",
1349            0,
1350            0,
1351            0,
1352            0,
1353            0,
1354            // Optional fields
1355            None,
1356            None,
1357            None,
1358            None,
1359            None,
1360            None,
1361        );
1362        let request_mdt = UserOperationSignatureRequest::new(
1363            user_op_mdt,
1364            2,
1365            137,
1366            AAVersion::MDT,
1367            Some(&Context::new("test_context")),
1368        );
1369
1370        let bytes_mdt = request_mdt.to_bytes();
1371        let deserialized_mdt = UserOperationSignatureRequest::from_bytes(&bytes_mdt).unwrap();
1372        assert_eq!(deserialized_mdt.aa_version, AAVersion::MDT);
1373    }
1374
1375    #[test]
1376    fn test_packed_user_operation_conversion() {
1377        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1378        let paymaster =
1379            Some(Address::from_str("0xabcdefabcdefabcdefabcdefabcdefabcdefabcd").unwrap());
1380        let factory =
1381            Some(Address::from_str("0x12345678901234567890abcdefabcdefabcdefab").unwrap());
1382
1383        let user_op = UserOperation::new(
1384            sender,
1385            Uint256::from(100),
1386            b"execution_data",
1387            150000,
1388            250000,
1389            60000,
1390            30_000_000_000,
1391            2_000_000_000,
1392            factory,
1393            Some(b"factory_data"),
1394            paymaster,
1395            Some(400000),
1396            Some(200000),
1397            Some(b"paymaster_specific_data"),
1398        );
1399
1400        let packed = PackedUserOperation::from_user_operation(&user_op);
1401
1402        assert_eq!(packed.sender, user_op.sender);
1403        assert_eq!(packed.nonce, user_op.nonce);
1404        assert_eq!(packed.init_code.len(), 32);
1405        assert_eq!(packed.call_data, user_op.call_data);
1406        assert_eq!(packed.pre_verification_gas, user_op.pre_verification_gas);
1407
1408        // Check account gas limits packing
1409        assert_eq!(packed.account_gas_limits.len(), 32);
1410
1411        // Check gas fees packing
1412        assert_eq!(packed.gas_fees.len(), 32);
1413
1414        // Check paymaster data packing (20 bytes address + 16 bytes + 16 bytes + data)
1415        assert_eq!(
1416            packed.paymaster_and_data.len(),
1417            20 + 16 + 16 + b"paymaster_specific_data".len()
1418        );
1419    }
1420
1421    #[test]
1422    fn test_user_operation_signature_request_serialization() {
1423        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1424        let paymaster =
1425            Some(Address::from_str("0xabcdefabcdefabcdefabcdefabcdefabcdefabcd").unwrap());
1426        let factory =
1427            Some(Address::from_str("0x12345678901234567890abcdefabcdefabcdefab").unwrap());
1428        let cohort_id = 1;
1429        let chain_id = 137;
1430
1431        let user_op = UserOperation::new(
1432            sender,
1433            Uint256::from(42),
1434            b"call_data",
1435            100000,
1436            200000,
1437            50000,
1438            20_000_000_000, // 20 gwei
1439            1_000_000_000,  // 1 gwei
1440            factory,
1441            Some(b"factory_data"),
1442            paymaster,
1443            Some(300000),
1444            Some(100000),
1445            Some(b"paymaster_data"),
1446        );
1447        let request = UserOperationSignatureRequest::new(
1448            user_op,
1449            cohort_id,
1450            chain_id,
1451            AAVersion::V08,
1452            Some(&Context::new("test_context")),
1453        );
1454
1455        let bytes = request.to_bytes();
1456        let deserialized = UserOperationSignatureRequest::from_bytes(&bytes).unwrap();
1457
1458        assert_eq!(request, deserialized);
1459        assert_eq!(deserialized.user_op.sender, sender);
1460        assert_eq!(deserialized.user_op.nonce, Uint256::from(42));
1461        assert_eq!(deserialized.aa_version, AAVersion::V08);
1462        assert_eq!(deserialized.cohort_id, cohort_id);
1463        assert_eq!(deserialized.chain_id, chain_id);
1464        assert_eq!(
1465            deserialized.context.as_ref().unwrap().as_ref(),
1466            "test_context"
1467        );
1468
1469        // test DirectSignatureRequest deserialization
1470        let direct_request = DirectSignatureRequest::from_bytes(&bytes).unwrap();
1471        assert_eq!(direct_request, DirectSignatureRequest::UserOp(request));
1472        assert_eq!(
1473            direct_request.signature_type(),
1474            SignatureRequestType::UserOp
1475        );
1476        assert_eq!(direct_request.cohort_id(), cohort_id);
1477        assert_eq!(direct_request.chain_id(), chain_id);
1478        assert_eq!(direct_request.context().unwrap().as_ref(), "test_context");
1479    }
1480
1481    #[test]
1482    fn test_packed_user_operation_signature_request_serialization() {
1483        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1484        let cohort_id = 1;
1485        let chain_id = 137;
1486
1487        let packed_user_op = PackedUserOperation::new(
1488            sender,
1489            Uint256::from(42),
1490            b"init_code",
1491            b"call_data",
1492            b"account_gas_limits",
1493            50000,
1494            b"gas_fees",
1495            b"paymaster_and_data",
1496        );
1497        let request = PackedUserOperationSignatureRequest::new(
1498            packed_user_op,
1499            cohort_id,
1500            chain_id,
1501            AAVersion::V08,
1502            Some(&Context::new("test_context")),
1503        );
1504
1505        let bytes = request.to_bytes();
1506        let deserialized = PackedUserOperationSignatureRequest::from_bytes(&bytes).unwrap();
1507
1508        assert_eq!(request, deserialized);
1509        assert_eq!(deserialized.packed_user_op.sender, sender);
1510        assert_eq!(deserialized.packed_user_op.nonce, Uint256::from(42));
1511        assert_eq!(deserialized.aa_version, AAVersion::V08);
1512        assert_eq!(deserialized.cohort_id, cohort_id);
1513        assert_eq!(deserialized.chain_id, chain_id);
1514        assert_eq!(
1515            deserialized.context.as_ref().unwrap().as_ref(),
1516            "test_context"
1517        );
1518
1519        // test DirectSignatureRequest deserialization
1520        let direct_request = DirectSignatureRequest::from_bytes(&bytes).unwrap();
1521        assert_eq!(
1522            direct_request,
1523            DirectSignatureRequest::PackedUserOp(request)
1524        );
1525        assert_eq!(
1526            direct_request.signature_type(),
1527            SignatureRequestType::PackedUserOp
1528        );
1529        assert_eq!(direct_request.cohort_id(), cohort_id);
1530        assert_eq!(direct_request.chain_id(), chain_id);
1531        assert_eq!(direct_request.context().unwrap().as_ref(), "test_context");
1532    }
1533
1534    #[test]
1535    fn test_deserialize_signature_request_invalid_brand() {
1536        let invalid_bytes = b"XXXXinvalid_data";
1537        let result = deserialize_signature_request(invalid_bytes);
1538        assert!(result
1539            .unwrap_err()
1540            .contains("Unknown signature request brand"));
1541    }
1542
1543    fn validate_eip712_domain(
1544        eip712_domain: &serde_json::Map<String, JsonValue>,
1545        packed_user_op: &PackedUserOperation,
1546        is_v08: bool,
1547    ) {
1548        assert_eq!(eip712_domain.get("version").unwrap(), "1");
1549        assert_eq!(eip712_domain.get("chainId").unwrap(), 137);
1550        if is_v08 {
1551            assert_eq!(eip712_domain.get("name").unwrap(), "ERC4337");
1552            assert_eq!(
1553                eip712_domain.get("verifyingContract").unwrap(),
1554                ENTRYPOINT_V08
1555            );
1556        } else {
1557            assert_eq!(eip712_domain.get("name").unwrap(), "MultiSigDeleGator");
1558            assert_eq!(
1559                eip712_domain.get("verifyingContract").unwrap(),
1560                &JsonValue::String(packed_user_op.sender.to_checksum_address().to_string())
1561            );
1562        }
1563    }
1564
1565    fn validate_eip712_message(
1566        eip712_message: &serde_json::Map<String, JsonValue>,
1567        packed_user_op: &PackedUserOperation,
1568        is_v08: bool,
1569    ) {
1570        assert_eq!(
1571            eip712_message.get("sender").unwrap(),
1572            &JsonValue::String(packed_user_op.sender.to_checksum_address().to_string())
1573        );
1574        assert_eq!(
1575            eip712_message.get("nonce").unwrap(),
1576            &JsonValue::String(packed_user_op.nonce.to_string())
1577        );
1578        assert_eq!(
1579            eip712_message.get("initCode").unwrap(),
1580            &JsonValue::String(format!("0x{}", hex::encode(&packed_user_op.init_code)))
1581        );
1582        assert_eq!(
1583            eip712_message.get("callData").unwrap(),
1584            &JsonValue::String(format!("0x{}", hex::encode(&packed_user_op.call_data)))
1585        );
1586        assert_eq!(
1587            eip712_message.get("accountGasLimits").unwrap(),
1588            &JsonValue::String(format!(
1589                "0x{}",
1590                hex::encode(&packed_user_op.account_gas_limits)
1591            ))
1592        );
1593        assert_eq!(
1594            eip712_message.get("preVerificationGas").unwrap(),
1595            &JsonValue::String(format!("{}", packed_user_op.pre_verification_gas))
1596        );
1597        assert_eq!(
1598            eip712_message.get("gasFees").unwrap(),
1599            &JsonValue::String(format!("0x{}", hex::encode(&packed_user_op.gas_fees)))
1600        );
1601        assert_eq!(
1602            eip712_message.get("paymasterAndData").unwrap(),
1603            &JsonValue::String(format!(
1604                "0x{}",
1605                hex::encode(&packed_user_op.paymaster_and_data)
1606            ))
1607        );
1608
1609        if is_v08 {
1610            // V08 should NOT have entryPoint field
1611            assert!(eip712_message.get("entryPoint").is_none());
1612        } else {
1613            // MDT should have entryPoint field set to ENTRYPOINT_V07
1614            assert_eq!(
1615                eip712_message.get("entryPoint").unwrap(),
1616                &JsonValue::String(ENTRYPOINT_V07.into())
1617            );
1618        }
1619    }
1620
1621    fn validate_eip712_types(eip712_types: &serde_json::Map<String, JsonValue>, is_v08: bool) {
1622        // Validate PackedUserOperation type
1623        let packed_user_op_type = eip712_types
1624            .get("PackedUserOperation")
1625            .unwrap()
1626            .as_array()
1627            .unwrap();
1628        let expected_packed_user_op_fields = vec![
1629            ("sender", "address"),
1630            ("nonce", "uint256"),
1631            ("initCode", "bytes"),
1632            ("callData", "bytes"),
1633            ("accountGasLimits", "bytes32"),
1634            ("preVerificationGas", "uint256"),
1635            ("gasFees", "bytes32"),
1636            ("paymasterAndData", "bytes"),
1637            ("entryPoint", "address"),
1638        ];
1639        for (i, (field, field_type)) in expected_packed_user_op_fields.iter().enumerate() {
1640            if is_v08 && *field == "entryPoint" {
1641                // V08 should NOT have entryPoint field
1642                continue;
1643            }
1644            let field_obj = packed_user_op_type.get(i).unwrap().as_object().unwrap();
1645            assert_eq!(field_obj.get("name").unwrap(), field);
1646            assert_eq!(field_obj.get("type").unwrap(), field_type);
1647        }
1648    }
1649
1650    #[test]
1651    fn test_packed_user_operation_to_eip712_struct() {
1652        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1653        let packed_user_op = PackedUserOperation::new(
1654            sender,
1655            Uint256::from(42),
1656            b"init_code",
1657            b"call_data",
1658            b"account_gas_limits",
1659            50000,
1660            b"gas_fees",
1661            b"paymaster_and_data",
1662        );
1663
1664        // v07 which should error because v07 does not use EIP-712 structs for signing
1665        let eip712_struct_v07 = packed_user_op.to_eip712_struct(&AAVersion::V07, 137);
1666        assert!(eip712_struct_v07.is_err());
1667        assert!(eip712_struct_v07
1668            .unwrap_err()
1669            .contains("Not supported for AA v0.7.0 since it does not use EIP-712 signatures"));
1670
1671        // v08
1672        let eip712_struct_v08 = packed_user_op
1673            .to_eip712_struct(&AAVersion::V08, 137)
1674            .unwrap();
1675
1676        assert_eq!(
1677            eip712_struct_v08.get("primaryType").unwrap(),
1678            &JsonValue::String("PackedUserOperation".into())
1679        );
1680
1681        let v08_types = eip712_struct_v08.get("types").unwrap().as_object().unwrap();
1682        validate_eip712_types(&v08_types, true);
1683
1684        let v08_domain = eip712_struct_v08
1685            .get("domain")
1686            .unwrap()
1687            .as_object()
1688            .unwrap();
1689        validate_eip712_domain(&v08_domain, &packed_user_op, true);
1690        let v08_message = eip712_struct_v08.get("message").unwrap();
1691        validate_eip712_message(v08_message.as_object().unwrap(), &packed_user_op, true);
1692
1693        // mdt version
1694        let eip712_struct_mdt = packed_user_op
1695            .to_eip712_struct(&AAVersion::MDT, 137)
1696            .unwrap();
1697        assert_eq!(
1698            eip712_struct_mdt.get("primaryType").unwrap(),
1699            &JsonValue::String("PackedUserOperation".into())
1700        );
1701
1702        let mdt_types = eip712_struct_mdt.get("types").unwrap().as_object().unwrap();
1703        validate_eip712_types(&mdt_types, false);
1704
1705        let mdt_domain = eip712_struct_mdt
1706            .get("domain")
1707            .unwrap()
1708            .as_object()
1709            .unwrap();
1710        validate_eip712_domain(&mdt_domain, &packed_user_op, false);
1711        let mdt_message = eip712_struct_mdt.get("message").unwrap();
1712        validate_eip712_message(mdt_message.as_object().unwrap(), &packed_user_op, false);
1713    }
1714
1715    #[test]
1716    fn test_packed_user_operation_to_v07_abi_encoded_fields() {
1717        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1718        let packed_user_op = PackedUserOperation::new(
1719            sender,
1720            Uint256::from(42),
1721            b"init_code",
1722            b"call_data",
1723            b"account_gas_limits",
1724            50000,
1725            b"gas_fees",
1726            b"paymaster_and_data",
1727        );
1728
1729        let encoded_user_op = packed_user_op.to_v07_abi_encoded_fields();
1730
1731        // The encoded data should be the ABI encoding of the PackedUserOperation struct with the correct fields
1732        let decoded = ethers::abi::decode(
1733            &[
1734                ethers::abi::ParamType::Address,
1735                ethers::abi::ParamType::Uint(256),
1736                ethers::abi::ParamType::FixedBytes(32),
1737                ethers::abi::ParamType::FixedBytes(32),
1738                ethers::abi::ParamType::FixedBytes(32),
1739                ethers::abi::ParamType::Uint(256),
1740                ethers::abi::ParamType::FixedBytes(32),
1741                ethers::abi::ParamType::FixedBytes(32),
1742            ],
1743            &encoded_user_op,
1744        )
1745        .unwrap();
1746        assert_eq!(
1747            decoded[0].clone().into_address().unwrap(),
1748            ethers::types::H160::from_slice(packed_user_op.sender.as_ref())
1749        );
1750        assert_eq!(
1751            decoded[1].clone().into_uint().unwrap(),
1752            ethers::types::U256::from_big_endian(&packed_user_op.nonce.to_be_bytes(),)
1753        );
1754        assert_eq!(
1755            decoded[2].clone().into_fixed_bytes().unwrap(),
1756            Keccak256::digest(&packed_user_op.init_code).as_slice()
1757        );
1758        assert_eq!(
1759            decoded[3].clone().into_fixed_bytes().unwrap(),
1760            Keccak256::digest(&packed_user_op.call_data).as_slice()
1761        );
1762        let mut expected_account_gas_limits = packed_user_op.account_gas_limits.to_vec();
1763        expected_account_gas_limits.resize(32, 0); // pad to 32 bytes
1764        assert_eq!(
1765            decoded[4].clone().into_fixed_bytes().unwrap(),
1766            expected_account_gas_limits
1767        );
1768        assert_eq!(
1769            decoded[5].clone().into_uint().unwrap(),
1770            ethers::types::U256::from(50000)
1771        );
1772        let mut expected_gas_fees = packed_user_op.gas_fees.to_vec();
1773        expected_gas_fees.resize(32, 0); // pad to 32 bytes
1774        assert_eq!(
1775            decoded[6].clone().into_fixed_bytes().unwrap(),
1776            expected_gas_fees
1777        );
1778        assert_eq!(
1779            decoded[7].clone().into_fixed_bytes().unwrap(),
1780            Keccak256::digest(&packed_user_op.paymaster_and_data).as_slice()
1781        );
1782    }
1783
1784    #[test]
1785    fn test_packed_user_operation_to_v07_hash() {
1786        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1787        let packed_user_op = PackedUserOperation::new(
1788            sender,
1789            Uint256::from(42),
1790            b"init_code",
1791            b"call_data",
1792            b"account_gas_limits",
1793            50000,
1794            b"gas_fees",
1795            b"paymaster_and_data",
1796        );
1797
1798        let chain_id = 137;
1799
1800        let encoded_user_op = packed_user_op.to_v07_abi_encoded_fields();
1801        let v07_encoding = packed_user_op.to_v07_hash(chain_id);
1802
1803        let hashed_encoded_user_op = Keccak256::digest(&encoded_user_op);
1804
1805        // The v07 encoding should be the keccak256 hash of the ABI encoding, entry point address, and chain id
1806        let overall_tokens = vec![
1807            Token::FixedBytes(hashed_encoded_user_op.as_slice().to_vec()),
1808            Token::Address(ethers::types::H160::from_slice(
1809                Address::from_str(ENTRYPOINT_V07).unwrap().as_ref(),
1810            )),
1811            Token::Uint(ethers::types::U256::from(chain_id)),
1812        ];
1813        let expected_v07_encoding = Keccak256::digest(&encode(&overall_tokens));
1814        assert_eq!(expected_v07_encoding.as_slice(), v07_encoding.as_slice());
1815    }
1816
1817    #[test]
1818    fn test_encrypted_threshold_signing_request() {
1819        let sender = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1820        let cohort_id = 1;
1821        let chain_id = 137;
1822
1823        let user_op = UserOperation::new(
1824            sender,
1825            Uint256::from(100),
1826            b"execution_data",
1827            150000,
1828            250000,
1829            60000,
1830            30_000_000_000,
1831            2_000_000_000,
1832            None,
1833            None,
1834            None,
1835            None,
1836            None,
1837            None,
1838        );
1839        let user_op_request = UserOperationSignatureRequest::new(
1840            user_op.clone(),
1841            cohort_id,
1842            chain_id,
1843            AAVersion::V08,
1844            None,
1845        );
1846
1847        let packed_user_op = PackedUserOperation::from_user_operation(&user_op);
1848        let packed_user_op_request = PackedUserOperationSignatureRequest::new(
1849            packed_user_op,
1850            cohort_id,
1851            chain_id,
1852            AAVersion::MDT,
1853            None,
1854        );
1855
1856        // generate service and requester keys
1857        let service_secret = SessionStaticSecret::random();
1858
1859        let requester_secret = SessionStaticSecret::random();
1860        let requester_public_key = requester_secret.public_key();
1861
1862        // requester encrypts request to send to service
1863        let service_public_key = service_secret.public_key();
1864        let requester_shared_secret = requester_secret.derive_shared_secret(&service_public_key);
1865
1866        // test requests
1867        for request in [
1868            DirectSignatureRequest::UserOp(user_op_request),
1869            DirectSignatureRequest::PackedUserOp(packed_user_op_request),
1870        ] {
1871            let encrypted_request =
1872                request.encrypt(&requester_shared_secret, &requester_public_key);
1873
1874            // mimic serialization/deserialization over the wire
1875            let encrypted_request_bytes = encrypted_request.to_bytes();
1876            let encrypted_request_from_bytes =
1877                EncryptedThresholdSignatureRequest::from_bytes(&encrypted_request_bytes).unwrap();
1878
1879            assert_eq!(encrypted_request_from_bytes.cohort_id, cohort_id);
1880            assert_eq!(
1881                encrypted_request_from_bytes.requester_public_key,
1882                requester_public_key
1883            );
1884
1885            // service decrypts request
1886            let service_shared_secret = service_secret
1887                .derive_shared_secret(&encrypted_request_from_bytes.requester_public_key);
1888            let decrypted_request = encrypted_request_from_bytes
1889                .decrypt(&service_shared_secret)
1890                .unwrap();
1891            assert_eq!(decrypted_request, request);
1892
1893            // wrong shared key used
1894            let random_secret_key = SessionStaticSecret::random();
1895            let random_shared_secret =
1896                random_secret_key.derive_shared_secret(&requester_public_key);
1897            assert!(encrypted_request_from_bytes
1898                .decrypt(&random_shared_secret)
1899                .is_err());
1900        }
1901    }
1902
1903    #[test]
1904    fn test_encrypted_threshold_signing_response() {
1905        let service_secret = SessionStaticSecret::random();
1906        let requester_secret = SessionStaticSecret::random();
1907
1908        let signer = Address::from_str("0x1234567890123456789012345678901234567890").unwrap();
1909        let response = SignatureResponse::new(
1910            signer,
1911            b"response_hash",
1912            b"response_signature",
1913            SignatureRequestType::UserOp,
1914        );
1915
1916        // service encrypts response to send back
1917        let requester_public_key = requester_secret.public_key();
1918
1919        let service_shared_secret = service_secret.derive_shared_secret(&requester_public_key);
1920        let encrypted_response = response.encrypt(&service_shared_secret);
1921
1922        // mimic serialization/deserialization over the wire
1923        let encrypted_response_bytes = encrypted_response.to_bytes();
1924        let encrypted_response_from_bytes =
1925            EncryptedThresholdSignatureResponse::from_bytes(&encrypted_response_bytes).unwrap();
1926
1927        // requester decrypts response
1928        let service_public_key = service_secret.public_key();
1929        let requester_shared_secret = requester_secret.derive_shared_secret(&service_public_key);
1930        assert_eq!(
1931            requester_shared_secret.as_bytes(),
1932            service_shared_secret.as_bytes()
1933        );
1934        let decrypted_response = encrypted_response_from_bytes
1935            .decrypt(&requester_shared_secret)
1936            .unwrap();
1937        assert_eq!(response, decrypted_response);
1938        // just to be sure, check fields
1939        assert_eq!(decrypted_response.signature, response.signature);
1940        assert_eq!(decrypted_response.signer, response.signer);
1941        assert_eq!(decrypted_response.hash, response.hash);
1942        assert_eq!(decrypted_response.signature_type, response.signature_type);
1943
1944        // wrong shared key used
1945        let random_secret_key = SessionStaticSecret::random();
1946        let random_shared_secret = random_secret_key.derive_shared_secret(&requester_public_key);
1947        assert!(encrypted_response_from_bytes
1948            .decrypt(&random_shared_secret)
1949            .is_err());
1950    }
1951}