ethane_abi/parameter/
mod.rs

1mod construction;
2pub mod display;
3mod encode_into;
4mod parameter_type;
5mod utils;
6
7pub use encode_into::encode_into;
8pub use parameter_type::ParameterType;
9use utils::*;
10
11use ethane_types::{Address, H256};
12
13/// An ABI function parameter type enclosing the underlying
14/// numeric data bytes.
15#[derive(Clone)]
16pub enum Parameter {
17    Address(H256),
18    Bool(H256),
19    Int(H256, usize),
20    Uint(H256, usize),
21    String(Vec<u8>),
22    Bytes(Vec<u8>),
23    FixedBytes(Vec<u8>),
24    Array(Vec<Parameter>),
25    FixedArray(Vec<Parameter>),
26    Tuple(Vec<Parameter>),
27}
28
29impl Parameter {
30    /// Encodes strictly the data part of the underlying type.
31    ///
32    /// It will not check whether the parameter is dynamic or not, it simply
33    /// encodes the enclosed data in place. For some types, it first writes the
34    /// number of elements of the data in bytes. For further info, check the
35    /// Solidity [contract ABI
36    /// specification](https://docs.soliditylang.org/en/v0.5.3/abi-spec.html#function-selector).
37    pub fn static_encode(&self) -> Vec<u8> {
38        match self {
39            Self::Address(data) | Self::Bool(data) | Self::Int(data, _) | Self::Uint(data, _) => {
40                data.as_bytes().to_vec()
41            }
42            Self::FixedBytes(data) => right_pad_to_32_multiples(data).to_vec(),
43            Self::Bytes(data) | Self::String(data) => {
44                let mut encoded = left_pad_to_32_bytes(&data.len().to_be_bytes()).to_vec();
45                encoded.extend_from_slice(&right_pad_to_32_multiples(data));
46                encoded
47            }
48            Self::FixedArray(params) | Self::Tuple(params) => {
49                let mut encoded = Vec::<u8>::new();
50                for p in params {
51                    encoded.extend_from_slice(&p.static_encode());
52                }
53                encoded
54            }
55            Self::Array(_) => panic!("Array type cannot be statically encoded!"),
56        }
57    }
58
59    /// Recursively checks wether a given parameter is dynamic.
60    ///
61    /// For example, a [`Tuple`](Parameter::Tuple) can be dynamic if any of its
62    /// contained types are dynamic. Additionally, a
63    /// [`FixedArray`](Parameter::FixedArray) is static if it contains values
64    /// with static type and dynamic otherwise.
65    pub fn is_dynamic(&self) -> bool {
66        match self {
67            Self::Array(_) | Self::Bytes(_) | Self::String(_) => true,
68            Self::FixedArray(parameters) | Self::Tuple(parameters) => {
69                parameters.iter().any(|x| x.is_dynamic())
70            }
71            _ => false,
72        }
73    }
74
75    pub fn decode(parameter_type: &ParameterType, raw_bytes: &[u8]) -> (Self, usize) {
76        match parameter_type {
77            ParameterType::Address => {
78                let mut bytes = [0u8; 20];
79                bytes.copy_from_slice(&raw_bytes[12..32]);
80                (Self::from(Address::from(bytes)), 32)
81            }
82            ParameterType::Bool => {
83                let mut bytes = [0u8; 32];
84                bytes.copy_from_slice(&raw_bytes[..32]);
85                (Self::Bool(H256::from(bytes)), 32)
86            }
87            ParameterType::Int(_) => {
88                let mut bytes = [0u8; 32];
89                bytes.copy_from_slice(&raw_bytes[..32]);
90                (Self::new_int(bytes, true), 32)
91            }
92            ParameterType::Uint(_) => {
93                let mut bytes = [0u8; 32];
94                bytes.copy_from_slice(&raw_bytes[..32]);
95                (Self::new_int(bytes, false), 32)
96            }
97            //ParameterType::String  => {
98            //    (Self::String(raw_bytes.to_vec()), )
99            //},
100            //ParameterType::Bytes  => {
101            //    Ok(Self::Bytes(raw_bytes.to_vec()))
102            //},
103            //ParameterType::FixedBytes(len) => {
104            //    Ok(Self::FixedBytes(raw_bytes.to_vec())
105            //},
106            //// TODO do we need more complicated types?
107            _ => unimplemented!(),
108        }
109    }
110}
111
112#[cfg(test)]
113mod test {
114    use super::*;
115
116    #[test]
117    #[rustfmt::skip]
118    fn parameter_encode() {
119        assert_eq!(Parameter::Address(H256::zero()).static_encode(), vec![0u8; 32]);
120        assert_eq!(Parameter::from("Hello, World!").static_encode(), vec![
121            0, 0, 0, 0, 0, 0, 0, 0,
122            0, 0, 0, 0, 0, 0, 0, 0,
123            0, 0, 0, 0, 0, 0, 0, 0,
124            0, 0, 0, 0, 0, 0, 0, 0x0d,
125            0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57,
126            0x6f, 0x72, 0x6c, 0x64, 0x21, 0, 0, 0,
127            0, 0, 0, 0, 0, 0, 0, 0,
128            0, 0, 0, 0, 0, 0, 0, 0,
129        ]); 
130        assert_eq!(Parameter::FixedArray(vec![
131                Parameter::Uint(H256::from_int_unchecked(0x4a_u8), 8),
132                Parameter::Uint(H256::from_int_unchecked(0xff_u8), 8),
133                Parameter::Uint(H256::from_int_unchecked(0xde_u8), 8),
134        ]).static_encode(),
135        vec![
136            0, 0, 0, 0, 0, 0, 0, 0,
137            0, 0, 0, 0, 0, 0, 0, 0,
138            0, 0, 0, 0, 0, 0, 0, 0,
139            0, 0, 0, 0, 0, 0, 0, 0x4a, // first
140            0, 0, 0, 0, 0, 0, 0, 0,
141            0, 0, 0, 0, 0, 0, 0, 0,
142            0, 0, 0, 0, 0, 0, 0, 0,
143            0, 0, 0, 0, 0, 0, 0, 0xff, // second
144            0, 0, 0, 0, 0, 0, 0, 0,
145            0, 0, 0, 0, 0, 0, 0, 0,
146            0, 0, 0, 0, 0, 0, 0, 0,
147            0, 0, 0, 0, 0, 0, 0, 0xde, // third
148        ]);
149    }
150
151    #[test]
152    fn parameter_is_dynamic() {
153        assert!(!Parameter::Address(H256::zero()).is_dynamic());
154        assert!(!Parameter::Bool(H256::zero()).is_dynamic());
155        assert!(Parameter::Bytes(Vec::new()).is_dynamic());
156        assert!(!Parameter::FixedBytes(Vec::new()).is_dynamic());
157        assert!(!Parameter::Uint(H256::zero(), 16).is_dynamic());
158        assert!(!Parameter::Int(H256::zero(), 32).is_dynamic());
159        assert!(Parameter::String(Vec::new()).is_dynamic());
160        assert!(Parameter::Array(vec![Parameter::Address(H256::zero()); 5]).is_dynamic());
161        assert!(Parameter::Array(vec![Parameter::Bytes(Vec::new())]).is_dynamic());
162        assert!(!Parameter::FixedArray(vec![Parameter::Uint(H256::zero(), 64); 3]).is_dynamic());
163        assert!(Parameter::FixedArray(vec![Parameter::String(Vec::new()); 2]).is_dynamic());
164        assert!(!Parameter::Tuple(vec![
165            Parameter::Address(H256::zero()),
166            Parameter::Uint(H256::zero(), 32),
167            Parameter::FixedBytes(Vec::new())
168        ])
169        .is_dynamic());
170        assert!(Parameter::Tuple(vec![
171            Parameter::FixedBytes(Vec::new()),
172            Parameter::Uint(H256::zero(), 32),
173            Parameter::String(Vec::new())
174        ])
175        .is_dynamic());
176        assert!(!Parameter::FixedArray(vec![
177            Parameter::FixedArray(vec![
178                Parameter::Int(
179                    H256::zero(),
180                    8
181                );
182                5
183            ]);
184            2
185        ])
186        .is_dynamic());
187        assert!(Parameter::Tuple(vec![
188            Parameter::FixedBytes(Vec::new()),
189            Parameter::Uint(H256::zero(), 32),
190            Parameter::FixedArray(vec![Parameter::String(Vec::new()); 3])
191        ])
192        .is_dynamic());
193    }
194
195    #[test]
196    #[rustfmt::skip]
197    fn decode_parameter() {
198        let result = vec![
199            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
200            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0xff,
201            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0xff,
202            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0c, 0xff,
203        ];
204
205        let mut index = 0;
206        let (addr, bytes_read) = Parameter::decode(&ParameterType::Address, &result);
207        index += bytes_read;
208        let (a, bytes_read) = Parameter::decode(&ParameterType::Uint(16), &result[index..]);
209        index += bytes_read;
210        let (b, bytes_read) = Parameter::decode(&ParameterType::Uint(16), &result[index..]);
211        index += bytes_read;
212        let (c, bytes_read) = Parameter::decode(&ParameterType::Uint(16), &result[index..]);
213        index += bytes_read;
214
215        assert_eq!(index, 128);
216        assert_eq!(addr.to_string(), String::from("0xffffffffffffffffffffffffffffffffffffffff"));
217        assert_eq!(a.to_string(), String::from("2815"));
218        assert_eq!(b.to_string(), String::from("3071"));
219        assert_eq!(c.to_string(), String::from("3327"));
220    }
221}