precompile_utils/solidity/codec/
mod.rs1pub mod bytes;
23pub mod native;
24
25#[cfg(any(feature = "codec-xcm", test))]
26pub mod xcm;
27
28use crate::solidity::revert::{MayRevert, RevertReason};
29use alloc::{vec, vec::Vec};
30use core::{convert::TryInto, marker::PhantomData, ops::Range};
31use sp_core::{H256, U256};
32
33pub use alloc::string::String;
34pub use bytes::{BoundedBytes, BoundedString, UnboundedBytes, UnboundedString};
35pub use native::{Address, BoundedVec};
36
37pub use precompile_utils_macro::Codec;
39
40pub trait Codec: Sized {
42 fn read(reader: &mut Reader) -> MayRevert<Self>;
43 fn write(writer: &mut Writer, value: Self);
44 fn has_static_size() -> bool;
45 fn signature() -> String;
46 fn is_explicit_tuple() -> bool {
47 false
48 }
49}
50
51fn encode<T: Codec>(value: T) -> Vec<u8> {
54 Writer::new().write(value).build()
55}
56
57pub fn encode_arguments<T: Codec>(value: T) -> Vec<u8> {
61 let output = encode(value);
62 if T::is_explicit_tuple() && !T::has_static_size() {
63 output[32..].to_vec()
64 } else {
65 output
66 }
67}
68
69pub use self::{encode_arguments as encode_return_value, encode_arguments as encode_event_data};
70
71pub fn encode_with_selector<T: Codec>(selector: u32, value: T) -> Vec<u8> {
74 Writer::new_with_selector(selector)
75 .write_raw_bytes(&encode_arguments(value))
76 .build()
77}
78
79fn decode<T: Codec>(input: &[u8]) -> MayRevert<T> {
82 Reader::new(input).read()
83}
84
85pub fn decode_arguments<T: Codec>(input: &[u8]) -> MayRevert<T> {
89 if T::is_explicit_tuple() && !T::has_static_size() {
90 let writer = Writer::new();
91 let mut writer = writer.write(U256::from(32));
92 writer.write_pointer(input.to_vec());
93 let input = writer.build();
94 decode(&input)
95 } else {
96 decode(input)
97 }
98}
99
100pub use self::{decode_arguments as decode_return_value, decode_arguments as decode_event_data};
101
102pub fn selector(input: &[u8]) -> Option<u32> {
104 input.get(0..4).map(|s| {
105 let mut buffer = [0u8; 4];
106 buffer.copy_from_slice(s);
107 u32::from_be_bytes(buffer)
108 })
109}
110
111#[derive(Clone, Copy, Debug)]
113pub struct Reader<'inner> {
114 input: &'inner [u8],
115 cursor: usize,
116}
117
118impl<'inner> Reader<'inner> {
119 pub fn new(input: &'inner [u8]) -> Self {
121 Self { input, cursor: 0 }
122 }
123
124 pub fn new_skip_selector(input: &'inner [u8]) -> MayRevert<Self> {
126 if input.len() < 4 {
127 return Err(RevertReason::read_out_of_bounds("selector").into());
128 }
129
130 Ok(Self::new(&input[4..]))
131 }
132
133 pub fn expect_arguments(&self, args: usize) -> MayRevert {
135 if self.input.len() >= self.cursor + args * 32 {
136 Ok(())
137 } else {
138 Err(RevertReason::ExpectedAtLeastNArguments(args).into())
139 }
140 }
141
142 pub fn read<T: Codec>(&mut self) -> MayRevert<T> {
144 T::read(self)
145 }
146
147 pub fn read_raw_bytes(&mut self, len: usize) -> MayRevert<&[u8]> {
151 let range = self.move_cursor(len)?;
152
153 let data = self
154 .input
155 .get(range)
156 .ok_or_else(|| RevertReason::read_out_of_bounds("raw bytes"))?;
157
158 Ok(data)
159 }
160
161 pub fn read_pointer(&mut self) -> MayRevert<Self> {
163 let offset: usize = self
164 .read::<U256>()
165 .map_err(|_| RevertReason::read_out_of_bounds("pointer"))?
166 .try_into()
167 .map_err(|_| RevertReason::value_is_too_large("pointer"))?;
168
169 if offset >= self.input.len() {
170 return Err(RevertReason::PointerToOutofBound.into());
171 }
172
173 Ok(Self {
174 input: &self.input[offset..],
175 cursor: 0,
176 })
177 }
178
179 pub fn read_till_end(&mut self) -> MayRevert<&[u8]> {
181 let range = self.move_cursor(self.input.len() - self.cursor)?;
182
183 let data = self
184 .input
185 .get(range)
186 .ok_or_else(|| RevertReason::read_out_of_bounds("raw bytes"))?;
187
188 Ok(data)
189 }
190
191 fn move_cursor(&mut self, len: usize) -> MayRevert<Range<usize>> {
195 let start = self.cursor;
196 let end = self
197 .cursor
198 .checked_add(len)
199 .ok_or(RevertReason::CursorOverflow)?;
200
201 self.cursor = end;
202
203 Ok(start..end)
204 }
205}
206
207#[derive(Clone, Debug, Default)]
214pub struct Writer {
215 pub(crate) data: Vec<u8>,
216 offset_data: Vec<OffsetChunk>,
217 selector: Option<u32>,
218}
219
220#[derive(Clone, Debug)]
221struct OffsetChunk {
222 offset_position: usize,
224 data: Vec<u8>,
226 offset_shift: usize,
229}
230
231impl Writer {
232 pub fn new() -> Self {
234 Default::default()
235 }
236
237 pub fn new_with_selector(selector: impl Into<u32>) -> Self {
241 Self {
242 data: vec![],
243 offset_data: vec![],
244 selector: Some(selector.into()),
245 }
246 }
247
248 pub fn build(mut self) -> Vec<u8> {
250 Self::bake_offsets(&mut self.data, self.offset_data);
251
252 if let Some(selector) = self.selector {
253 let mut output = selector.to_be_bytes().to_vec();
254 output.append(&mut self.data);
255 output
256 } else {
257 self.data
258 }
259 }
260
261 fn bake_offsets(output: &mut Vec<u8>, offsets: Vec<OffsetChunk>) {
263 for mut offset_chunk in offsets {
264 let offset_position = offset_chunk.offset_position;
265 let offset_position_end = offset_position + 32;
266
267 let free_space_offset = output.len() - offset_chunk.offset_shift;
273
274 U256::from(free_space_offset)
276 .write_as_big_endian(&mut output[offset_position..offset_position_end]);
277
278 output.append(&mut offset_chunk.data);
280 }
281 }
282
283 fn write_raw_bytes(mut self, value: &[u8]) -> Self {
286 self.data.extend_from_slice(value);
287 self
288 }
289
290 pub fn write<T: Codec>(mut self, value: T) -> Self {
292 T::write(&mut self, value);
293 self
294 }
295
296 pub fn write_pointer(&mut self, data: Vec<u8>) {
303 let offset_position = self.data.len();
304 H256::write(self, H256::repeat_byte(0xff));
305
306 self.offset_data.push(OffsetChunk {
307 offset_position,
308 data,
309 offset_shift: 0,
310 });
311 }
312}
313
314#[derive(Clone, Copy, Debug)]
318pub struct Convert<P, C> {
319 inner: C,
320 _phantom: PhantomData<P>,
321}
322
323impl<P, C> From<C> for Convert<P, C> {
324 fn from(value: C) -> Self {
325 Self {
326 inner: value,
327 _phantom: PhantomData,
328 }
329 }
330}
331
332impl<P, C> Convert<P, C> {
333 pub fn converted(self) -> C {
334 self.inner
335 }
336}
337
338impl<P, C> Codec for Convert<P, C>
339where
340 P: Codec + TryInto<C>,
341 C: Codec + Into<P>,
342{
343 fn read(reader: &mut Reader) -> MayRevert<Self> {
344 let c = P::read(reader)?
345 .try_into()
346 .map_err(|_| RevertReason::value_is_too_large(C::signature()))?;
347
348 Ok(Self {
349 inner: c,
350 _phantom: PhantomData,
351 })
352 }
353
354 fn write(writer: &mut Writer, value: Self) {
355 P::write(writer, value.inner.into())
356 }
357
358 fn has_static_size() -> bool {
359 P::has_static_size()
360 }
361
362 fn signature() -> String {
363 P::signature()
364 }
365}