ethers_core/types/transaction/
mod.rs

1pub mod request;
2pub mod response;
3
4pub mod eip1559;
5pub mod eip2718;
6pub mod eip2930;
7
8#[cfg(feature = "optimism")]
9pub mod optimism;
10
11pub mod eip712;
12
13pub(crate) const BASE_NUM_TX_FIELDS: usize = 9;
14
15// Number of tx fields before signing
16#[cfg(not(feature = "celo"))]
17pub(crate) const NUM_TX_FIELDS: usize = BASE_NUM_TX_FIELDS;
18// Celo has 3 additional fields
19#[cfg(feature = "celo")]
20pub(crate) const NUM_TX_FIELDS: usize = BASE_NUM_TX_FIELDS + 3;
21
22pub(super) fn rlp_opt<T: rlp::Encodable>(rlp: &mut rlp::RlpStream, opt: &Option<T>) {
23    if let Some(inner) = opt {
24        rlp.append(inner);
25    } else {
26        rlp.append(&"");
27    }
28}
29
30pub(super) fn rlp_opt_list<T: rlp::Encodable>(rlp: &mut rlp::RlpStream, opt: &Option<T>) {
31    if let Some(inner) = opt {
32        rlp.append(inner);
33    } else {
34        // Choice of `u8` type here is arbitrary as all empty lists are encoded the same.
35        rlp.append_list::<u8, u8>(&[]);
36    }
37}
38
39/// normalizes the signature back to 0/1
40pub(crate) fn normalize_v(v: u64, chain_id: crate::types::U64) -> u64 {
41    if v > 1 {
42        v - chain_id.as_u64() * 2 - 35
43    } else {
44        v
45    }
46}
47
48/// extracts the chainid from the signature v value based on EIP-155
49pub(crate) fn extract_chain_id(v: u64) -> Option<crate::types::U64> {
50    // https://eips.ethereum.org/EIPS/eip-155
51    // if chainid is available, v = {0, 1} + CHAIN_ID * 2 + 35
52    if v >= 35 {
53        return Some(crate::types::U64::from((v - 35) >> 1))
54    }
55    None
56}
57
58/// Decodes the signature portion of the RLP encoding based on the RLP offset passed.
59/// Increments the offset for each element parsed.
60#[inline]
61fn decode_signature(
62    rlp: &rlp::Rlp,
63    offset: &mut usize,
64) -> Result<super::Signature, rlp::DecoderError> {
65    let sig = super::Signature {
66        v: rlp.val_at(*offset)?,
67        r: rlp.val_at(*offset + 1)?,
68        s: rlp.val_at(*offset + 2)?,
69    };
70    *offset += 3;
71    Ok(sig)
72}
73
74/// Decodes the `to` field of the RLP encoding based on the RLP offset passed. Increments the offset
75/// by one.
76#[inline]
77fn decode_to(
78    rlp: &rlp::Rlp,
79    offset: &mut usize,
80) -> Result<Option<super::Address>, rlp::DecoderError> {
81    let to = {
82        let to = rlp.at(*offset)?;
83        if to.is_empty() {
84            if to.is_data() {
85                None
86            } else {
87                return Err(rlp::DecoderError::RlpExpectedToBeData)
88            }
89        } else {
90            Some(to.as_val()?)
91        }
92    };
93    *offset += 1;
94
95    Ok(to)
96}
97
98#[cfg(test)]
99mod tests {
100    use crate::types::{transaction::rlp_opt, U64};
101    use rlp::RlpStream;
102
103    #[test]
104    fn test_rlp_opt_none() {
105        let mut stream = RlpStream::new_list(1);
106        let empty_chainid: Option<U64> = None;
107        rlp_opt(&mut stream, &empty_chainid);
108        let out = stream.out();
109        assert_eq!(out, vec![0xc1, 0x80]);
110    }
111}