1use crate::error::SignerError;
29
30#[derive(Debug, Clone, PartialEq)]
34pub enum AbiValue {
35 Uint256([u8; 32]),
37 Int256([u8; 32]),
39 Address([u8; 20]),
41 Bool(bool),
43 FixedBytes(Vec<u8>),
45 Bytes(Vec<u8>),
47 String(String),
49 Array(Vec<AbiValue>),
51 Tuple(Vec<AbiValue>),
53}
54
55impl AbiValue {
56 #[must_use]
58 pub fn from_u64(val: u64) -> Self {
59 let mut buf = [0u8; 32];
60 buf[24..].copy_from_slice(&val.to_be_bytes());
61 AbiValue::Uint256(buf)
62 }
63
64 #[must_use]
66 pub fn from_u128(val: u128) -> Self {
67 let mut buf = [0u8; 32];
68 buf[16..].copy_from_slice(&val.to_be_bytes());
69 AbiValue::Uint256(buf)
70 }
71
72 fn is_dynamic(&self) -> bool {
74 matches!(
75 self,
76 AbiValue::Bytes(_) | AbiValue::String(_) | AbiValue::Array(_)
77 ) || matches!(self, AbiValue::Tuple(items) if items.iter().any(|i| i.is_dynamic()))
78 }
79
80 fn encode_head(&self) -> Vec<u8> {
82 match self {
83 AbiValue::Uint256(val) => val.to_vec(),
84 AbiValue::Int256(val) => val.to_vec(),
85 AbiValue::Address(addr) => {
86 let mut buf = [0u8; 32];
87 buf[12..].copy_from_slice(addr);
88 buf.to_vec()
89 }
90 AbiValue::Bool(b) => {
91 let mut buf = [0u8; 32];
92 buf[31] = if *b { 1 } else { 0 };
93 buf.to_vec()
94 }
95 AbiValue::FixedBytes(data) => {
96 let mut buf = [0u8; 32];
97 let len = data.len().min(32);
98 buf[..len].copy_from_slice(&data[..len]);
99 buf.to_vec()
100 }
101 _ => vec![0u8; 32],
103 }
104 }
105
106 fn encode_tail(&self) -> Vec<u8> {
108 match self {
109 AbiValue::Bytes(data) => encode_dynamic_bytes(data),
110 AbiValue::String(s) => encode_dynamic_bytes(s.as_bytes()),
111 AbiValue::Array(items) => {
112 let mut buf = Vec::new();
113 let mut len = [0u8; 32];
115 len[24..].copy_from_slice(&(items.len() as u64).to_be_bytes());
116 buf.extend_from_slice(&len);
117 buf.extend_from_slice(&encode_tuple(items));
119 buf
120 }
121 AbiValue::Tuple(items) => encode_tuple(items),
122 _ => vec![], }
124 }
125}
126
127pub fn encode(values: &[AbiValue]) -> Vec<u8> {
133 encode_tuple(values)
134}
135
136pub fn encode_packed(values: &[AbiValue]) -> Vec<u8> {
141 let mut buf = Vec::new();
142 for v in values {
143 match v {
144 AbiValue::Uint256(val) => {
145 let start = val.iter().position(|b| *b != 0).unwrap_or(31);
147 buf.extend_from_slice(&val[start..]);
148 }
149 AbiValue::Int256(val) => buf.extend_from_slice(val),
150 AbiValue::Address(addr) => buf.extend_from_slice(addr),
151 AbiValue::Bool(b) => buf.push(if *b { 1 } else { 0 }),
152 AbiValue::FixedBytes(data) => buf.extend_from_slice(data),
153 AbiValue::Bytes(data) => buf.extend_from_slice(data),
154 AbiValue::String(s) => buf.extend_from_slice(s.as_bytes()),
155 AbiValue::Array(items) => {
156 for item in items {
157 buf.extend_from_slice(&encode_packed(std::slice::from_ref(item)));
158 }
159 }
160 AbiValue::Tuple(items) => {
161 buf.extend_from_slice(&encode_packed(items));
162 }
163 }
164 }
165 buf
166}
167
168pub fn encode_and_hash(values: &[AbiValue]) -> [u8; 32] {
170 keccak256(&encode(values))
171}
172
173pub fn encode_packed_and_hash(values: &[AbiValue]) -> [u8; 32] {
177 keccak256(&encode_packed(values))
178}
179
180pub struct Function {
197 signature: String,
199 selector_bytes: [u8; 4],
201}
202
203impl Function {
204 #[must_use]
208 pub fn new(signature: &str) -> Self {
209 let hash = keccak256(signature.as_bytes());
210 let mut selector = [0u8; 4];
211 selector.copy_from_slice(&hash[..4]);
212 Self {
213 signature: signature.to_string(),
214 selector_bytes: selector,
215 }
216 }
217
218 #[must_use]
220 pub fn selector(&self) -> [u8; 4] {
221 self.selector_bytes
222 }
223
224 #[must_use]
226 pub fn signature(&self) -> &str {
227 &self.signature
228 }
229
230 #[must_use]
234 pub fn encode(&self, args: &[AbiValue]) -> Vec<u8> {
235 let mut calldata = Vec::with_capacity(4 + args.len() * 32);
236 calldata.extend_from_slice(&self.selector_bytes);
237 calldata.extend_from_slice(&encode(args));
238 calldata
239 }
240}
241
242#[must_use]
246pub fn function_selector(signature: &str) -> [u8; 4] {
247 Function::new(signature).selector()
248}
249
250#[must_use]
254pub fn event_topic(signature: &str) -> [u8; 32] {
255 keccak256(signature.as_bytes())
256}
257
258pub fn decode_uint256(data: &[u8]) -> Result<[u8; 32], SignerError> {
262 if data.len() < 32 {
263 return Err(SignerError::ParseError(
264 "ABI: need 32 bytes for uint256".into(),
265 ));
266 }
267 let mut buf = [0u8; 32];
268 buf.copy_from_slice(&data[..32]);
269 Ok(buf)
270}
271
272pub fn decode_uint256_as_u64(data: &[u8]) -> Result<u64, SignerError> {
274 let raw = decode_uint256(data)?;
275 if raw[..24].iter().any(|b| *b != 0) {
277 return Err(SignerError::ParseError(
278 "ABI: uint256 overflow for u64".into(),
279 ));
280 }
281 let mut buf = [0u8; 8];
282 buf.copy_from_slice(&raw[24..32]);
283 Ok(u64::from_be_bytes(buf))
284}
285
286pub fn decode_address(data: &[u8]) -> Result<[u8; 20], SignerError> {
288 if data.len() < 32 {
289 return Err(SignerError::ParseError(
290 "ABI: need 32 bytes for address".into(),
291 ));
292 }
293 if data[..12].iter().any(|b| *b != 0) {
294 return Err(SignerError::ParseError(
295 "ABI: non-canonical address padding".into(),
296 ));
297 }
298 let mut addr = [0u8; 20];
299 addr.copy_from_slice(&data[12..32]);
300 Ok(addr)
301}
302
303pub fn decode_bool(data: &[u8]) -> Result<bool, SignerError> {
305 if data.len() < 32 {
306 return Err(SignerError::ParseError(
307 "ABI: need 32 bytes for bool".into(),
308 ));
309 }
310 if data[..31].iter().any(|b| *b != 0) {
311 return Err(SignerError::ParseError(
312 "ABI: non-canonical bool padding".into(),
313 ));
314 }
315 match data[31] {
316 0 => Ok(false),
317 1 => Ok(true),
318 _ => Err(SignerError::ParseError(
319 "ABI: non-canonical bool value".into(),
320 )),
321 }
322}
323
324pub fn decode_bytes(data: &[u8], param_offset: usize) -> Result<Vec<u8>, SignerError> {
328 if param_offset > data.len() {
329 return Err(SignerError::ParseError(
330 "ABI: parameter offset out of range".into(),
331 ));
332 }
333 if param_offset % 32 != 0 {
334 return Err(SignerError::ParseError(
335 "ABI: parameter offset must be 32-byte aligned".into(),
336 ));
337 }
338
339 let offset_u64 = decode_uint256_as_u64(&data[param_offset..])?;
341 let offset = usize::try_from(offset_u64)
342 .map_err(|_| SignerError::ParseError("ABI: bytes offset exceeds usize".into()))?;
343 if offset % 32 != 0 {
344 return Err(SignerError::ParseError(
345 "ABI: bytes offset must be 32-byte aligned".into(),
346 ));
347 }
348
349 let start = offset
351 .checked_add(32)
352 .ok_or_else(|| SignerError::ParseError("ABI: bytes offset overflow".into()))?;
353 if start > data.len() {
354 return Err(SignerError::ParseError(
355 "ABI: bytes offset out of range".into(),
356 ));
357 }
358
359 let len_u64 = decode_uint256_as_u64(&data[offset..])?;
360 let len = usize::try_from(len_u64)
361 .map_err(|_| SignerError::ParseError("ABI: bytes length exceeds usize".into()))?;
362 let end = start
363 .checked_add(len)
364 .ok_or_else(|| SignerError::ParseError("ABI: bytes length overflow".into()))?;
365 if end > data.len() {
366 return Err(SignerError::ParseError("ABI: bytes data truncated".into()));
367 }
368 Ok(data[start..end].to_vec())
369}
370
371pub fn decode_string(data: &[u8], param_offset: usize) -> Result<String, SignerError> {
373 let bytes = decode_bytes(data, param_offset)?;
374 String::from_utf8(bytes)
375 .map_err(|e| SignerError::ParseError(format!("ABI: invalid UTF-8: {e}")))
376}
377
378#[must_use]
388pub fn encode_constructor(bytecode: &[u8], constructor_args: &[AbiValue]) -> Vec<u8> {
389 let mut data = bytecode.to_vec();
390 if !constructor_args.is_empty() {
391 data.extend_from_slice(&encode(constructor_args));
392 }
393 data
394}
395
396#[allow(clippy::too_many_arguments)]
398pub fn deploy_contract(
399 signer: &super::EthereumSigner,
400 bytecode: &[u8],
401 constructor_args: &[AbiValue],
402 chain_id: u64,
403 nonce: u64,
404 max_priority_fee_per_gas: u128,
405 max_fee_per_gas: u128,
406 gas_limit: u64,
407) -> Result<super::transaction::SignedTransaction, SignerError> {
408 let tx = super::transaction::EIP1559Transaction {
409 chain_id,
410 nonce,
411 max_priority_fee_per_gas,
412 max_fee_per_gas,
413 gas_limit,
414 to: None, value: 0,
416 data: encode_constructor(bytecode, constructor_args),
417 access_list: vec![],
418 };
419 tx.sign(signer)
420}
421
422pub struct ContractCall {
441 contract: [u8; 20],
443 function: Function,
445 args: Vec<AbiValue>,
447 value_wei: u128,
449}
450
451impl ContractCall {
452 #[must_use]
454 pub fn new(contract: [u8; 20], function_signature: &str) -> Self {
455 Self {
456 contract,
457 function: Function::new(function_signature),
458 args: Vec::new(),
459 value_wei: 0,
460 }
461 }
462
463 #[must_use]
465 pub fn args(mut self, args: &[AbiValue]) -> Self {
466 self.args = args.to_vec();
467 self
468 }
469
470 #[must_use]
472 pub fn value(mut self, value_wei: u128) -> Self {
473 self.value_wei = value_wei;
474 self
475 }
476
477 #[must_use]
481 pub fn calldata(&self) -> Vec<u8> {
482 self.function.encode(&self.args)
483 }
484
485 pub fn sign(
487 &self,
488 signer: &super::EthereumSigner,
489 chain_id: u64,
490 nonce: u64,
491 max_priority_fee_per_gas: u128,
492 max_fee_per_gas: u128,
493 gas_limit: u64,
494 ) -> Result<super::transaction::SignedTransaction, SignerError> {
495 let tx = super::transaction::EIP1559Transaction {
496 chain_id,
497 nonce,
498 max_priority_fee_per_gas,
499 max_fee_per_gas,
500 gas_limit,
501 to: Some(self.contract),
502 value: self.value_wei,
503 data: self.calldata(),
504 access_list: vec![],
505 };
506 tx.sign(signer)
507 }
508}
509
510fn keccak256(data: &[u8]) -> [u8; 32] {
513 super::keccak256(data)
514}
515
516fn encode_dynamic_bytes(data: &[u8]) -> Vec<u8> {
517 let mut buf = Vec::new();
518 let mut len = [0u8; 32];
520 len[24..].copy_from_slice(&(data.len() as u64).to_be_bytes());
521 buf.extend_from_slice(&len);
522 buf.extend_from_slice(data);
524 let padding = (32 - (data.len() % 32)) % 32;
525 buf.extend_from_slice(&vec![0u8; padding]);
526 buf
527}
528
529fn encode_tuple(values: &[AbiValue]) -> Vec<u8> {
530 let head_size = values.len() * 32;
531 let mut heads = Vec::with_capacity(head_size);
532 let mut tails = Vec::new();
533
534 for v in values {
535 if v.is_dynamic() {
536 let offset = head_size + tails.len();
538 let mut offset_bytes = [0u8; 32];
539 offset_bytes[24..].copy_from_slice(&(offset as u64).to_be_bytes());
540 heads.extend_from_slice(&offset_bytes);
541 tails.extend_from_slice(&v.encode_tail());
542 } else {
543 heads.extend_from_slice(&v.encode_head());
544 }
545 }
546
547 let mut result = Vec::with_capacity(heads.len() + tails.len());
548 result.extend_from_slice(&heads);
549 result.extend_from_slice(&tails);
550 result
551}
552
553#[cfg(test)]
556#[allow(clippy::unwrap_used, clippy::expect_used)]
557mod tests {
558 use super::*;
559 use crate::traits::KeyPair;
560
561 #[test]
564 fn test_selector_transfer() {
565 let sel = function_selector("transfer(address,uint256)");
567 assert_eq!(hex::encode(sel), "a9059cbb");
568 }
569
570 #[test]
571 fn test_selector_approve() {
572 let sel = function_selector("approve(address,uint256)");
574 assert_eq!(hex::encode(sel), "095ea7b3");
575 }
576
577 #[test]
578 fn test_selector_balance_of() {
579 let sel = function_selector("balanceOf(address)");
581 assert_eq!(hex::encode(sel), "70a08231");
582 }
583
584 #[test]
585 fn test_selector_total_supply() {
586 let sel = function_selector("totalSupply()");
588 assert_eq!(hex::encode(sel), "18160ddd");
589 }
590
591 #[test]
592 fn test_event_topic_transfer() {
593 let topic = event_topic("Transfer(address,address,uint256)");
595 assert_eq!(
596 hex::encode(topic),
597 "ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
598 );
599 }
600
601 #[test]
602 fn test_event_topic_approval() {
603 let topic = event_topic("Approval(address,address,uint256)");
604 assert_eq!(
605 hex::encode(topic),
606 "8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"
607 );
608 }
609
610 #[test]
613 fn test_encode_uint256() {
614 let val = AbiValue::from_u64(42);
615 let encoded = encode(&[val]);
616 assert_eq!(encoded.len(), 32);
617 assert_eq!(encoded[31], 42);
618 assert!(encoded[..31].iter().all(|b| *b == 0));
619 }
620
621 #[test]
622 fn test_encode_address() {
623 let addr = [0xAA; 20];
624 let encoded = encode(&[AbiValue::Address(addr)]);
625 assert_eq!(encoded.len(), 32);
626 assert!(encoded[..12].iter().all(|b| *b == 0)); assert_eq!(&encoded[12..], &[0xAA; 20]);
628 }
629
630 #[test]
631 fn test_encode_bool() {
632 let encoded_true = encode(&[AbiValue::Bool(true)]);
633 assert_eq!(encoded_true[31], 1);
634 let encoded_false = encode(&[AbiValue::Bool(false)]);
635 assert_eq!(encoded_false[31], 0);
636 }
637
638 #[test]
639 fn test_encode_dynamic_bytes() {
640 let data = vec![0xDE, 0xAD, 0xBE, 0xEF];
641 let encoded = encode(&[AbiValue::Bytes(data.clone())]);
642 assert_eq!(encoded[31], 32);
644 assert_eq!(encoded[63], 4); assert_eq!(&encoded[64..68], &data);
647 }
648
649 #[test]
650 fn test_encode_string() {
651 let s = "hello";
652 let encoded = encode(&[AbiValue::String(s.to_string())]);
653 assert_eq!(encoded[31], 32); assert_eq!(encoded[63], 5); assert_eq!(&encoded[64..69], b"hello");
656 }
657
658 #[test]
659 fn test_encode_multiple_static() {
660 let encoded = encode(&[AbiValue::Address([0xBB; 20]), AbiValue::from_u64(100)]);
662 assert_eq!(encoded.len(), 64); assert_eq!(&encoded[12..32], &[0xBB; 20]);
664 assert_eq!(encoded[63], 100);
665 }
666
667 #[test]
668 fn test_function_encode_transfer() {
669 let transfer = Function::new("transfer(address,uint256)");
670 let calldata = transfer.encode(&[AbiValue::Address([0xCC; 20]), AbiValue::from_u64(1000)]);
671 assert_eq!(&calldata[..4], &hex::decode("a9059cbb").unwrap());
672 assert_eq!(calldata.len(), 4 + 64);
673 }
674
675 #[test]
678 fn test_encode_packed_address_uint() {
679 let packed = encode_packed(&[AbiValue::Address([0xAA; 20]), AbiValue::from_u64(1)]);
680 assert_eq!(&packed[..20], &[0xAA; 20]);
682 assert_eq!(packed[20], 1);
683 }
684
685 #[test]
686 fn test_encode_packed_and_hash() {
687 let hash = encode_packed_and_hash(&[
688 AbiValue::String("hello".to_string()),
689 AbiValue::String("world".to_string()),
690 ]);
691 let expected = keccak256(b"helloworld");
693 assert_eq!(hash, expected);
694 }
695
696 #[test]
699 fn test_decode_uint256_roundtrip() {
700 let val = AbiValue::from_u64(12345);
701 let encoded = encode(&[val]);
702 let decoded = decode_uint256_as_u64(&encoded).unwrap();
703 assert_eq!(decoded, 12345);
704 }
705
706 #[test]
707 fn test_decode_address_roundtrip() {
708 let addr = [0xDD; 20];
709 let encoded = encode(&[AbiValue::Address(addr)]);
710 let decoded = decode_address(&encoded).unwrap();
711 assert_eq!(decoded, addr);
712 }
713
714 #[test]
715 fn test_decode_bool_roundtrip() {
716 let encoded = encode(&[AbiValue::Bool(true)]);
717 assert!(decode_bool(&encoded).unwrap());
718 let encoded = encode(&[AbiValue::Bool(false)]);
719 assert!(!decode_bool(&encoded).unwrap());
720 }
721
722 #[test]
723 fn test_decode_address_rejects_non_canonical_padding() {
724 let mut encoded = encode(&[AbiValue::Address([0x11; 20])]);
725 encoded[0] = 0x01; assert!(decode_address(&encoded).is_err());
727 }
728
729 #[test]
730 fn test_decode_bool_rejects_non_canonical_value() {
731 let mut encoded = [0u8; 32];
732 encoded[31] = 2; assert!(decode_bool(&encoded).is_err());
734 }
735
736 #[test]
737 fn test_decode_bool_rejects_non_canonical_padding() {
738 let mut encoded = [0u8; 32];
739 encoded[0] = 1; encoded[31] = 1;
741 assert!(decode_bool(&encoded).is_err());
742 }
743
744 #[test]
745 fn test_decode_bytes_roundtrip() {
746 let data = vec![0xCA, 0xFE, 0xBA, 0xBE];
747 let encoded = encode(&[AbiValue::Bytes(data.clone())]);
748 let decoded = decode_bytes(&encoded, 0).unwrap();
749 assert_eq!(decoded, data);
750 }
751
752 #[test]
753 fn test_decode_string_roundtrip() {
754 let s = "Hello, Ethereum!";
755 let encoded = encode(&[AbiValue::String(s.to_string())]);
756 let decoded = decode_string(&encoded, 0).unwrap();
757 assert_eq!(decoded, s);
758 }
759
760 #[test]
761 fn test_decode_bytes_param_offset_out_of_range() {
762 let encoded = encode(&[AbiValue::Bytes(vec![0xAA, 0xBB])]);
763 assert!(decode_bytes(&encoded, encoded.len() + 1).is_err());
764 }
765
766 #[test]
767 fn test_decode_bytes_rejects_unaligned_param_offset() {
768 let encoded = encode(&[AbiValue::Bytes(vec![0xAA, 0xBB])]);
769 assert!(decode_bytes(&encoded, 1).is_err());
770 }
771
772 #[test]
773 fn test_decode_bytes_rejects_unaligned_dynamic_offset() {
774 let mut encoded = encode(&[AbiValue::Bytes(vec![0xAA, 0xBB])]);
775 encoded[31] = 0x21;
777 assert!(decode_bytes(&encoded, 0).is_err());
778 }
779
780 #[test]
783 fn test_encode_constructor_no_args() {
784 let bytecode = vec![0x60, 0x00, 0x60, 0x00]; let data = encode_constructor(&bytecode, &[]);
786 assert_eq!(data, bytecode);
787 }
788
789 #[test]
790 fn test_encode_constructor_with_args() {
791 let bytecode = vec![0x60, 0x00];
792 let data = encode_constructor(&bytecode, &[AbiValue::from_u64(42)]);
793 assert_eq!(&data[..2], &bytecode);
794 assert_eq!(data.len(), 2 + 32);
795 assert_eq!(data[33], 42);
796 }
797
798 #[test]
799 fn test_deploy_contract_signs() {
800 let signer = super::super::EthereumSigner::generate().unwrap();
801 let signed = deploy_contract(
802 &signer,
803 &[0x60, 0x00],
804 &[],
805 1,
806 0,
807 2_000_000_000,
808 100_000_000_000,
809 1_000_000,
810 )
811 .unwrap();
812 assert_eq!(signed.raw_tx()[0], 0x02); }
814
815 #[test]
818 fn test_contract_call_calldata() {
819 let call = ContractCall::new([0xAA; 20], "transfer(address,uint256)")
820 .args(&[AbiValue::Address([0xBB; 20]), AbiValue::from_u64(1000)]);
821 let cd = call.calldata();
822 assert_eq!(&cd[..4], &hex::decode("a9059cbb").unwrap());
823 }
824
825 #[test]
826 fn test_contract_call_sign() {
827 let signer = super::super::EthereumSigner::generate().unwrap();
828 let call = ContractCall::new([0xAA; 20], "transfer(address,uint256)")
829 .args(&[AbiValue::Address([0xBB; 20]), AbiValue::from_u64(1000)])
830 .value(0);
831 let signed = call
832 .sign(&signer, 1, 0, 2_000_000_000, 100_000_000_000, 100_000)
833 .unwrap();
834 assert_eq!(signed.raw_tx()[0], 0x02);
835 }
836
837 #[test]
840 fn test_encode_fixed_bytes() {
841 let val = AbiValue::FixedBytes(vec![0xAA, 0xBB, 0xCC, 0xDD]);
842 let encoded = encode(&[val]);
843 assert_eq!(encoded.len(), 32);
844 assert_eq!(&encoded[..4], &[0xAA, 0xBB, 0xCC, 0xDD]);
845 assert!(encoded[4..].iter().all(|b| *b == 0)); }
847
848 #[test]
851 fn test_encode_array() {
852 let arr = AbiValue::Array(vec![
853 AbiValue::from_u64(1),
854 AbiValue::from_u64(2),
855 AbiValue::from_u64(3),
856 ]);
857 let encoded = encode(&[arr]);
858 assert_eq!(encoded.len(), 32 + 32 + 3 * 32); }
862}