1use crate::error::SignerError;
15use sha3::{Digest, Keccak256};
16
17fn keccak256(data: &[u8]) -> [u8; 32] {
18 let mut out = [0u8; 32];
19 out.copy_from_slice(&Keccak256::digest(data));
20 out
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: u64) -> [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 let mut chain_buf = [0u8; 32];
186 chain_buf[24..].copy_from_slice(&chain_id.to_be_bytes());
187 data.extend_from_slice(&chain_buf);
188
189 keccak256(&data)
190 }
191
192 pub fn sign(
194 &self,
195 signer: &super::EthereumSigner,
196 entry_point: &[u8; 20],
197 chain_id: u64,
198 ) -> Result<super::EthereumSignature, SignerError> {
199 let hash = self.hash(entry_point, chain_id);
200 let eth_hash = eth_signed_message_hash(&hash);
202 signer.sign_digest(ð_hash)
203 }
204}
205
206fn eth_signed_message_hash(hash: &[u8; 32]) -> [u8; 32] {
207 let mut buf = Vec::with_capacity(28 + 32);
208 buf.extend_from_slice(b"\x19Ethereum Signed Message:\n32");
209 buf.extend_from_slice(hash);
210 keccak256(&buf)
211}
212
213#[derive(Debug, Clone)]
222pub struct Eip7702Authorization {
223 pub chain_id: u64,
225 pub address: [u8; 20],
227 pub nonce: u64,
229}
230
231impl Eip7702Authorization {
232 pub const MAGIC: u8 = 0x05;
234
235 #[must_use]
239 pub fn signing_hash(&self) -> [u8; 32] {
240 use super::rlp;
241 let mut items = Vec::new();
242 items.extend_from_slice(&rlp::encode_u64(self.chain_id));
243 items.extend_from_slice(&rlp::encode_bytes(&self.address));
244 items.extend_from_slice(&rlp::encode_u64(self.nonce));
245 let rlp_data = rlp::encode_list(&items);
246
247 let mut payload = vec![Self::MAGIC];
248 payload.extend_from_slice(&rlp_data);
249 keccak256(&payload)
250 }
251
252 pub fn sign(
254 &self,
255 signer: &super::EthereumSigner,
256 ) -> Result<super::EthereumSignature, SignerError> {
257 let hash = self.signing_hash();
258 signer.sign_digest(&hash)
259 }
260}
261
262#[derive(Debug, Clone)]
271pub struct AuthMessage {
272 pub invoker: [u8; 20],
274 pub commit: [u8; 32],
276}
277
278impl AuthMessage {
279 pub const MAGIC: u8 = 0x04;
281
282 #[must_use]
289 pub fn signing_hash(&self, chain_id: u64, nonce: u64) -> [u8; 32] {
290 let mut buf = Vec::with_capacity(1 + 4 * 32);
291 buf.push(Self::MAGIC);
292
293 let mut chain_buf = [0u8; 32];
295 chain_buf[24..].copy_from_slice(&chain_id.to_be_bytes());
296 buf.extend_from_slice(&chain_buf);
297
298 let mut nonce_buf = [0u8; 32];
300 nonce_buf[24..].copy_from_slice(&nonce.to_be_bytes());
301 buf.extend_from_slice(&nonce_buf);
302
303 let mut invoker_buf = [0u8; 32];
305 invoker_buf[12..].copy_from_slice(&self.invoker);
306 buf.extend_from_slice(&invoker_buf);
307
308 buf.extend_from_slice(&self.commit);
310
311 keccak256(&buf)
312 }
313
314 pub fn sign(
316 &self,
317 signer: &super::EthereumSigner,
318 chain_id: u64,
319 nonce: u64,
320 ) -> Result<super::EthereumSignature, SignerError> {
321 let hash = self.signing_hash(chain_id, nonce);
322 signer.sign_digest(&hash)
323 }
324}
325
326pub const EIP6492_MAGIC: [u8; 32] = [
332 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92,
333 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92,
334];
335
336#[must_use]
343pub fn wrap_eip6492_signature(
344 create2_factory: &[u8; 20],
345 factory_calldata: &[u8],
346 original_signature: &[u8],
347) -> Vec<u8> {
348 use super::abi::{self, AbiValue};
349 let mut encoded = abi::encode(&[
350 AbiValue::Address(*create2_factory),
351 AbiValue::Bytes(factory_calldata.to_vec()),
352 AbiValue::Bytes(original_signature.to_vec()),
353 ]);
354 encoded.extend_from_slice(&EIP6492_MAGIC);
355 encoded
356}
357
358#[must_use]
360pub fn is_eip6492_signature(signature: &[u8]) -> bool {
361 signature.len() > 32 && signature[signature.len() - 32..] == EIP6492_MAGIC
362}
363
364pub fn unwrap_eip6492_signature(signature: &[u8]) -> Result<&[u8], SignerError> {
369 if !is_eip6492_signature(signature) {
370 return Err(SignerError::ParseError("not an EIP-6492 signature".into()));
371 }
372 Ok(&signature[..signature.len() - 32])
373}
374
375#[must_use]
385pub fn encode_eip712_domain_call() -> Vec<u8> {
386 let selector = &keccak256(b"eip712Domain()")[..4];
388 selector.to_vec()
389}
390
391pub const EIP5267_SELECTOR: [u8; 4] = [0x84, 0xb0, 0x19, 0x6e];
393
394pub mod bls_paths {
400 pub fn withdrawal(validator_index: u32) -> Vec<u32> {
402 vec![12381, 3600, validator_index, 0]
403 }
404
405 pub fn signing(validator_index: u32) -> Vec<u32> {
407 vec![12381, 3600, validator_index, 0, 0]
408 }
409}
410
411pub const EIP2335_VERSION: u32 = 4;
413
414pub const EIP2335_KDF: &str = "scrypt";
416pub const EIP2335_CIPHER: &str = "aes-128-ctr";
418pub const EIP2335_CHECKSUM: &str = "sha256";
420
421#[derive(Debug, Clone)]
430pub struct TransferWithAuthorization {
431 pub from: [u8; 20],
433 pub to: [u8; 20],
435 pub value: [u8; 32],
437 pub valid_after: u64,
439 pub valid_before: u64,
441 pub nonce: [u8; 32],
443}
444
445impl TransferWithAuthorization {
446 #[must_use]
450 pub fn type_hash() -> [u8; 32] {
451 keccak256(b"TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
452 }
453
454 #[must_use]
456 pub fn struct_hash(&self) -> [u8; 32] {
457 let mut data = Vec::with_capacity(7 * 32);
458 data.extend_from_slice(&Self::type_hash());
459
460 let mut from_padded = [0u8; 32];
461 from_padded[12..].copy_from_slice(&self.from);
462 data.extend_from_slice(&from_padded);
463
464 let mut to_padded = [0u8; 32];
465 to_padded[12..].copy_from_slice(&self.to);
466 data.extend_from_slice(&to_padded);
467
468 data.extend_from_slice(&self.value);
469
470 let mut va = [0u8; 32];
471 va[24..].copy_from_slice(&self.valid_after.to_be_bytes());
472 data.extend_from_slice(&va);
473
474 let mut vb = [0u8; 32];
475 vb[24..].copy_from_slice(&self.valid_before.to_be_bytes());
476 data.extend_from_slice(&vb);
477
478 data.extend_from_slice(&self.nonce);
479
480 keccak256(&data)
481 }
482
483 #[must_use]
485 pub fn signing_hash(&self, domain_separator: &[u8; 32]) -> [u8; 32] {
486 eip712_signing_hash(domain_separator, &self.struct_hash())
487 }
488
489 pub fn sign(
491 &self,
492 signer: &super::EthereumSigner,
493 domain_separator: &[u8; 32],
494 ) -> Result<super::EthereumSignature, SignerError> {
495 let hash = self.signing_hash(domain_separator);
496 signer.sign_digest(&hash)
497 }
498}
499
500#[derive(Debug, Clone)]
502pub struct ReceiveWithAuthorization {
503 pub from: [u8; 20],
505 pub to: [u8; 20],
507 pub value: [u8; 32],
509 pub valid_after: u64,
511 pub valid_before: u64,
513 pub nonce: [u8; 32],
515}
516
517impl ReceiveWithAuthorization {
518 #[must_use]
520 pub fn type_hash() -> [u8; 32] {
521 keccak256(b"ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)")
522 }
523
524 #[must_use]
526 pub fn struct_hash(&self) -> [u8; 32] {
527 let mut data = Vec::with_capacity(7 * 32);
528 data.extend_from_slice(&Self::type_hash());
529
530 let mut from_padded = [0u8; 32];
531 from_padded[12..].copy_from_slice(&self.from);
532 data.extend_from_slice(&from_padded);
533
534 let mut to_padded = [0u8; 32];
535 to_padded[12..].copy_from_slice(&self.to);
536 data.extend_from_slice(&to_padded);
537
538 data.extend_from_slice(&self.value);
539
540 let mut va = [0u8; 32];
541 va[24..].copy_from_slice(&self.valid_after.to_be_bytes());
542 data.extend_from_slice(&va);
543
544 let mut vb = [0u8; 32];
545 vb[24..].copy_from_slice(&self.valid_before.to_be_bytes());
546 data.extend_from_slice(&vb);
547
548 data.extend_from_slice(&self.nonce);
549
550 keccak256(&data)
551 }
552
553 pub fn sign(
555 &self,
556 signer: &super::EthereumSigner,
557 domain_separator: &[u8; 32],
558 ) -> Result<super::EthereumSignature, SignerError> {
559 let hash = eip712_signing_hash(domain_separator, &self.struct_hash());
560 signer.sign_digest(&hash)
561 }
562}
563
564#[derive(Debug, Clone)]
566pub struct CancelAuthorization {
567 pub authorizer: [u8; 20],
569 pub nonce: [u8; 32],
571}
572
573impl CancelAuthorization {
574 #[must_use]
576 pub fn type_hash() -> [u8; 32] {
577 keccak256(b"CancelAuthorization(address authorizer,bytes32 nonce)")
578 }
579
580 #[must_use]
582 pub fn struct_hash(&self) -> [u8; 32] {
583 let mut data = Vec::with_capacity(3 * 32);
584 data.extend_from_slice(&Self::type_hash());
585
586 let mut auth_padded = [0u8; 32];
587 auth_padded[12..].copy_from_slice(&self.authorizer);
588 data.extend_from_slice(&auth_padded);
589
590 data.extend_from_slice(&self.nonce);
591
592 keccak256(&data)
593 }
594
595 pub fn sign(
597 &self,
598 signer: &super::EthereumSigner,
599 domain_separator: &[u8; 32],
600 ) -> Result<super::EthereumSignature, SignerError> {
601 let hash = eip712_signing_hash(domain_separator, &self.struct_hash());
602 signer.sign_digest(&hash)
603 }
604}
605
606#[derive(Debug, Clone)]
615pub struct Erc721Permit {
616 pub spender: [u8; 20],
618 pub token_id: [u8; 32],
620 pub nonce: u64,
622 pub deadline: u64,
624}
625
626impl Erc721Permit {
627 #[must_use]
631 pub fn type_hash() -> [u8; 32] {
632 keccak256(b"Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)")
633 }
634
635 #[must_use]
637 pub fn struct_hash(&self) -> [u8; 32] {
638 let mut data = Vec::with_capacity(5 * 32);
639 data.extend_from_slice(&Self::type_hash());
640
641 let mut spender_padded = [0u8; 32];
642 spender_padded[12..].copy_from_slice(&self.spender);
643 data.extend_from_slice(&spender_padded);
644
645 data.extend_from_slice(&self.token_id);
646
647 let mut nonce_buf = [0u8; 32];
648 nonce_buf[24..].copy_from_slice(&self.nonce.to_be_bytes());
649 data.extend_from_slice(&nonce_buf);
650
651 let mut deadline_buf = [0u8; 32];
652 deadline_buf[24..].copy_from_slice(&self.deadline.to_be_bytes());
653 data.extend_from_slice(&deadline_buf);
654
655 keccak256(&data)
656 }
657
658 #[must_use]
660 pub fn signing_hash(&self, domain_separator: &[u8; 32]) -> [u8; 32] {
661 eip712_signing_hash(domain_separator, &self.struct_hash())
662 }
663
664 pub fn sign(
666 &self,
667 signer: &super::EthereumSigner,
668 domain_separator: &[u8; 32],
669 ) -> Result<super::EthereumSignature, SignerError> {
670 let hash = self.signing_hash(domain_separator);
671 signer.sign_digest(&hash)
672 }
673}
674
675#[must_use]
690pub fn encode_multicall3(calls: &[([u8; 20], bool, Vec<u8>)]) -> Vec<u8> {
691 use super::abi::{self, AbiValue};
692
693 let selector = &keccak256(b"aggregate3((address,bool,bytes)[])")[..4];
695
696 let call_tuples: Vec<AbiValue> = calls
697 .iter()
698 .map(|(target, allow, cd)| {
699 AbiValue::Tuple(vec![
700 AbiValue::Address(*target),
701 AbiValue::Bool(*allow),
702 AbiValue::Bytes(cd.clone()),
703 ])
704 })
705 .collect();
706
707 let mut calldata = Vec::new();
708 calldata.extend_from_slice(selector);
709 calldata.extend_from_slice(&abi::encode(&[AbiValue::Array(call_tuples)]));
710 calldata
711}
712
713pub const MULTICALL3_ADDRESS: [u8; 20] = [
715 0xCA, 0x11, 0xBD, 0xE0, 0x59, 0x77, 0xB3, 0x63, 0x11, 0x67, 0x02, 0x88, 0x62, 0xBE, 0x2A, 0x17,
716 0x39, 0x76, 0xCA, 0x11,
717];
718
719#[must_use]
728pub fn encode_try_aggregate(require_success: bool, calls: &[([u8; 20], Vec<u8>)]) -> Vec<u8> {
729 use super::abi::{self, AbiValue};
730
731 let selector = &keccak256(b"tryAggregate(bool,(address,bytes)[])")[..4];
732
733 let call_tuples: Vec<AbiValue> = calls
734 .iter()
735 .map(|(target, cd)| {
736 AbiValue::Tuple(vec![
737 AbiValue::Address(*target),
738 AbiValue::Bytes(cd.clone()),
739 ])
740 })
741 .collect();
742
743 let mut calldata = Vec::new();
744 calldata.extend_from_slice(selector);
745 calldata.extend_from_slice(&abi::encode(&[
746 AbiValue::Bool(require_success),
747 AbiValue::Array(call_tuples),
748 ]));
749 calldata
750}
751
752fn eip712_signing_hash(domain_separator: &[u8; 32], struct_hash: &[u8; 32]) -> [u8; 32] {
755 let mut buf = Vec::with_capacity(2 + 32 + 32);
756 buf.push(0x19);
757 buf.push(0x01);
758 buf.extend_from_slice(domain_separator);
759 buf.extend_from_slice(struct_hash);
760 keccak256(&buf)
761}
762
763#[cfg(test)]
768#[allow(clippy::unwrap_used, clippy::expect_used)]
769mod tests {
770 use super::*;
771 use crate::traits::KeyPair;
772
773 #[test]
776 fn test_permit_type_hash() {
777 let hash = Permit::type_hash();
778 assert_eq!(
779 hex::encode(hash),
780 "6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9"
781 );
782 }
783
784 #[test]
785 fn test_permit_struct_hash_deterministic() {
786 let permit = Permit {
787 owner: [0xAA; 20],
788 spender: [0xBB; 20],
789 value: [0; 32],
790 nonce: 0,
791 deadline: u64::MAX,
792 };
793 assert_eq!(permit.struct_hash(), permit.struct_hash());
794 }
795
796 #[test]
797 fn test_permit_sign_roundtrip() {
798 let signer = super::super::EthereumSigner::generate().unwrap();
799 let permit = Permit {
800 owner: signer.address(),
801 spender: [0xBB; 20],
802 value: {
803 let mut v = [0u8; 32];
804 v[31] = 100;
805 v
806 },
807 nonce: 0,
808 deadline: u64::MAX,
809 };
810 let domain = [0xCC; 32]; let sig = permit.sign(&signer, &domain).unwrap();
812 assert_eq!(sig.r.len(), 32);
813 assert_eq!(sig.s.len(), 32);
814 }
815
816 #[test]
819 fn test_user_op_hash_deterministic() {
820 let op = UserOperation {
821 sender: [0xAA; 20],
822 nonce: [0; 32],
823 init_code: vec![],
824 call_data: vec![0x01, 0x02],
825 call_gas_limit: [0; 32],
826 verification_gas_limit: [0; 32],
827 pre_verification_gas: [0; 32],
828 max_fee_per_gas: [0; 32],
829 max_priority_fee_per_gas: [0; 32],
830 paymaster_and_data: vec![],
831 };
832 let entry_point = [0xBB; 20];
833 let h1 = op.hash(&entry_point, 1);
834 let h2 = op.hash(&entry_point, 1);
835 assert_eq!(h1, h2);
836 }
837
838 #[test]
839 fn test_user_op_different_chain_different_hash() {
840 let op = UserOperation {
841 sender: [0xAA; 20],
842 nonce: [0; 32],
843 init_code: vec![],
844 call_data: vec![],
845 call_gas_limit: [0; 32],
846 verification_gas_limit: [0; 32],
847 pre_verification_gas: [0; 32],
848 max_fee_per_gas: [0; 32],
849 max_priority_fee_per_gas: [0; 32],
850 paymaster_and_data: vec![],
851 };
852 let ep = [0xBB; 20];
853 assert_ne!(op.hash(&ep, 1), op.hash(&ep, 5));
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], 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}