1#[macro_use]
18mod macros;
19
20mod bytes;
21mod encodable;
22mod encoder;
23mod error;
24mod params;
25mod result;
26mod types;
27mod utils;
28
29#[cfg(test)]
30mod tests;
31
32use core::ops::Deref;
33
34use alloy_sol_types::SolType as AlloySolType;
35use impl_trait_for_tuples::impl_for_tuples;
36use ink_prelude::{
37 borrow::Cow,
38 boxed::Box,
39 string::String,
40 vec::Vec,
41};
42use itertools::Itertools;
43use primitive_types::{
44 H256,
45 U256,
46};
47use sp_weights::Weight;
48
49pub use self::{
50 bytes::{
51 ByteSlice,
52 DynBytes,
53 FixedBytes,
54 },
55 error::{
56 SolErrorDecode,
57 SolErrorEncode,
58 },
59 params::{
60 SolParamsDecode,
61 SolParamsEncode,
62 SolTypeParamsEncode,
63 },
64 result::{
65 SolResultDecode,
66 SolResultDecodeError,
67 SolResultEncode,
68 },
69 types::{
70 SolTopicEncode,
71 SolTypeDecode,
72 SolTypeEncode,
73 },
74};
75
76use crate::types::{
77 AccountId,
78 Address,
79 Hash,
80};
81
82pub trait SolDecode: Sized {
121 type SolType: SolTypeDecode;
123
124 const SOL_NAME: &'static str =
126 <<Self::SolType as SolTypeDecode>::AlloyType as AlloySolType>::SOL_NAME;
127
128 fn decode(data: &[u8]) -> Result<Self, Error> {
130 <Self::SolType as SolTypeDecode>::decode(data).and_then(Self::from_sol_type)
131 }
132
133 fn from_sol_type(value: Self::SolType) -> Result<Self, Error>;
135}
136
137pub trait SolEncode<'a> {
171 type SolType: SolTypeEncode + SolTopicEncode;
177
178 const SOL_NAME: &'static str =
180 <<Self::SolType as SolTypeEncode>::AlloyType as AlloySolType>::SOL_NAME;
181
182 fn encode(&'a self) -> Vec<u8> {
184 <Self::SolType as SolTypeEncode>::encode(&self.to_sol_type())
185 }
186
187 fn encode_to(&'a self, buffer: &mut [u8]) -> usize {
194 <Self::SolType as SolTypeEncode>::encode_to(&self.to_sol_type(), buffer)
195 }
196
197 fn encode_topic<H>(&'a self, hasher: H) -> [u8; 32]
199 where
200 H: Fn(&[u8], &mut [u8; 32]),
201 {
202 <Self::SolType as SolTopicEncode>::encode_topic(&self.to_sol_type(), hasher)
203 }
204
205 fn to_sol_type(&'a self) -> Self::SolType;
208}
209
210pub fn encode_sequence<T: for<'a> SolParamsEncode<'a>>(value: &T) -> Vec<u8> {
221 SolParamsEncode::encode(value)
222}
223
224pub fn encode_sequence_to<T: for<'a> SolParamsEncode<'a>>(
236 value: &T,
237 buffer: &mut [u8],
238) -> usize {
239 SolParamsEncode::encode_to(value, buffer)
240}
241
242pub fn decode_sequence<T: SolParamsDecode>(data: &[u8]) -> Result<T, Error> {
250 SolParamsDecode::decode(data)
251}
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq)]
255pub struct Error;
256
257impl From<alloy_sol_types::Error> for Error {
258 fn from(_: alloy_sol_types::Error) -> Self {
259 Self
260 }
261}
262
263impl core::fmt::Display for Error {
264 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
265 f.write_str("Solidity ABI encode/decode error")
266 }
267}
268
269macro_rules! impl_primitive_decode {
270 ($($ty: ty),+ $(,)*) => {
271 $(
272 impl SolDecode for $ty {
273 type SolType = $ty;
274
275 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
276 Ok(value)
277 }
278 }
279 )*
280 };
281}
282
283macro_rules! impl_primitive_encode {
284 ($($ty: ty),+ $(,)*) => {
285 $(
286 impl SolEncode<'_> for $ty {
287 type SolType = $ty;
288
289 fn to_sol_type(&self) -> Self::SolType {
290 *self
291 }
292 }
293 )*
294 };
295}
296
297macro_rules! impl_primitive {
298 ($($ty: ty),+ $(,)*) => {
299 $(
300 impl_primitive_decode!($ty);
301
302 impl_primitive_encode!($ty);
303 )*
304 };
305}
306
307macro_rules! impl_primitive_encode_by_ref {
308 ($($ty: ty, $ref_ty: ty),+ $(,)*) => {
309 $(
310 impl<'a> SolEncode<'a> for $ty {
311 type SolType = &'a $ref_ty;
312
313 fn to_sol_type(&'a self) -> Self::SolType {
314 self
315 }
316 }
317 )*
318 };
319}
320
321macro_rules! impl_primitive_by_ref {
322 ($($ty: ty, $ref_ty: ty),+ $(,)*) => {
323 $(
324 impl_primitive_decode!($ty);
325
326 impl_primitive_encode_by_ref!($ty, $ref_ty);
327 )*
328 };
329}
330
331impl_primitive! {
332 bool,
334 i8, i16, i32, i64, i128,
336 u8, u16, u32, u64, u128, U256,
338 Address,
340}
341
342impl_primitive_by_ref! {
343 String, str,
345 Box<str>, str,
346}
347
348impl<T: SolDecode, const N: usize> SolDecode for [T; N] {
350 type SolType = [T::SolType; N];
351
352 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
353 value
357 .into_iter()
358 .map(<T as SolDecode>::from_sol_type)
359 .process_results(|iter| iter.collect_array())?
360 .ok_or(Error)
361 }
362}
363
364impl<'a, T: SolEncode<'a>, const N: usize> SolEncode<'a> for [T; N] {
365 type SolType = [T::SolType; N];
366
367 fn to_sol_type(&'a self) -> Self::SolType {
368 self.each_ref().map(<T as SolEncode>::to_sol_type)
369 }
370}
371
372impl<T: SolDecode> SolDecode for Vec<T> {
374 type SolType = Vec<T::SolType>;
375
376 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
377 value
378 .into_iter()
379 .map(<T as SolDecode>::from_sol_type)
380 .collect()
381 }
382}
383
384impl<'a, T: SolEncode<'a>> SolEncode<'a> for Vec<T> {
385 type SolType = Vec<T::SolType>;
386
387 fn to_sol_type(&'a self) -> Self::SolType {
388 self.iter().map(<T as SolEncode>::to_sol_type).collect()
389 }
390}
391
392impl<T: SolDecode> SolDecode for Box<[T]> {
394 type SolType = Box<[T::SolType]>;
395
396 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
397 value
398 .into_iter()
399 .map(<T as SolDecode>::from_sol_type)
400 .process_results(|iter| iter.collect())
401 }
402}
403
404impl<'a, T: SolEncode<'a>> SolEncode<'a> for Box<[T]> {
405 type SolType = Box<[T::SolType]>;
406
407 fn to_sol_type(&'a self) -> Self::SolType {
408 self.iter().map(<T as SolEncode>::to_sol_type).collect()
409 }
410}
411
412#[impl_for_tuples(12)]
416impl SolDecode for Tuple {
417 for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
418
419 #[allow(clippy::unused_unit)]
420 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
421 Ok(for_tuples! { ( #( Tuple::from_sol_type(value.Tuple)? ),* ) })
422 }
423}
424
425#[impl_for_tuples(12)]
426impl<'a> SolEncode<'a> for Tuple {
427 for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
428
429 #[allow(clippy::unused_unit)]
430 fn to_sol_type(&'a self) -> Self::SolType {
431 for_tuples!( ( #( self.Tuple.to_sol_type() ),* ) )
432 }
433}
434
435macro_rules! impl_refs_encode {
437 ($($ty: ty), +$(,)*) => {
438 $(
439 impl<'a, T> SolEncode<'a> for $ty
440 where
441 T: SolEncode<'a>,
442 {
443 type SolType = T::SolType;
444
445 fn to_sol_type(&'a self) -> Self::SolType {
446 <T as SolEncode>::to_sol_type(self)
447 }
448 }
449 )*
450 };
451}
452
453impl_refs_encode! {
454 &T,
455 &mut T,
456 Box<T>,
457}
458
459impl<'a, T> SolEncode<'a> for Cow<'_, T>
460where
461 T: SolEncode<'a> + Clone,
462{
463 type SolType = T::SolType;
464
465 fn to_sol_type(&'a self) -> Self::SolType {
466 <T as SolEncode>::to_sol_type(self.deref())
467 }
468}
469
470macro_rules! impl_str_ref_encode {
472 ($($ty: ty),+ $(,)*) => {
473 $(
474 impl<'a> SolEncode<'a> for $ty {
475 type SolType = &'a str;
476
477 fn to_sol_type(&'a self) -> Self::SolType {
478 self
479 }
480 }
481 )*
482 };
483}
484
485impl_str_ref_encode!(&str, &mut str);
486
487macro_rules! impl_slice_ref_encode {
488 ($($ty: ty),+ $(,)*) => {
489 $(
490 impl<'a, T> SolEncode<'a> for $ty
491 where
492 T: SolEncode<'a>,
493 {
494 type SolType = Vec<T::SolType>;
495
496 fn to_sol_type(&'a self) -> Self::SolType {
497 self.iter().map(<T as SolEncode>::to_sol_type).collect()
498 }
499 }
500 )*
501 };
502}
503
504impl_slice_ref_encode!(&[T], &mut [T]);
505
506impl<T> SolDecode for Option<T>
527where
528 T: SolDecode,
529{
530 type SolType = Option<T::SolType>;
531
532 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
533 value.map(<T as SolDecode>::from_sol_type).transpose()
534 }
535}
536
537impl<'a, T> SolEncode<'a> for Option<T>
538where
539 T: SolEncode<'a>,
540{
541 type SolType = Option<T::SolType>;
542
543 fn to_sol_type(&'a self) -> Self::SolType {
544 self.as_ref().map(T::to_sol_type)
545 }
546}
547
548impl<T> SolDecode for core::marker::PhantomData<T> {
550 type SolType = ();
551
552 fn decode(_: &[u8]) -> Result<Self, Error>
553 where
554 Self: Sized,
555 {
556 Ok(core::marker::PhantomData)
558 }
559
560 fn from_sol_type(_: Self::SolType) -> Result<Self, Error> {
561 Ok(core::marker::PhantomData)
562 }
563}
564
565impl<T> SolEncode<'_> for core::marker::PhantomData<T> {
566 type SolType = ();
567
568 fn encode(&self) -> Vec<u8> {
569 Vec::new()
570 }
571
572 fn to_sol_type(&self) {}
573}
574
575impl SolDecode for AccountId {
577 type SolType = FixedBytes<32>;
578
579 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
580 Ok(AccountId(value.0))
581 }
582}
583
584impl<'a> SolEncode<'a> for AccountId {
585 type SolType = &'a FixedBytes<32>;
586
587 fn to_sol_type(&'a self) -> Self::SolType {
588 FixedBytes::from_ref(self.as_ref())
589 }
590}
591
592impl SolDecode for Hash {
594 type SolType = FixedBytes<32>;
595
596 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
597 Ok(Hash::from(value.0))
598 }
599}
600
601impl<'a> SolEncode<'a> for Hash {
602 type SolType = &'a FixedBytes<32>;
603
604 fn to_sol_type(&'a self) -> Self::SolType {
605 use core::borrow::Borrow;
606 FixedBytes::from_ref(self.borrow())
607 }
608}
609
610impl SolDecode for H256 {
612 type SolType = FixedBytes<32>;
613
614 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
615 Ok(H256(value.0))
616 }
617}
618
619impl<'a> SolEncode<'a> for H256 {
620 type SolType = &'a FixedBytes<32>;
621
622 fn to_sol_type(&'a self) -> Self::SolType {
623 FixedBytes::from_ref(self.as_fixed_bytes())
624 }
625}
626
627impl SolDecode for Weight {
629 type SolType = (u64, u64);
630
631 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
632 Ok(Weight::from_parts(value.0, value.1))
633 }
634}
635
636impl SolEncode<'_> for Weight {
637 type SolType = (u64, u64);
638
639 fn to_sol_type(&self) -> Self::SolType {
640 (self.ref_time(), self.proof_size())
641 }
642}