api3_common/abi/
decode.rs1use crate::abi::{ParamType, Token, Word};
4use crate::Error;
5
6#[derive(Debug)]
7struct DecodeResult {
8 token: Token,
9 new_offset: usize,
10}
11
12fn as_usize(slice: &Word) -> Result<usize, Error> {
13 if !slice[..28].iter().all(|x| *x == 0) {
14 return Err(Error::InvalidData);
15 }
16
17 let result = ((slice[28] as usize) << 24)
18 + ((slice[29] as usize) << 16)
19 + ((slice[30] as usize) << 8)
20 + (slice[31] as usize);
21
22 Ok(result)
23}
24
25pub fn decode(types: &[ParamType], data: &[u8]) -> Result<Vec<Token>, Error> {
27 let is_empty_bytes_valid_encoding = types.iter().all(|t| t.is_empty_bytes_valid_encoding());
28 if !is_empty_bytes_valid_encoding && data.is_empty() {
29 return Err(Error::InvalidName(
30 "please ensure the contract and method you're calling exist! \
31 failed to decode empty bytes. if you're using jsonrpc this is \
32 likely due to jsonrpc returning `0x` in case contract or method \
33 don't exist"
34 .into(),
35 ));
36 }
37
38 let mut tokens = vec![];
39 let mut offset = 0;
40
41 for param in types {
42 let res = decode_param(param, data, offset)?;
43 offset = res.new_offset;
44 tokens.push(res.token);
45 }
46
47 Ok(tokens)
48}
49
50fn peek(data: &[u8], offset: usize, len: usize) -> Result<&[u8], Error> {
51 if offset + len > data.len() {
52 Err(Error::InvalidData)
53 } else {
54 Ok(&data[offset..(offset + len)])
55 }
56}
57
58fn peek_32_bytes(data: &[u8], offset: usize) -> Result<Word, Error> {
59 peek(data, offset, 32).map(|x| {
60 let mut out: Word = [0u8; 32];
61 out.copy_from_slice(&x[0..32]);
62 out
63 })
64}
65
66fn take_bytes(data: &[u8], offset: usize, len: usize) -> Result<Vec<u8>, Error> {
67 if offset + len > data.len() {
68 Err(Error::InvalidData)
69 } else {
70 Ok((data[offset..(offset + len)]).to_vec())
71 }
72}
73
74fn decode_param(param: &ParamType, data: &[u8], offset: usize) -> Result<DecodeResult, Error> {
75 match *param {
76 ParamType::Address => {
77 let slice = peek_32_bytes(data, offset)?;
78 let mut address = [0u8; 20];
79 address.copy_from_slice(&slice[12..]);
80 let result = DecodeResult {
81 token: Token::Address(address),
82 new_offset: offset + 32,
83 };
84 Ok(result)
85 }
86 ParamType::Uint(_) => {
87 let slice = peek_32_bytes(data, offset)?;
88 let result = DecodeResult {
89 token: Token::Uint(slice.into()),
90 new_offset: offset + 32,
91 };
92 Ok(result)
93 }
94 ParamType::Int(_) => {
95 let slice = peek_32_bytes(data, offset)?;
96 let result = DecodeResult {
97 token: Token::Int(slice.into()),
98 new_offset: offset + 32,
99 };
100 Ok(result)
101 }
102 ParamType::FixedBytes(len) => {
103 let bytes = take_bytes(data, offset, len)?;
106 let result = DecodeResult {
107 token: Token::FixedBytes(bytes),
108 new_offset: offset + 32,
109 };
110 Ok(result)
111 }
112 ParamType::Bytes => {
113 let dynamic_offset = as_usize(&peek_32_bytes(data, offset)?)?;
114 let len = as_usize(&peek_32_bytes(data, dynamic_offset)?)?;
115 let bytes = take_bytes(data, dynamic_offset + 32, len)?;
116 let result = DecodeResult {
117 token: Token::Bytes(bytes),
118 new_offset: offset + 32,
119 };
120 Ok(result)
121 }
122 ParamType::String => {
123 let dynamic_offset = as_usize(&peek_32_bytes(data, offset)?)?;
124 let len = as_usize(&peek_32_bytes(data, dynamic_offset)?)?;
125 let bytes = take_bytes(data, dynamic_offset + 32, len)?;
126 let result = DecodeResult {
127 token: Token::String(String::from_utf8_lossy(&*bytes).into()),
132 new_offset: offset + 32,
133 };
134 Ok(result)
135 }
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use crate::abi::decode::decode;
142 use crate::abi::types::ParamType;
143 use crate::abi::{Token, Uint};
144 use hex_literal::hex;
145
146 #[test]
147 fn decode_from_empty_byte_slice() {
148 assert!(decode(&[ParamType::Address], &[]).is_err());
150 assert!(decode(&[ParamType::Bytes], &[]).is_err());
151 assert!(decode(&[ParamType::String], &[]).is_err());
152 assert!(decode(&[ParamType::FixedBytes(1)], &[]).is_err());
153 assert!(decode(&[ParamType::FixedBytes(0)], &[]).is_ok());
155 }
156
157 #[test]
158 fn decode_data_with_size_that_is_not_a_multiple_of_32() {
159 let encoded = hex!(
160 "
161 0000000000000000000000000000000000000000000000000000000000000000
162 00000000000000000000000000000000000000000000000000000000000000a0
163 0000000000000000000000000000000000000000000000000000000000000152
164 0000000000000000000000000000000000000000000000000000000000000001
165 000000000000000000000000000000000000000000000000000000000054840d
166 0000000000000000000000000000000000000000000000000000000000000092
167 3132323033393637623533326130633134633938306235616566666231373034
168 3862646661656632633239336139353039663038656233633662306635663866
169 3039343265376239636337366361353163636132366365353436393230343438
170 6533303866646136383730623565326165313261323430396439343264653432
171 3831313350373230703330667073313678390000000000000000000000000000
172 0000000000000000000000000000000000103933633731376537633061363531
173 3761
174 "
175 );
176
177 assert_eq!(
178 decode(
179 &[
180 ParamType::Uint(256),
181 ParamType::String,
182 ParamType::String,
183 ParamType::Uint(256),
184 ParamType::Uint(256),
185 ],
186 &encoded,
187 ).unwrap(),
188 &[
189 Token::Uint(Uint::from(0u128)),
190 Token::String(String::from("12203967b532a0c14c980b5aeffb17048bdfaef2c293a9509f08eb3c6b0f5f8f0942e7b9cc76ca51cca26ce546920448e308fda6870b5e2ae12a2409d942de428113P720p30fps16x9")),
191 Token::String(String::from("93c717e7c0a6517a")),
192 Token::Uint(Uint::from(1u128)),
193 Token::Uint(Uint::from(5538829u128))
194 ]
195 );
196 }
197
198 #[test]
199 fn decode_after_fixed_bytes_with_less_than_32_bytes() {
200 let encoded = hex!(
201 "
202 0000000000000000000000008497afefdc5ac170a664a231f6efb25526ef813f
203 0000000000000000000000000000000000000000000000000000000000000000
204 0000000000000000000000000000000000000000000000000000000000000000
205 0000000000000000000000000000000000000000000000000000000000000080
206 000000000000000000000000000000000000000000000000000000000000000a
207 3078303030303030314600000000000000000000000000000000000000000000
208 "
209 );
210
211 assert_eq!(
212 decode(
213 &[
214 ParamType::Address,
215 ParamType::FixedBytes(32),
216 ParamType::FixedBytes(4),
217 ParamType::String,
218 ],
219 &encoded,
220 )
221 .unwrap(),
222 &[
223 Token::Address(hex!("8497afefdc5ac170a664a231f6efb25526ef813f").into()),
224 Token::FixedBytes([0u8; 32].to_vec()),
225 Token::FixedBytes([0u8; 4].to_vec()),
226 Token::String("0x0000001F".into()),
227 ]
228 )
229 }
230
231 #[test]
232 fn decode_broken_utf8() {
233 let encoded = hex!(
234 "
235 0000000000000000000000000000000000000000000000000000000000000020
236 0000000000000000000000000000000000000000000000000000000000000004
237 e4b88de500000000000000000000000000000000000000000000000000000000
238 "
239 );
240
241 assert_eq!(
242 decode(&[ParamType::String,], &encoded).unwrap(),
243 &[Token::String("不�".into())]
244 );
245 }
246}