1use crate::error::SignerError;
29use crate::ethereum::abi::{self, AbiValue};
30use sha3::{Digest, Keccak256};
31
32#[derive(Debug, Clone)]
39pub struct PackedUserOperation {
40 pub sender: [u8; 20],
42 pub nonce: [u8; 32],
44 pub init_code: Vec<u8>,
46 pub call_data: Vec<u8>,
48 pub account_gas_limits: [u8; 32],
50 pub pre_verification_gas: [u8; 32],
52 pub gas_fees: [u8; 32],
54 pub paymaster_and_data: Vec<u8>,
56 pub signature: Vec<u8>,
58}
59
60impl PackedUserOperation {
61 #[must_use]
65 pub fn pack(&self) -> Vec<u8> {
66 let mut buf = Vec::with_capacity(11 * 32);
67
68 buf.extend_from_slice(&pad_address(&self.sender));
71 buf.extend_from_slice(&self.nonce);
72 buf.extend_from_slice(&keccak256(&self.init_code));
73 buf.extend_from_slice(&keccak256(&self.call_data));
74 buf.extend_from_slice(&self.account_gas_limits);
75 buf.extend_from_slice(&self.pre_verification_gas);
76 buf.extend_from_slice(&self.gas_fees);
77 buf.extend_from_slice(&keccak256(&self.paymaster_and_data));
78
79 buf
80 }
81
82 #[must_use]
86 pub fn hash(&self, entry_point: &[u8; 20], chain_id: u64) -> [u8; 32] {
87 let packed_hash = keccak256(&self.pack());
88 let mut buf = Vec::with_capacity(3 * 32);
89 buf.extend_from_slice(&packed_hash);
90 buf.extend_from_slice(&pad_address(entry_point));
91 buf.extend_from_slice(&pad_u64(chain_id));
92 keccak256(&buf)
93 }
94
95 pub fn sign(
97 &self,
98 signer: &super::EthereumSigner,
99 entry_point: &[u8; 20],
100 chain_id: u64,
101 ) -> Result<super::EthereumSignature, SignerError> {
102 let hash = self.hash(entry_point, chain_id);
103 signer.sign_digest(&hash)
104 }
105
106 #[must_use]
110 pub fn pack_account_gas_limits(
111 verification_gas_limit: u128,
112 call_gas_limit: u128,
113 ) -> [u8; 32] {
114 let mut buf = [0u8; 32];
115 buf[..16].copy_from_slice(&verification_gas_limit.to_be_bytes());
116 buf[16..].copy_from_slice(&call_gas_limit.to_be_bytes());
117 buf
118 }
119
120 #[must_use]
122 pub fn unpack_account_gas_limits(packed: &[u8; 32]) -> (u128, u128) {
123 let mut vgl = [0u8; 16];
124 let mut cgl = [0u8; 16];
125 vgl.copy_from_slice(&packed[..16]);
126 cgl.copy_from_slice(&packed[16..]);
127 (u128::from_be_bytes(vgl), u128::from_be_bytes(cgl))
128 }
129
130 #[must_use]
134 pub fn pack_gas_fees(max_priority_fee: u128, max_fee: u128) -> [u8; 32] {
135 let mut buf = [0u8; 32];
136 buf[..16].copy_from_slice(&max_priority_fee.to_be_bytes());
137 buf[16..].copy_from_slice(&max_fee.to_be_bytes());
138 buf
139 }
140
141 #[must_use]
143 pub fn unpack_gas_fees(packed: &[u8; 32]) -> (u128, u128) {
144 let mut mpf = [0u8; 16];
145 let mut mf = [0u8; 16];
146 mpf.copy_from_slice(&packed[..16]);
147 mf.copy_from_slice(&packed[16..]);
148 (u128::from_be_bytes(mpf), u128::from_be_bytes(mf))
149 }
150}
151
152pub const ENTRY_POINT_V07: [u8; 20] = [
158 0x00, 0x00, 0x00, 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160];
161
162#[must_use]
166pub fn encode_handle_ops(
167 ops: &[PackedUserOperation],
168 beneficiary: [u8; 20],
169) -> Vec<u8> {
170 let func = abi::Function::new(
171 "handleOps((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)[],address)",
172 );
173
174 let op_tuples: Vec<AbiValue> = ops
175 .iter()
176 .map(|op| {
177 AbiValue::Tuple(vec![
178 AbiValue::Address(op.sender),
179 AbiValue::Uint256(op.nonce),
180 AbiValue::Bytes(op.init_code.clone()),
181 AbiValue::Bytes(op.call_data.clone()),
182 AbiValue::Uint256(op.account_gas_limits),
183 AbiValue::Uint256(op.pre_verification_gas),
184 AbiValue::Uint256(op.gas_fees),
185 AbiValue::Bytes(op.paymaster_and_data.clone()),
186 AbiValue::Bytes(op.signature.clone()),
187 ])
188 })
189 .collect();
190
191 func.encode(&[AbiValue::Array(op_tuples), AbiValue::Address(beneficiary)])
192}
193
194#[must_use]
200pub fn encode_paymaster_data(
201 paymaster: [u8; 20],
202 verification_gas_limit: u128,
203 post_op_gas_limit: u128,
204 data: &[u8],
205) -> Vec<u8> {
206 let mut buf = Vec::with_capacity(20 + 16 + 16 + data.len());
207 buf.extend_from_slice(&paymaster);
208 buf.extend_from_slice(&verification_gas_limit.to_be_bytes());
209 buf.extend_from_slice(&post_op_gas_limit.to_be_bytes());
210 buf.extend_from_slice(data);
211 buf
212}
213
214pub fn decode_paymaster_data(
218 encoded: &[u8],
219) -> Result<([u8; 20], u128, u128, Vec<u8>), SignerError> {
220 if encoded.len() < 52 {
221 return Err(SignerError::EncodingError(format!(
222 "paymasterAndData too short: {} bytes, need at least 52",
223 encoded.len()
224 )));
225 }
226 let mut paymaster = [0u8; 20];
227 paymaster.copy_from_slice(&encoded[..20]);
228
229 let mut vgl_bytes = [0u8; 16];
230 vgl_bytes.copy_from_slice(&encoded[20..36]);
231 let verification_gas_limit = u128::from_be_bytes(vgl_bytes);
232
233 let mut pogl_bytes = [0u8; 16];
234 pogl_bytes.copy_from_slice(&encoded[36..52]);
235 let post_op_gas_limit = u128::from_be_bytes(pogl_bytes);
236
237 let data = encoded[52..].to_vec();
238
239 Ok((paymaster, verification_gas_limit, post_op_gas_limit, data))
240}
241
242#[must_use]
248pub fn encode_execute(dest: [u8; 20], value: u128, func: &[u8]) -> Vec<u8> {
249 let f = abi::Function::new("execute(address,uint256,bytes)");
250 f.encode(&[
251 AbiValue::Address(dest),
252 AbiValue::from_u128(value),
253 AbiValue::Bytes(func.to_vec()),
254 ])
255}
256
257#[derive(Debug, Clone)]
259pub struct ExecuteCall {
260 pub target: [u8; 20],
262 pub value: u128,
264 pub data: Vec<u8>,
266}
267
268#[must_use]
272pub fn encode_execute_batch(calls: &[ExecuteCall]) -> Vec<u8> {
273 let f = abi::Function::new("executeBatch(address[],uint256[],bytes[])");
274 let dests: Vec<AbiValue> = calls.iter().map(|c| AbiValue::Address(c.target)).collect();
275 let values: Vec<AbiValue> = calls.iter().map(|c| AbiValue::from_u128(c.value)).collect();
276 let funcs: Vec<AbiValue> = calls
277 .iter()
278 .map(|c| AbiValue::Bytes(c.data.clone()))
279 .collect();
280 f.encode(&[
281 AbiValue::Array(dests),
282 AbiValue::Array(values),
283 AbiValue::Array(funcs),
284 ])
285}
286
287pub const ERC1271_MAGIC: [u8; 4] = [0x16, 0x26, 0xba, 0x7e];
293
294#[must_use]
298pub fn encode_is_valid_signature(hash: &[u8; 32], signature: &[u8]) -> Vec<u8> {
299 let f = abi::Function::new("isValidSignature(bytes32,bytes)");
300 f.encode(&[
301 AbiValue::Uint256(*hash),
302 AbiValue::Bytes(signature.to_vec()),
303 ])
304}
305
306#[must_use]
310pub fn is_valid_signature_magic(return_data: &[u8]) -> bool {
311 if return_data.len() < 32 {
312 return false;
313 }
314 return_data[..4] == [0u8; 4]
316 && return_data[4..28] == [0u8; 24]
317 && return_data[28..32] == ERC1271_MAGIC
318}
319
320#[must_use]
323pub fn is_valid_signature_magic_raw(return_data: &[u8]) -> bool {
324 if return_data.len() < 4 {
325 return false;
326 }
327 return_data[..4] == ERC1271_MAGIC
328}
329
330#[must_use]
336pub fn encode_create_account(owner: [u8; 20], salt: u64) -> Vec<u8> {
337 let f = abi::Function::new("createAccount(address,uint256)");
338 f.encode(&[AbiValue::Address(owner), AbiValue::from_u64(salt)])
339}
340
341#[must_use]
345pub fn encode_get_address(owner: [u8; 20], salt: u64) -> Vec<u8> {
346 let f = abi::Function::new("getAddress(address,uint256)");
347 f.encode(&[AbiValue::Address(owner), AbiValue::from_u64(salt)])
348}
349
350#[must_use]
354pub fn encode_get_nonce(sender: [u8; 20], key: u64) -> Vec<u8> {
355 let f = abi::Function::new("getNonce(address,uint192)");
356 f.encode(&[AbiValue::Address(sender), AbiValue::from_u64(key)])
357}
358
359fn keccak256(data: &[u8]) -> [u8; 32] {
362 let mut hasher = Keccak256::new();
363 hasher.update(data);
364 hasher.finalize().into()
365}
366
367fn pad_address(addr: &[u8; 20]) -> [u8; 32] {
368 let mut buf = [0u8; 32];
369 buf[12..32].copy_from_slice(addr);
370 buf
371}
372
373fn pad_u64(val: u64) -> [u8; 32] {
374 let mut buf = [0u8; 32];
375 buf[24..32].copy_from_slice(&val.to_be_bytes());
376 buf
377}
378
379#[cfg(test)]
382#[allow(clippy::unwrap_used, clippy::expect_used)]
383mod tests {
384 use super::*;
385 use crate::traits::KeyPair;
386
387 fn sample_op() -> PackedUserOperation {
388 PackedUserOperation {
389 sender: [0xAA; 20],
390 nonce: [0u8; 32],
391 init_code: vec![],
392 call_data: vec![0x01, 0x02],
393 account_gas_limits: PackedUserOperation::pack_account_gas_limits(100_000, 200_000),
394 pre_verification_gas: {
395 let mut buf = [0u8; 32];
396 buf[24..32].copy_from_slice(&50_000u64.to_be_bytes());
397 buf
398 },
399 gas_fees: PackedUserOperation::pack_gas_fees(1_000_000_000, 2_000_000_000),
400 paymaster_and_data: vec![],
401 signature: vec![],
402 }
403 }
404
405 #[test]
408 fn test_pack_deterministic() {
409 let op = sample_op();
410 assert_eq!(op.pack(), op.pack());
411 }
412
413 #[test]
414 fn test_pack_length() {
415 let op = sample_op();
416 assert_eq!(op.pack().len(), 256);
418 }
419
420 #[test]
421 fn test_hash_deterministic() {
422 let op = sample_op();
423 let ep = [0xFF; 20];
424 assert_eq!(op.hash(&ep, 1), op.hash(&ep, 1));
425 }
426
427 #[test]
428 fn test_hash_changes_with_chain_id() {
429 let op = sample_op();
430 let ep = [0xFF; 20];
431 assert_ne!(op.hash(&ep, 1), op.hash(&ep, 137));
432 }
433
434 #[test]
435 fn test_hash_changes_with_entry_point() {
436 let op = sample_op();
437 assert_ne!(op.hash(&[0xAA; 20], 1), op.hash(&[0xBB; 20], 1));
438 }
439
440 #[test]
441 fn test_hash_changes_with_calldata() {
442 let mut op1 = sample_op();
443 let mut op2 = sample_op();
444 op2.call_data = vec![0x03, 0x04];
445 assert_ne!(op1.hash(&[0xFF; 20], 1), op2.hash(&[0xFF; 20], 1));
446 }
447
448 #[test]
449 fn test_hash_changes_with_sender() {
450 let mut op1 = sample_op();
451 let mut op2 = sample_op();
452 op2.sender = [0xBB; 20];
453 assert_ne!(op1.hash(&[0xFF; 20], 1), op2.hash(&[0xFF; 20], 1));
454 }
455
456 #[test]
457 fn test_hash_changes_with_nonce() {
458 let mut op1 = sample_op();
459 let mut op2 = sample_op();
460 op2.nonce[31] = 1;
461 assert_ne!(op1.hash(&[0xFF; 20], 1), op2.hash(&[0xFF; 20], 1));
462 }
463
464 #[test]
467 fn test_sign_produces_valid_signature() {
468 let signer = super::super::EthereumSigner::generate().unwrap();
469 let op = sample_op();
470 let sig = op.sign(&signer, &[0xFF; 20], 1).unwrap();
471 assert!(sig.v == 27 || sig.v == 28);
472 assert_ne!(sig.r, [0u8; 32]);
473 }
474
475 #[test]
476 fn test_sign_recovers_correct_address() {
477 let signer = super::super::EthereumSigner::generate().unwrap();
478 let op = sample_op();
479 let sig = op.sign(&signer, &[0xFF; 20], 1).unwrap();
480 let hash = op.hash(&[0xFF; 20], 1);
481 let recovered = super::super::ecrecover_digest(&hash, &sig).unwrap();
482 assert_eq!(recovered, signer.address());
483 }
484
485 #[test]
488 fn test_pack_account_gas_limits_roundtrip() {
489 let packed = PackedUserOperation::pack_account_gas_limits(100_000, 200_000);
490 let (vgl, cgl) = PackedUserOperation::unpack_account_gas_limits(&packed);
491 assert_eq!(vgl, 100_000);
492 assert_eq!(cgl, 200_000);
493 }
494
495 #[test]
496 fn test_pack_gas_fees_roundtrip() {
497 let packed = PackedUserOperation::pack_gas_fees(1_000_000_000, 2_000_000_000);
498 let (mpf, mf) = PackedUserOperation::unpack_gas_fees(&packed);
499 assert_eq!(mpf, 1_000_000_000);
500 assert_eq!(mf, 2_000_000_000);
501 }
502
503 #[test]
504 fn test_pack_gas_limits_zero() {
505 let packed = PackedUserOperation::pack_account_gas_limits(0, 0);
506 assert_eq!(packed, [0u8; 32]);
507 let (vgl, cgl) = PackedUserOperation::unpack_account_gas_limits(&packed);
508 assert_eq!(vgl, 0);
509 assert_eq!(cgl, 0);
510 }
511
512 #[test]
513 fn test_pack_gas_fees_max() {
514 let max = u128::MAX;
515 let packed = PackedUserOperation::pack_gas_fees(max, max);
516 let (mpf, mf) = PackedUserOperation::unpack_gas_fees(&packed);
517 assert_eq!(mpf, max);
518 assert_eq!(mf, max);
519 }
520
521 #[test]
524 fn test_encode_handle_ops_selector() {
525 let ops = vec![sample_op()];
526 let calldata = encode_handle_ops(&ops, [0xFF; 20]);
527 let expected = abi::function_selector(
528 "handleOps((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)[],address)",
529 );
530 assert_eq!(&calldata[..4], &expected);
531 }
532
533 #[test]
534 fn test_encode_handle_ops_empty() {
535 let calldata = encode_handle_ops(&[], [0xFF; 20]);
536 assert!(calldata.len() > 4);
537 }
538
539 #[test]
542 fn test_paymaster_data_roundtrip() {
543 let paymaster = [0xAA; 20];
544 let vgl = 100_000u128;
545 let pogl = 50_000u128;
546 let data = vec![0xDE, 0xAD];
547
548 let encoded = encode_paymaster_data(paymaster, vgl, pogl, &data);
549 let (dec_pm, dec_vgl, dec_pogl, dec_data) = decode_paymaster_data(&encoded).unwrap();
550
551 assert_eq!(dec_pm, paymaster);
552 assert_eq!(dec_vgl, vgl);
553 assert_eq!(dec_pogl, pogl);
554 assert_eq!(dec_data, data);
555 }
556
557 #[test]
558 fn test_paymaster_data_empty_extra_data() {
559 let encoded = encode_paymaster_data([0xAA; 20], 100, 200, &[]);
560 let (_, _, _, data) = decode_paymaster_data(&encoded).unwrap();
561 assert!(data.is_empty());
562 }
563
564 #[test]
565 fn test_paymaster_data_too_short() {
566 assert!(decode_paymaster_data(&[0u8; 51]).is_err());
567 assert!(decode_paymaster_data(&[]).is_err());
568 }
569
570 #[test]
571 fn test_paymaster_data_minimum_length() {
572 let encoded = encode_paymaster_data([0xBB; 20], 0, 0, &[]);
573 assert_eq!(encoded.len(), 52);
574 assert!(decode_paymaster_data(&encoded).is_ok());
575 }
576
577 #[test]
580 fn test_encode_execute_selector() {
581 let calldata = encode_execute([0xBB; 20], 0, &[]);
582 let expected = abi::function_selector("execute(address,uint256,bytes)");
583 assert_eq!(&calldata[..4], &expected);
584 }
585
586 #[test]
587 fn test_encode_execute_with_value() {
588 let calldata = encode_execute([0xBB; 20], 1_000_000, &[0xDE, 0xAD]);
589 assert!(calldata.len() > 4 + 3 * 32);
590 }
591
592 #[test]
593 fn test_encode_execute_batch_selector() {
594 let calls = vec![ExecuteCall {
595 target: [0xAA; 20],
596 value: 0,
597 data: vec![],
598 }];
599 let calldata = encode_execute_batch(&calls);
600 let expected = abi::function_selector("executeBatch(address[],uint256[],bytes[])");
601 assert_eq!(&calldata[..4], &expected);
602 }
603
604 #[test]
605 fn test_encode_execute_batch_multiple() {
606 let calls = vec![
607 ExecuteCall { target: [0xAA; 20], value: 100, data: vec![0x01] },
608 ExecuteCall { target: [0xBB; 20], value: 200, data: vec![0x02] },
609 ];
610 let calldata = encode_execute_batch(&calls);
611 assert!(calldata.len() > 4);
612 }
613
614 #[test]
615 fn test_encode_execute_batch_empty() {
616 let calldata = encode_execute_batch(&[]);
617 let expected = abi::function_selector("executeBatch(address[],uint256[],bytes[])");
618 assert_eq!(&calldata[..4], &expected);
619 }
620
621 #[test]
624 fn test_erc1271_magic_value() {
625 assert_eq!(ERC1271_MAGIC, [0x16, 0x26, 0xba, 0x7e]);
626 }
627
628 #[test]
629 fn test_encode_is_valid_signature_selector() {
630 let calldata = encode_is_valid_signature(&[0xAA; 32], &[0xBB; 65]);
631 let expected = abi::function_selector("isValidSignature(bytes32,bytes)");
632 assert_eq!(&calldata[..4], &expected);
633 }
634
635 #[test]
636 fn test_is_valid_signature_magic_true() {
637 let mut result = [0u8; 32];
639 result[28] = 0x16;
640 result[29] = 0x26;
641 result[30] = 0xba;
642 result[31] = 0x7e;
643 assert!(is_valid_signature_magic(&result));
644 }
645
646 #[test]
647 fn test_is_valid_signature_magic_false() {
648 let result = [0u8; 32]; assert!(!is_valid_signature_magic(&result));
650 }
651
652 #[test]
653 fn test_is_valid_signature_magic_too_short() {
654 assert!(!is_valid_signature_magic(&[0u8; 31]));
655 }
656
657 #[test]
658 fn test_is_valid_signature_magic_raw_true() {
659 assert!(is_valid_signature_magic_raw(&[0x16, 0x26, 0xba, 0x7e]));
660 }
661
662 #[test]
663 fn test_is_valid_signature_magic_raw_false() {
664 assert!(!is_valid_signature_magic_raw(&[0x00, 0x00, 0x00, 0x00]));
665 }
666
667 #[test]
668 fn test_is_valid_signature_magic_raw_too_short() {
669 assert!(!is_valid_signature_magic_raw(&[0x16, 0x26, 0xba]));
670 }
671
672 #[test]
675 fn test_encode_create_account_selector() {
676 let calldata = encode_create_account([0xAA; 20], 0);
677 let expected = abi::function_selector("createAccount(address,uint256)");
678 assert_eq!(&calldata[..4], &expected);
679 }
680
681 #[test]
682 fn test_encode_get_address_selector() {
683 let calldata = encode_get_address([0xAA; 20], 0);
684 let expected = abi::function_selector("getAddress(address,uint256)");
685 assert_eq!(&calldata[..4], &expected);
686 }
687
688 #[test]
691 fn test_encode_get_nonce_selector() {
692 let calldata = encode_get_nonce([0xAA; 20], 0);
693 let expected = abi::function_selector("getNonce(address,uint192)");
694 assert_eq!(&calldata[..4], &expected);
695 }
696
697 #[test]
700 fn test_pad_address() {
701 let addr = [0xAA; 20];
702 let padded = pad_address(&addr);
703 assert_eq!(&padded[..12], &[0u8; 12]);
704 assert_eq!(&padded[12..], &[0xAA; 20]);
705 }
706
707 #[test]
708 fn test_pad_u64() {
709 let padded = pad_u64(256);
710 assert_eq!(&padded[..24], &[0u8; 24]);
711 assert_eq!(&padded[24..], &256u64.to_be_bytes());
712 }
713
714 #[test]
717 fn test_hash_changes_with_init_code() {
718 let mut op1 = sample_op();
719 let mut op2 = sample_op();
720 op2.init_code = vec![0xFF; 20];
721 assert_ne!(op1.hash(&[0xFF; 20], 1), op2.hash(&[0xFF; 20], 1));
722 }
723
724 #[test]
725 fn test_hash_changes_with_paymaster_data() {
726 let mut op1 = sample_op();
727 let mut op2 = sample_op();
728 op2.paymaster_and_data = vec![0xAA; 52];
729 assert_ne!(op1.hash(&[0xFF; 20], 1), op2.hash(&[0xFF; 20], 1));
730 }
731
732 #[test]
733 fn test_hash_changes_with_gas_limits() {
734 let mut op1 = sample_op();
735 let mut op2 = sample_op();
736 op2.account_gas_limits = PackedUserOperation::pack_account_gas_limits(999, 888);
737 assert_ne!(op1.hash(&[0xFF; 20], 1), op2.hash(&[0xFF; 20], 1));
738 }
739
740 #[test]
741 fn test_hash_changes_with_gas_fees() {
742 let mut op1 = sample_op();
743 let mut op2 = sample_op();
744 op2.gas_fees = PackedUserOperation::pack_gas_fees(999, 888);
745 assert_ne!(op1.hash(&[0xFF; 20], 1), op2.hash(&[0xFF; 20], 1));
746 }
747}