1#[macro_use]
18mod macros;
19
20mod bytes;
21mod encodable;
22mod error;
23mod params;
24mod result;
25mod types;
26mod utils;
27
28#[cfg(test)]
29mod tests;
30
31use core::ops::Deref;
32
33use alloy_sol_types::SolType as AlloySolType;
34use impl_trait_for_tuples::impl_for_tuples;
35use ink_prelude::{
36 borrow::Cow,
37 boxed::Box,
38 string::String,
39 vec::Vec,
40};
41use itertools::Itertools;
42use primitive_types::{
43 H256,
44 U256,
45};
46use sp_weights::Weight;
47
48pub use self::{
49 bytes::{
50 ByteSlice,
51 DynBytes,
52 FixedBytes,
53 },
54 error::{
55 SolErrorDecode,
56 SolErrorEncode,
57 },
58 params::{
59 SolParamsDecode,
60 SolParamsEncode,
61 },
62 result::{
63 SolResultDecode,
64 SolResultDecodeError,
65 },
66 types::{
67 SolTopicEncode,
68 SolTypeDecode,
69 SolTypeEncode,
70 },
71};
72
73use crate::types::{
74 AccountId,
75 Address,
76 Hash,
77};
78
79pub trait SolDecode: Sized {
118 type SolType: SolTypeDecode;
120
121 const SOL_NAME: &'static str =
123 <<Self::SolType as SolTypeDecode>::AlloyType as AlloySolType>::SOL_NAME;
124
125 fn decode(data: &[u8]) -> Result<Self, Error> {
127 <Self::SolType as SolTypeDecode>::decode(data).and_then(Self::from_sol_type)
128 }
129
130 fn from_sol_type(value: Self::SolType) -> Result<Self, Error>;
132}
133
134pub trait SolEncode<'a> {
168 type SolType: SolTypeEncode + SolTopicEncode;
174
175 const SOL_NAME: &'static str =
177 <<Self::SolType as SolTypeEncode>::AlloyType as AlloySolType>::SOL_NAME;
178
179 #[doc(hidden)]
181 const DYNAMIC: bool =
182 <<Self::SolType as SolTypeEncode>::AlloyType as AlloySolType>::DYNAMIC;
183
184 fn encode(&'a self) -> Vec<u8> {
186 <Self::SolType as SolTypeEncode>::encode(&self.to_sol_type())
187 }
188
189 fn encode_topic<H>(&'a self, hasher: H) -> [u8; 32]
191 where
192 H: Fn(&[u8], &mut [u8; 32]),
193 {
194 <Self::SolType as SolTopicEncode>::encode_topic(&self.to_sol_type(), hasher)
195 }
196
197 fn to_sol_type(&'a self) -> Self::SolType;
200}
201
202pub fn encode_sequence<T: for<'a> SolParamsEncode<'a>>(value: &T) -> Vec<u8> {
213 SolParamsEncode::encode(value)
214}
215
216pub fn decode_sequence<T: SolParamsDecode>(data: &[u8]) -> Result<T, Error> {
224 SolParamsDecode::decode(data)
225}
226
227#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229pub struct Error;
230
231impl From<alloy_sol_types::Error> for Error {
232 fn from(_: alloy_sol_types::Error) -> Self {
233 Self
234 }
235}
236
237impl core::fmt::Display for Error {
238 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239 f.write_str("Solidity ABI encode/decode error")
240 }
241}
242
243macro_rules! impl_primitive_decode {
244 ($($ty: ty),+ $(,)*) => {
245 $(
246 impl SolDecode for $ty {
247 type SolType = $ty;
248
249 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
250 Ok(value)
251 }
252 }
253 )*
254 };
255}
256
257macro_rules! impl_primitive_encode {
258 ($($ty: ty),+ $(,)*) => {
259 $(
260 impl SolEncode<'_> for $ty {
261 type SolType = $ty;
262
263 fn to_sol_type(&self) -> Self::SolType {
264 *self
265 }
266 }
267 )*
268 };
269}
270
271macro_rules! impl_primitive {
272 ($($ty: ty),+ $(,)*) => {
273 $(
274 impl_primitive_decode!($ty);
275
276 impl_primitive_encode!($ty);
277 )*
278 };
279}
280
281macro_rules! impl_primitive_encode_by_ref {
282 ($($ty: ty, $ref_ty: ty),+ $(,)*) => {
283 $(
284 impl<'a> SolEncode<'a> for $ty {
285 type SolType = &'a $ref_ty;
286
287 fn to_sol_type(&'a self) -> Self::SolType {
288 self
289 }
290 }
291 )*
292 };
293}
294
295macro_rules! impl_primitive_by_ref {
296 ($($ty: ty, $ref_ty: ty),+ $(,)*) => {
297 $(
298 impl_primitive_decode!($ty);
299
300 impl_primitive_encode_by_ref!($ty, $ref_ty);
301 )*
302 };
303}
304
305impl_primitive! {
306 bool,
308 i8, i16, i32, i64, i128,
310 u8, u16, u32, u64, u128, U256,
312 Address,
314}
315
316impl_primitive_by_ref! {
317 String, str,
319 Box<str>, str,
320}
321
322impl<T: SolDecode, const N: usize> SolDecode for [T; N] {
324 type SolType = [T::SolType; N];
325
326 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
327 value
331 .into_iter()
332 .map(<T as SolDecode>::from_sol_type)
333 .process_results(|iter| iter.collect_array())?
334 .ok_or(Error)
335 }
336}
337
338impl<'a, T: SolEncode<'a>, const N: usize> SolEncode<'a> for [T; N] {
339 type SolType = [T::SolType; N];
340
341 fn to_sol_type(&'a self) -> Self::SolType {
342 self.each_ref().map(<T as SolEncode>::to_sol_type)
343 }
344}
345
346impl<T: SolDecode> SolDecode for Vec<T> {
348 type SolType = Vec<T::SolType>;
349
350 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
351 value
352 .into_iter()
353 .map(<T as SolDecode>::from_sol_type)
354 .collect()
355 }
356}
357
358impl<'a, T: SolEncode<'a>> SolEncode<'a> for Vec<T> {
359 type SolType = Vec<T::SolType>;
360
361 fn to_sol_type(&'a self) -> Self::SolType {
362 self.iter().map(<T as SolEncode>::to_sol_type).collect()
363 }
364}
365
366impl<T: SolDecode> SolDecode for Box<[T]> {
368 type SolType = Box<[T::SolType]>;
369
370 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
371 core::iter::IntoIterator::into_iter(value)
375 .map(<T as SolDecode>::from_sol_type)
376 .process_results(|iter| iter.collect())
377 }
378}
379
380impl<'a, T: SolEncode<'a>> SolEncode<'a> for Box<[T]> {
381 type SolType = Box<[T::SolType]>;
382
383 fn to_sol_type(&'a self) -> Self::SolType {
384 self.iter().map(<T as SolEncode>::to_sol_type).collect()
385 }
386}
387
388#[impl_for_tuples(12)]
392impl SolDecode for Tuple {
393 for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
394
395 #[allow(clippy::unused_unit)]
396 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
397 Ok(for_tuples! { ( #( Tuple::from_sol_type(value.Tuple)? ),* ) })
398 }
399}
400
401#[impl_for_tuples(12)]
402impl<'a> SolEncode<'a> for Tuple {
403 for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
404
405 #[allow(clippy::unused_unit)]
406 fn to_sol_type(&'a self) -> Self::SolType {
407 for_tuples!( ( #( self.Tuple.to_sol_type() ),* ) )
408 }
409}
410
411macro_rules! impl_refs_encode {
413 ($($ty: ty), +$(,)*) => {
414 $(
415 impl<'a, T> SolEncode<'a> for $ty
416 where
417 T: SolEncode<'a>,
418 {
419 type SolType = T::SolType;
420
421 fn to_sol_type(&'a self) -> Self::SolType {
422 <T as SolEncode>::to_sol_type(self)
423 }
424 }
425 )*
426 };
427}
428
429impl_refs_encode! {
430 &T,
431 &mut T,
432 Box<T>,
433}
434
435impl<'a, T> SolEncode<'a> for Cow<'_, T>
436where
437 T: SolEncode<'a> + Clone,
438{
439 type SolType = T::SolType;
440
441 fn to_sol_type(&'a self) -> Self::SolType {
442 <T as SolEncode>::to_sol_type(self.deref())
443 }
444}
445
446macro_rules! impl_str_ref_encode {
448 ($($ty: ty),+ $(,)*) => {
449 $(
450 impl<'a> SolEncode<'a> for $ty {
451 type SolType = &'a str;
452
453 fn to_sol_type(&'a self) -> Self::SolType {
454 self
455 }
456 }
457 )*
458 };
459}
460
461impl_str_ref_encode!(&str, &mut str);
462
463macro_rules! impl_slice_ref_encode {
464 ($($ty: ty),+ $(,)*) => {
465 $(
466 impl<'a, T> SolEncode<'a> for $ty
467 where
468 T: SolEncode<'a>,
469 {
470 type SolType = Vec<T::SolType>;
471
472 fn to_sol_type(&'a self) -> Self::SolType {
473 self.iter().map(<T as SolEncode>::to_sol_type).collect()
474 }
475 }
476 )*
477 };
478}
479
480impl_slice_ref_encode!(&[T], &mut [T]);
481
482impl<T> SolDecode for Option<T>
503where
504 T: SolDecode,
505{
506 type SolType = Option<T::SolType>;
507
508 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
509 value.map(<T as SolDecode>::from_sol_type).transpose()
510 }
511}
512
513impl<'a, T> SolEncode<'a> for Option<T>
514where
515 T: SolEncode<'a>,
516{
517 type SolType = Option<T::SolType>;
518
519 fn to_sol_type(&'a self) -> Self::SolType {
520 self.as_ref().map(T::to_sol_type)
521 }
522}
523
524impl<T> SolDecode for core::marker::PhantomData<T> {
526 type SolType = ();
527
528 fn decode(_: &[u8]) -> Result<Self, Error>
529 where
530 Self: Sized,
531 {
532 Ok(core::marker::PhantomData)
534 }
535
536 fn from_sol_type(_: Self::SolType) -> Result<Self, Error> {
537 Ok(core::marker::PhantomData)
538 }
539}
540
541impl<T> SolEncode<'_> for core::marker::PhantomData<T> {
542 type SolType = ();
543
544 fn encode(&self) -> Vec<u8> {
545 Vec::new()
546 }
547
548 fn to_sol_type(&self) {}
549}
550
551impl SolDecode for AccountId {
553 type SolType = FixedBytes<32>;
554
555 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
556 Ok(AccountId(value.0))
557 }
558}
559
560impl<'a> SolEncode<'a> for AccountId {
561 type SolType = &'a FixedBytes<32>;
562
563 fn to_sol_type(&'a self) -> Self::SolType {
564 FixedBytes::from_ref(self.as_ref())
565 }
566}
567
568impl SolDecode for Hash {
570 type SolType = FixedBytes<32>;
571
572 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
573 Ok(Hash::from(value.0))
574 }
575}
576
577impl<'a> SolEncode<'a> for Hash {
578 type SolType = &'a FixedBytes<32>;
579
580 fn to_sol_type(&'a self) -> Self::SolType {
581 use core::borrow::Borrow;
582 FixedBytes::from_ref(self.borrow())
583 }
584}
585
586impl SolDecode for H256 {
588 type SolType = FixedBytes<32>;
589
590 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
591 Ok(H256(value.0))
592 }
593}
594
595impl<'a> SolEncode<'a> for H256 {
596 type SolType = &'a FixedBytes<32>;
597
598 fn to_sol_type(&'a self) -> Self::SolType {
599 FixedBytes::from_ref(self.as_fixed_bytes())
600 }
601}
602
603impl SolDecode for Weight {
605 type SolType = (u64, u64);
606
607 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
608 Ok(Weight::from_parts(value.0, value.1))
609 }
610}
611
612impl SolEncode<'_> for Weight {
613 type SolType = (u64, u64);
614
615 fn to_sol_type(&self) -> Self::SolType {
616 (self.ref_time(), self.proof_size())
617 }
618}