1use crate::error::SignerError;
15
16fn keccak256(data: &[u8]) -> [u8; 32] {
20 super::keccak256(data)
21}
22
23#[derive(Debug, Clone)]
32pub struct Permit {
33 pub owner: [u8; 20],
35 pub spender: [u8; 20],
37 pub value: [u8; 32],
39 pub nonce: u64,
41 pub deadline: u64,
43}
44
45impl Permit {
46 #[must_use]
50 pub fn type_hash() -> [u8; 32] {
51 keccak256(
52 b"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)",
53 )
54 }
55
56 #[must_use]
60 pub fn struct_hash(&self) -> [u8; 32] {
61 let mut data = Vec::with_capacity(6 * 32);
62 data.extend_from_slice(&Self::type_hash());
63
64 let mut owner_padded = [0u8; 32];
66 owner_padded[12..].copy_from_slice(&self.owner);
67 data.extend_from_slice(&owner_padded);
68
69 let mut spender_padded = [0u8; 32];
71 spender_padded[12..].copy_from_slice(&self.spender);
72 data.extend_from_slice(&spender_padded);
73
74 data.extend_from_slice(&self.value);
76
77 let mut nonce_buf = [0u8; 32];
79 nonce_buf[24..].copy_from_slice(&self.nonce.to_be_bytes());
80 data.extend_from_slice(&nonce_buf);
81
82 let mut deadline_buf = [0u8; 32];
84 deadline_buf[24..].copy_from_slice(&self.deadline.to_be_bytes());
85 data.extend_from_slice(&deadline_buf);
86
87 keccak256(&data)
88 }
89
90 #[must_use]
94 pub fn signing_hash(&self, domain_separator: &[u8; 32]) -> [u8; 32] {
95 let mut buf = Vec::with_capacity(2 + 32 + 32);
96 buf.push(0x19);
97 buf.push(0x01);
98 buf.extend_from_slice(domain_separator);
99 buf.extend_from_slice(&self.struct_hash());
100 keccak256(&buf)
101 }
102
103 pub fn sign(
105 &self,
106 signer: &super::EthereumSigner,
107 domain_separator: &[u8; 32],
108 ) -> Result<super::EthereumSignature, SignerError> {
109 let hash = self.signing_hash(domain_separator);
110 signer.sign_digest(&hash)
111 }
112}
113
114#[derive(Debug, Clone)]
123pub struct UserOperation {
124 pub sender: [u8; 20],
126 pub nonce: [u8; 32],
128 pub init_code: Vec<u8>,
130 pub call_data: Vec<u8>,
132 pub call_gas_limit: [u8; 32],
134 pub verification_gas_limit: [u8; 32],
136 pub pre_verification_gas: [u8; 32],
138 pub max_fee_per_gas: [u8; 32],
140 pub max_priority_fee_per_gas: [u8; 32],
142 pub paymaster_and_data: Vec<u8>,
144}
145
146impl UserOperation {
147 #[must_use]
151 pub fn pack(&self) -> Vec<u8> {
152 let mut data = Vec::with_capacity(320);
153
154 let mut sender_buf = [0u8; 32];
156 sender_buf[12..].copy_from_slice(&self.sender);
157 data.extend_from_slice(&sender_buf);
158
159 data.extend_from_slice(&self.nonce);
160 data.extend_from_slice(&keccak256(&self.init_code));
161 data.extend_from_slice(&keccak256(&self.call_data));
162 data.extend_from_slice(&self.call_gas_limit);
163 data.extend_from_slice(&self.verification_gas_limit);
164 data.extend_from_slice(&self.pre_verification_gas);
165 data.extend_from_slice(&self.max_fee_per_gas);
166 data.extend_from_slice(&self.max_priority_fee_per_gas);
167 data.extend_from_slice(&keccak256(&self.paymaster_and_data));
168
169 data
170 }
171
172 #[must_use]
176 pub fn hash(&self, entry_point: &[u8; 20], chain_id: [u8; 32]) -> [u8; 32] {
177 let packed_hash = keccak256(&self.pack());
178 let mut data = Vec::with_capacity(3 * 32);
179 data.extend_from_slice(&packed_hash);
180
181 let mut ep_buf = [0u8; 32];
182 ep_buf[12..].copy_from_slice(entry_point);
183 data.extend_from_slice(&ep_buf);
184
185 data.extend_from_slice(&chain_id);
186
187 keccak256(&data)
188 }
189
190 pub fn sign(
192 &self,
193 signer: &super::EthereumSigner,
194 entry_point: &[u8; 20],
195 chain_id: [u8; 32],
196 ) -> Result<super::EthereumSignature, SignerError> {
197 let hash = self.hash(entry_point, chain_id);
198 signer.sign_digest(&hash)
199 }
200}
201
202#[must_use]
204pub fn uint256_from_u64(value: u64) -> [u8; 32] {
205 let mut out = [0u8; 32];
206 out[24..].copy_from_slice(&value.to_be_bytes());
207 out
208}
209
210#[derive(Debug, Clone)]
219pub struct Eip7702Authorization {
220 pub chain_id: u64,
222 pub address: [u8; 20],
224 pub nonce: u64,
226}
227
228impl Eip7702Authorization {
229 pub const MAGIC: u8 = 0x05;
231
232 #[must_use]
236 pub fn signing_hash(&self) -> [u8; 32] {
237 use super::rlp;
238 let mut items = Vec::new();
239 items.extend_from_slice(&rlp::encode_u64(self.chain_id));
240 items.extend_from_slice(&rlp::encode_bytes(&self.address));
241 items.extend_from_slice(&rlp::encode_u64(self.nonce));
242 let rlp_data = rlp::encode_list(&items);
243
244 let mut payload = vec![Self::MAGIC];
245 payload.extend_from_slice(&rlp_data);
246 keccak256(&payload)
247 }
248
249 pub fn sign(
251 &self,
252 signer: &super::EthereumSigner,
253 ) -> Result<super::EthereumSignature, SignerError> {
254 let hash = self.signing_hash();
255 signer.sign_digest(&hash)
256 }
257}
258
259#[derive(Debug, Clone)]
268pub struct AuthMessage {
269 pub invoker: [u8; 20],
271 pub commit: [u8; 32],
273}
274
275impl AuthMessage {
276 pub const MAGIC: u8 = 0x04;
278
279 #[must_use]
286 pub fn signing_hash(&self, chain_id: u64, nonce: u64) -> [u8; 32] {
287 let mut buf = Vec::with_capacity(1 + 4 * 32);
288 buf.push(Self::MAGIC);
289
290 let mut chain_buf = [0u8; 32];
292 chain_buf[24..].copy_from_slice(&chain_id.to_be_bytes());
293 buf.extend_from_slice(&chain_buf);
294
295 let mut nonce_buf = [0u8; 32];
297 nonce_buf[24..].copy_from_slice(&nonce.to_be_bytes());
298 buf.extend_from_slice(&nonce_buf);
299
300 let mut invoker_buf = [0u8; 32];
302 invoker_buf[12..].copy_from_slice(&self.invoker);
303 buf.extend_from_slice(&invoker_buf);
304
305 buf.extend_from_slice(&self.commit);
307
308 keccak256(&buf)
309 }
310
311 pub fn sign(
313 &self,
314 signer: &super::EthereumSigner,
315 chain_id: u64,
316 nonce: u64,
317 ) -> Result<super::EthereumSignature, SignerError> {
318 let hash = self.signing_hash(chain_id, nonce);
319 signer.sign_digest(&hash)
320 }
321}
322
323pub const EIP6492_MAGIC: [u8; 32] = [
329 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92,
330 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92,
331];
332
333#[must_use]
340pub fn wrap_eip6492_signature(
341 create2_factory: &[u8; 20],
342 factory_calldata: &[u8],
343 original_signature: &[u8],
344) -> Vec<u8> {
345 use super::abi::{self, AbiValue};
346 let mut encoded = abi::encode(&[
347 AbiValue::Address(*create2_factory),
348 AbiValue::Bytes(factory_calldata.to_vec()),
349 AbiValue::Bytes(original_signature.to_vec()),
350 ]);
351 encoded.extend_from_slice(&EIP6492_MAGIC);
352 encoded
353}
354
355#[must_use]
357pub fn is_eip6492_signature(signature: &[u8]) -> bool {
358 signature.len() > 32 && signature[signature.len() - 32..] == EIP6492_MAGIC
359}
360
361pub fn unwrap_eip6492_signature(signature: &[u8]) -> Result<&[u8], SignerError> {
366 if !is_eip6492_signature(signature) {
367 return Err(SignerError::ParseError("not an EIP-6492 signature".into()));
368 }
369 Ok(&signature[..signature.len() - 32])
370}
371
372#[must_use]
382pub fn encode_eip712_domain_call() -> Vec<u8> {
383 let selector = &keccak256(b"eip712Domain()")[..4];
385 selector.to_vec()
386}
387
388pub const EIP5267_SELECTOR: [u8; 4] = [0x84, 0xb0, 0x19, 0x6e];
390
391pub mod bls_paths {
397 pub fn withdrawal(validator_index: u32) -> Vec<u32> {
399 vec![12381, 3600, validator_index, 0]
400 }
401
402 pub fn signing(validator_index: u32) -> Vec<u32> {
404 vec![12381, 3600, validator_index, 0, 0]
405 }
406}
407
408pub const EIP2335_VERSION: u32 = 4;
410
411pub const EIP2335_KDF: &str = "scrypt";
413pub const EIP2335_CIPHER: &str = "aes-128-ctr";
415pub const EIP2335_CHECKSUM: &str = "sha256";
417
418#[derive(Debug, Clone)]
427pub struct TransferWithAuthorization {
428 pub from: [u8; 20],
430 pub to: [u8; 20],
432 pub value: [u8; 32],
434 pub valid_after: u64,
436 pub valid_before: u64,
438 pub nonce: [u8; 32],
440}
441
442impl TransferWithAuthorization {
443 #[must_use]
447 pub fn type_hash() -> [u8; 32] {
448 keccak256(b"TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
449 }
450
451 #[must_use]
453 pub fn struct_hash(&self) -> [u8; 32] {
454 let mut data = Vec::with_capacity(7 * 32);
455 data.extend_from_slice(&Self::type_hash());
456
457 let mut from_padded = [0u8; 32];
458 from_padded[12..].copy_from_slice(&self.from);
459 data.extend_from_slice(&from_padded);
460
461 let mut to_padded = [0u8; 32];
462 to_padded[12..].copy_from_slice(&self.to);
463 data.extend_from_slice(&to_padded);
464
465 data.extend_from_slice(&self.value);
466
467 let mut va = [0u8; 32];
468 va[24..].copy_from_slice(&self.valid_after.to_be_bytes());
469 data.extend_from_slice(&va);
470
471 let mut vb = [0u8; 32];
472 vb[24..].copy_from_slice(&self.valid_before.to_be_bytes());
473 data.extend_from_slice(&vb);
474
475 data.extend_from_slice(&self.nonce);
476
477 keccak256(&data)
478 }
479
480 #[must_use]
482 pub fn signing_hash(&self, domain_separator: &[u8; 32]) -> [u8; 32] {
483 eip712_signing_hash(domain_separator, &self.struct_hash())
484 }
485
486 pub fn sign(
488 &self,
489 signer: &super::EthereumSigner,
490 domain_separator: &[u8; 32],
491 ) -> Result<super::EthereumSignature, SignerError> {
492 let hash = self.signing_hash(domain_separator);
493 signer.sign_digest(&hash)
494 }
495}
496
497#[derive(Debug, Clone)]
499pub struct ReceiveWithAuthorization {
500 pub from: [u8; 20],
502 pub to: [u8; 20],
504 pub value: [u8; 32],
506 pub valid_after: u64,
508 pub valid_before: u64,
510 pub nonce: [u8; 32],
512}
513
514impl ReceiveWithAuthorization {
515 #[must_use]
517 pub fn type_hash() -> [u8; 32] {
518 keccak256(b"ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
519 }
520
521 #[must_use]
523 pub fn struct_hash(&self) -> [u8; 32] {
524 let mut data = Vec::with_capacity(7 * 32);
525 data.extend_from_slice(&Self::type_hash());
526
527 let mut from_padded = [0u8; 32];
528 from_padded[12..].copy_from_slice(&self.from);
529 data.extend_from_slice(&from_padded);
530
531 let mut to_padded = [0u8; 32];
532 to_padded[12..].copy_from_slice(&self.to);
533 data.extend_from_slice(&to_padded);
534
535 data.extend_from_slice(&self.value);
536
537 let mut va = [0u8; 32];
538 va[24..].copy_from_slice(&self.valid_after.to_be_bytes());
539 data.extend_from_slice(&va);
540
541 let mut vb = [0u8; 32];
542 vb[24..].copy_from_slice(&self.valid_before.to_be_bytes());
543 data.extend_from_slice(&vb);
544
545 data.extend_from_slice(&self.nonce);
546
547 keccak256(&data)
548 }
549
550 pub fn sign(
552 &self,
553 signer: &super::EthereumSigner,
554 domain_separator: &[u8; 32],
555 ) -> Result<super::EthereumSignature, SignerError> {
556 let hash = eip712_signing_hash(domain_separator, &self.struct_hash());
557 signer.sign_digest(&hash)
558 }
559}
560
561#[derive(Debug, Clone)]
563pub struct CancelAuthorization {
564 pub authorizer: [u8; 20],
566 pub nonce: [u8; 32],
568}
569
570impl CancelAuthorization {
571 #[must_use]
573 pub fn type_hash() -> [u8; 32] {
574 keccak256(b"CancelAuthorization(address authorizer,bytes32 nonce)")
575 }
576
577 #[must_use]
579 pub fn struct_hash(&self) -> [u8; 32] {
580 let mut data = Vec::with_capacity(3 * 32);
581 data.extend_from_slice(&Self::type_hash());
582
583 let mut auth_padded = [0u8; 32];
584 auth_padded[12..].copy_from_slice(&self.authorizer);
585 data.extend_from_slice(&auth_padded);
586
587 data.extend_from_slice(&self.nonce);
588
589 keccak256(&data)
590 }
591
592 pub fn sign(
594 &self,
595 signer: &super::EthereumSigner,
596 domain_separator: &[u8; 32],
597 ) -> Result<super::EthereumSignature, SignerError> {
598 let hash = eip712_signing_hash(domain_separator, &self.struct_hash());
599 signer.sign_digest(&hash)
600 }
601}
602
603#[derive(Debug, Clone)]
612pub struct Erc721Permit {
613 pub spender: [u8; 20],
615 pub token_id: [u8; 32],
617 pub nonce: u64,
619 pub deadline: u64,
621}
622
623impl Erc721Permit {
624 #[must_use]
628 pub fn type_hash() -> [u8; 32] {
629 keccak256(b"Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)")
630 }
631
632 #[must_use]
634 pub fn struct_hash(&self) -> [u8; 32] {
635 let mut data = Vec::with_capacity(5 * 32);
636 data.extend_from_slice(&Self::type_hash());
637
638 let mut spender_padded = [0u8; 32];
639 spender_padded[12..].copy_from_slice(&self.spender);
640 data.extend_from_slice(&spender_padded);
641
642 data.extend_from_slice(&self.token_id);
643
644 let mut nonce_buf = [0u8; 32];
645 nonce_buf[24..].copy_from_slice(&self.nonce.to_be_bytes());
646 data.extend_from_slice(&nonce_buf);
647
648 let mut deadline_buf = [0u8; 32];
649 deadline_buf[24..].copy_from_slice(&self.deadline.to_be_bytes());
650 data.extend_from_slice(&deadline_buf);
651
652 keccak256(&data)
653 }
654
655 #[must_use]
657 pub fn signing_hash(&self, domain_separator: &[u8; 32]) -> [u8; 32] {
658 eip712_signing_hash(domain_separator, &self.struct_hash())
659 }
660
661 pub fn sign(
663 &self,
664 signer: &super::EthereumSigner,
665 domain_separator: &[u8; 32],
666 ) -> Result<super::EthereumSignature, SignerError> {
667 let hash = self.signing_hash(domain_separator);
668 signer.sign_digest(&hash)
669 }
670}
671
672#[must_use]
687pub fn encode_multicall3(calls: &[([u8; 20], bool, Vec<u8>)]) -> Vec<u8> {
688 use super::abi::{self, AbiValue};
689
690 let selector = &keccak256(b"aggregate3((address,bool,bytes)[])")[..4];
692
693 let call_tuples: Vec<AbiValue> = calls
694 .iter()
695 .map(|(target, allow, cd)| {
696 AbiValue::Tuple(vec![
697 AbiValue::Address(*target),
698 AbiValue::Bool(*allow),
699 AbiValue::Bytes(cd.clone()),
700 ])
701 })
702 .collect();
703
704 let mut calldata = Vec::new();
705 calldata.extend_from_slice(selector);
706 calldata.extend_from_slice(&abi::encode(&[AbiValue::Array(call_tuples)]));
707 calldata
708}
709
710pub const MULTICALL3_ADDRESS: [u8; 20] = [
712 0xCA, 0x11, 0xBD, 0xE0, 0x59, 0x77, 0xB3, 0x63, 0x11, 0x67, 0x02, 0x88, 0x62, 0xBE, 0x2A, 0x17,
713 0x39, 0x76, 0xCA, 0x11,
714];
715
716#[must_use]
725pub fn encode_try_aggregate(require_success: bool, calls: &[([u8; 20], Vec<u8>)]) -> Vec<u8> {
726 use super::abi::{self, AbiValue};
727
728 let selector = &keccak256(b"tryAggregate(bool,(address,bytes)[])")[..4];
729
730 let call_tuples: Vec<AbiValue> = calls
731 .iter()
732 .map(|(target, cd)| {
733 AbiValue::Tuple(vec![
734 AbiValue::Address(*target),
735 AbiValue::Bytes(cd.clone()),
736 ])
737 })
738 .collect();
739
740 let mut calldata = Vec::new();
741 calldata.extend_from_slice(selector);
742 calldata.extend_from_slice(&abi::encode(&[
743 AbiValue::Bool(require_success),
744 AbiValue::Array(call_tuples),
745 ]));
746 calldata
747}
748
749fn eip712_signing_hash(domain_separator: &[u8; 32], struct_hash: &[u8; 32]) -> [u8; 32] {
752 let mut buf = Vec::with_capacity(2 + 32 + 32);
753 buf.push(0x19);
754 buf.push(0x01);
755 buf.extend_from_slice(domain_separator);
756 buf.extend_from_slice(struct_hash);
757 keccak256(&buf)
758}
759
760#[cfg(test)]
765#[allow(clippy::unwrap_used, clippy::expect_used)]
766mod tests {
767 use super::*;
768 use crate::traits::KeyPair;
769
770 #[test]
773 fn test_permit_type_hash() {
774 let hash = Permit::type_hash();
775 assert_eq!(
776 hex::encode(hash),
777 "6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9"
778 );
779 }
780
781 #[test]
782 fn test_permit_struct_hash_deterministic() {
783 let permit = Permit {
784 owner: [0xAA; 20],
785 spender: [0xBB; 20],
786 value: [0; 32],
787 nonce: 0,
788 deadline: u64::MAX,
789 };
790 assert_eq!(permit.struct_hash(), permit.struct_hash());
791 }
792
793 #[test]
794 fn test_permit_sign_roundtrip() {
795 let signer = super::super::EthereumSigner::generate().unwrap();
796 let permit = Permit {
797 owner: signer.address(),
798 spender: [0xBB; 20],
799 value: {
800 let mut v = [0u8; 32];
801 v[31] = 100;
802 v
803 },
804 nonce: 0,
805 deadline: u64::MAX,
806 };
807 let domain = [0xCC; 32]; let sig = permit.sign(&signer, &domain).unwrap();
809 assert_eq!(sig.r.len(), 32);
810 assert_eq!(sig.s.len(), 32);
811 }
812
813 #[test]
816 fn test_user_op_hash_deterministic() {
817 let op = UserOperation {
818 sender: [0xAA; 20],
819 nonce: [0; 32],
820 init_code: vec![],
821 call_data: vec![0x01, 0x02],
822 call_gas_limit: [0; 32],
823 verification_gas_limit: [0; 32],
824 pre_verification_gas: [0; 32],
825 max_fee_per_gas: [0; 32],
826 max_priority_fee_per_gas: [0; 32],
827 paymaster_and_data: vec![],
828 };
829 let entry_point = [0xBB; 20];
830 let h1 = op.hash(&entry_point, uint256_from_u64(1));
831 let h2 = op.hash(&entry_point, uint256_from_u64(1));
832 assert_eq!(h1, h2);
833 }
834
835 #[test]
836 fn test_user_op_different_chain_different_hash() {
837 let op = UserOperation {
838 sender: [0xAA; 20],
839 nonce: [0; 32],
840 init_code: vec![],
841 call_data: vec![],
842 call_gas_limit: [0; 32],
843 verification_gas_limit: [0; 32],
844 pre_verification_gas: [0; 32],
845 max_fee_per_gas: [0; 32],
846 max_priority_fee_per_gas: [0; 32],
847 paymaster_and_data: vec![],
848 };
849 let ep = [0xBB; 20];
850 assert_ne!(
851 op.hash(&ep, uint256_from_u64(1)),
852 op.hash(&ep, uint256_from_u64(5))
853 );
854 }
855
856 #[test]
857 fn test_user_op_sign() {
858 let signer = super::super::EthereumSigner::generate().unwrap();
859 let op = UserOperation {
860 sender: signer.address(),
861 nonce: [0; 32],
862 init_code: vec![],
863 call_data: vec![],
864 call_gas_limit: [0; 32],
865 verification_gas_limit: [0; 32],
866 pre_verification_gas: [0; 32],
867 max_fee_per_gas: [0; 32],
868 max_priority_fee_per_gas: [0; 32],
869 paymaster_and_data: vec![],
870 };
871 let sig = op.sign(&signer, &[0x55; 20], uint256_from_u64(1)).unwrap();
872 assert_eq!(sig.r.len(), 32);
873 }
874
875 #[test]
878 fn test_eip7702_signing_hash_deterministic() {
879 let auth = Eip7702Authorization {
880 chain_id: 1,
881 address: [0xCC; 20],
882 nonce: 0,
883 };
884 assert_eq!(auth.signing_hash(), auth.signing_hash());
885 }
886
887 #[test]
888 fn test_eip7702_different_chain_different_hash() {
889 let auth1 = Eip7702Authorization {
890 chain_id: 1,
891 address: [0xCC; 20],
892 nonce: 0,
893 };
894 let auth2 = Eip7702Authorization {
895 chain_id: 5,
896 address: [0xCC; 20],
897 nonce: 0,
898 };
899 assert_ne!(auth1.signing_hash(), auth2.signing_hash());
900 }
901
902 #[test]
903 fn test_eip7702_sign() {
904 let signer = super::super::EthereumSigner::generate().unwrap();
905 let auth = Eip7702Authorization {
906 chain_id: 1,
907 address: [0xDD; 20],
908 nonce: 42,
909 };
910 let sig = auth.sign(&signer).unwrap();
911 assert!(sig.v == 27 || sig.v == 28);
912 }
913
914 #[test]
917 fn test_auth_message_hash_deterministic() {
918 let msg = AuthMessage {
919 invoker: [0xEE; 20],
920 commit: [0xFF; 32],
921 };
922 assert_eq!(msg.signing_hash(1, 0), msg.signing_hash(1, 0));
923 }
924
925 #[test]
926 fn test_auth_message_different_nonce() {
927 let msg = AuthMessage {
928 invoker: [0xEE; 20],
929 commit: [0xFF; 32],
930 };
931 assert_ne!(msg.signing_hash(1, 0), msg.signing_hash(1, 1));
932 }
933
934 #[test]
935 fn test_auth_message_sign() {
936 let signer = super::super::EthereumSigner::generate().unwrap();
937 let msg = AuthMessage {
938 invoker: [0xAA; 20],
939 commit: [0xBB; 32],
940 };
941 let sig = msg.sign(&signer, 1, 0).unwrap();
942 assert!(sig.v == 27 || sig.v == 28);
943 }
944
945 #[test]
948 fn test_eip6492_wrap_unwrap() {
949 let factory = [0xAA; 20];
950 let calldata = vec![0xBB; 64];
951 let sig = vec![0xCC; 65];
952 let wrapped = wrap_eip6492_signature(&factory, &calldata, &sig);
953 assert!(is_eip6492_signature(&wrapped));
954 let inner = unwrap_eip6492_signature(&wrapped).unwrap();
955 assert!(!inner.is_empty());
956 }
957
958 #[test]
959 fn test_eip6492_not_wrapped() {
960 let plain_sig = vec![0x00; 65];
961 assert!(!is_eip6492_signature(&plain_sig));
962 }
963
964 #[test]
967 fn test_eip5267_selector() {
968 let calldata = encode_eip712_domain_call();
969 assert_eq!(calldata, EIP5267_SELECTOR);
970 }
971
972 #[test]
975 fn test_bls_signing_path() {
976 let path = bls_paths::signing(0);
977 assert_eq!(path, vec![12381, 3600, 0, 0, 0]);
978 }
979
980 #[test]
981 fn test_bls_withdrawal_path() {
982 let path = bls_paths::withdrawal(5);
983 assert_eq!(path, vec![12381, 3600, 5, 0]);
984 }
985
986 #[test]
989 fn test_transfer_auth_type_hash() {
990 let hash = TransferWithAuthorization::type_hash();
992 assert_eq!(
993 hex::encode(hash),
994 "7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267"
995 );
996 }
997
998 #[test]
999 fn test_receive_auth_type_hash() {
1000 let hash = ReceiveWithAuthorization::type_hash();
1001 assert_eq!(
1002 hex::encode(hash),
1003 "d099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de8"
1004 );
1005 }
1006
1007 #[test]
1008 fn test_cancel_auth_type_hash() {
1009 let hash = CancelAuthorization::type_hash();
1010 assert_eq!(
1011 hex::encode(hash),
1012 "158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429"
1013 );
1014 }
1015
1016 #[test]
1017 fn test_transfer_auth_sign() {
1018 let signer = super::super::EthereumSigner::generate().unwrap();
1019 let auth = TransferWithAuthorization {
1020 from: signer.address(),
1021 to: [0xBB; 20],
1022 value: {
1023 let mut v = [0u8; 32];
1024 v[31] = 100;
1025 v
1026 },
1027 valid_after: 0,
1028 valid_before: u64::MAX,
1029 nonce: [0x42; 32],
1030 };
1031 let domain = [0xCC; 32];
1032 let sig = auth.sign(&signer, &domain).unwrap();
1033 assert!(sig.v == 27 || sig.v == 28);
1034 }
1035
1036 #[test]
1037 fn test_cancel_auth_sign() {
1038 let signer = super::super::EthereumSigner::generate().unwrap();
1039 let cancel = CancelAuthorization {
1040 authorizer: signer.address(),
1041 nonce: [0xFF; 32],
1042 };
1043 let domain = [0xCC; 32];
1044 let sig = cancel.sign(&signer, &domain).unwrap();
1045 assert!(sig.v == 27 || sig.v == 28);
1046 }
1047
1048 #[test]
1049 fn test_transfer_auth_different_nonce_different_hash() {
1050 let auth1 = TransferWithAuthorization {
1051 from: [0xAA; 20],
1052 to: [0xBB; 20],
1053 value: [0; 32],
1054 valid_after: 0,
1055 valid_before: u64::MAX,
1056 nonce: [0x01; 32],
1057 };
1058 let auth2 = TransferWithAuthorization {
1059 nonce: [0x02; 32],
1060 ..auth1.clone()
1061 };
1062 assert_ne!(auth1.struct_hash(), auth2.struct_hash());
1063 }
1064
1065 #[test]
1068 fn test_erc721_permit_type_hash() {
1069 let hash = Erc721Permit::type_hash();
1070 assert_eq!(
1072 hex::encode(hash),
1073 "49ecf333e5b8c95c40fdafc95c1ad136e8914a8fb55e9dc8bb01eaa83a2df9ad"
1074 );
1075 }
1076
1077 #[test]
1078 fn test_erc721_permit_sign() {
1079 let signer = super::super::EthereumSigner::generate().unwrap();
1080 let permit = Erc721Permit {
1081 spender: [0xBB; 20],
1082 token_id: {
1083 let mut t = [0u8; 32];
1084 t[31] = 1;
1085 t
1086 }, nonce: 0,
1088 deadline: u64::MAX,
1089 };
1090 let domain = [0xCC; 32];
1091 let sig = permit.sign(&signer, &domain).unwrap();
1092 assert_eq!(sig.r.len(), 32);
1093 }
1094
1095 #[test]
1096 fn test_erc721_permit_different_token_id() {
1097 let perm1 = Erc721Permit {
1098 spender: [0xBB; 20],
1099 token_id: {
1100 let mut t = [0u8; 32];
1101 t[31] = 1;
1102 t
1103 },
1104 nonce: 0,
1105 deadline: u64::MAX,
1106 };
1107 let perm2 = Erc721Permit {
1108 token_id: {
1109 let mut t = [0u8; 32];
1110 t[31] = 2;
1111 t
1112 },
1113 ..perm1.clone()
1114 };
1115 assert_ne!(perm1.struct_hash(), perm2.struct_hash());
1116 }
1117
1118 #[test]
1121 fn test_multicall3_encode() {
1122 let calls = vec![
1123 ([0xAA; 20], false, vec![0x01, 0x02, 0x03]),
1124 ([0xBB; 20], true, vec![0x04, 0x05]),
1125 ];
1126 let calldata = encode_multicall3(&calls);
1127 let expected_selector = &keccak256(b"aggregate3((address,bool,bytes)[])")[..4];
1129 assert_eq!(&calldata[..4], expected_selector);
1130 assert!(calldata.len() > 4);
1131 }
1132
1133 #[test]
1134 fn test_multicall3_empty() {
1135 let calldata = encode_multicall3(&[]);
1136 let expected_selector = &keccak256(b"aggregate3((address,bool,bytes)[])")[..4];
1137 assert_eq!(&calldata[..4], expected_selector);
1138 }
1139
1140 #[test]
1141 fn test_try_aggregate_encode() {
1142 let calls = vec![([0xAA; 20], vec![0x01, 0x02])];
1143 let calldata = encode_try_aggregate(true, &calls);
1144 let expected_selector = &keccak256(b"tryAggregate(bool,(address,bytes)[])")[..4];
1145 assert_eq!(&calldata[..4], expected_selector);
1146 }
1147
1148 #[test]
1149 fn test_multicall3_address() {
1150 assert_eq!(
1152 hex::encode(MULTICALL3_ADDRESS).to_lowercase(),
1153 "ca11bde05977b3631167028862be2a173976ca11"
1154 );
1155 }
1156}