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 },
63 result::{
64 SolResultDecode,
65 SolResultDecodeError,
66 SolResultEncode,
67 },
68 types::{
69 SolTopicEncode,
70 SolTypeDecode,
71 SolTypeEncode,
72 },
73};
74
75use crate::types::{
76 AccountId,
77 Address,
78 Hash,
79};
80
81pub trait SolDecode: Sized {
120 type SolType: SolTypeDecode;
122
123 const SOL_NAME: &'static str =
125 <<Self::SolType as SolTypeDecode>::AlloyType as AlloySolType>::SOL_NAME;
126
127 fn decode(data: &[u8]) -> Result<Self, Error> {
129 <Self::SolType as SolTypeDecode>::decode(data).and_then(Self::from_sol_type)
130 }
131
132 fn from_sol_type(value: Self::SolType) -> Result<Self, Error>;
134}
135
136pub trait SolEncode<'a> {
170 type SolType: SolTypeEncode + SolTopicEncode;
176
177 const SOL_NAME: &'static str =
179 <<Self::SolType as SolTypeEncode>::AlloyType as AlloySolType>::SOL_NAME;
180
181 #[doc(hidden)]
183 const DYNAMIC: bool =
184 <<Self::SolType as SolTypeEncode>::AlloyType as AlloySolType>::DYNAMIC;
185
186 fn encode(&'a self) -> Vec<u8> {
188 <Self::SolType as SolTypeEncode>::encode(&self.to_sol_type())
189 }
190
191 fn encode_to(&'a self, buffer: &mut [u8]) -> usize {
198 <Self::SolType as SolTypeEncode>::encode_to(&self.to_sol_type(), buffer)
199 }
200
201 fn encode_topic<H>(&'a self, hasher: H) -> [u8; 32]
203 where
204 H: Fn(&[u8], &mut [u8; 32]),
205 {
206 <Self::SolType as SolTopicEncode>::encode_topic(&self.to_sol_type(), hasher)
207 }
208
209 fn to_sol_type(&'a self) -> Self::SolType;
212}
213
214pub fn encode_sequence<T: for<'a> SolParamsEncode<'a>>(value: &T) -> Vec<u8> {
225 SolParamsEncode::encode(value)
226}
227
228pub fn encode_sequence_to<T: for<'a> SolParamsEncode<'a>>(
240 value: &T,
241 buffer: &mut [u8],
242) -> usize {
243 SolParamsEncode::encode_to(value, buffer)
244}
245
246pub fn decode_sequence<T: SolParamsDecode>(data: &[u8]) -> Result<T, Error> {
254 SolParamsDecode::decode(data)
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
259pub struct Error;
260
261impl From<alloy_sol_types::Error> for Error {
262 fn from(_: alloy_sol_types::Error) -> Self {
263 Self
264 }
265}
266
267impl core::fmt::Display for Error {
268 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
269 f.write_str("Solidity ABI encode/decode error")
270 }
271}
272
273macro_rules! impl_primitive_decode {
274 ($($ty: ty),+ $(,)*) => {
275 $(
276 impl SolDecode for $ty {
277 type SolType = $ty;
278
279 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
280 Ok(value)
281 }
282 }
283 )*
284 };
285}
286
287macro_rules! impl_primitive_encode {
288 ($($ty: ty),+ $(,)*) => {
289 $(
290 impl SolEncode<'_> for $ty {
291 type SolType = $ty;
292
293 fn to_sol_type(&self) -> Self::SolType {
294 *self
295 }
296 }
297 )*
298 };
299}
300
301macro_rules! impl_primitive {
302 ($($ty: ty),+ $(,)*) => {
303 $(
304 impl_primitive_decode!($ty);
305
306 impl_primitive_encode!($ty);
307 )*
308 };
309}
310
311macro_rules! impl_primitive_encode_by_ref {
312 ($($ty: ty, $ref_ty: ty),+ $(,)*) => {
313 $(
314 impl<'a> SolEncode<'a> for $ty {
315 type SolType = &'a $ref_ty;
316
317 fn to_sol_type(&'a self) -> Self::SolType {
318 self
319 }
320 }
321 )*
322 };
323}
324
325macro_rules! impl_primitive_by_ref {
326 ($($ty: ty, $ref_ty: ty),+ $(,)*) => {
327 $(
328 impl_primitive_decode!($ty);
329
330 impl_primitive_encode_by_ref!($ty, $ref_ty);
331 )*
332 };
333}
334
335impl_primitive! {
336 bool,
338 i8, i16, i32, i64, i128,
340 u8, u16, u32, u64, u128, U256,
342 Address,
344}
345
346impl_primitive_by_ref! {
347 String, str,
349 Box<str>, str,
350}
351
352impl<T: SolDecode, const N: usize> SolDecode for [T; N] {
354 type SolType = [T::SolType; N];
355
356 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
357 value
361 .into_iter()
362 .map(<T as SolDecode>::from_sol_type)
363 .process_results(|iter| iter.collect_array())?
364 .ok_or(Error)
365 }
366}
367
368impl<'a, T: SolEncode<'a>, const N: usize> SolEncode<'a> for [T; N] {
369 type SolType = [T::SolType; N];
370
371 fn to_sol_type(&'a self) -> Self::SolType {
372 self.each_ref().map(<T as SolEncode>::to_sol_type)
373 }
374}
375
376impl<T: SolDecode> SolDecode for Vec<T> {
378 type SolType = Vec<T::SolType>;
379
380 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
381 value
382 .into_iter()
383 .map(<T as SolDecode>::from_sol_type)
384 .collect()
385 }
386}
387
388impl<'a, T: SolEncode<'a>> SolEncode<'a> for Vec<T> {
389 type SolType = Vec<T::SolType>;
390
391 fn to_sol_type(&'a self) -> Self::SolType {
392 self.iter().map(<T as SolEncode>::to_sol_type).collect()
393 }
394}
395
396impl<T: SolDecode> SolDecode for Box<[T]> {
398 type SolType = Box<[T::SolType]>;
399
400 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
401 value
402 .into_iter()
403 .map(<T as SolDecode>::from_sol_type)
404 .process_results(|iter| iter.collect())
405 }
406}
407
408impl<'a, T: SolEncode<'a>> SolEncode<'a> for Box<[T]> {
409 type SolType = Box<[T::SolType]>;
410
411 fn to_sol_type(&'a self) -> Self::SolType {
412 self.iter().map(<T as SolEncode>::to_sol_type).collect()
413 }
414}
415
416#[impl_for_tuples(12)]
420impl SolDecode for Tuple {
421 for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
422
423 #[allow(clippy::unused_unit)]
424 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
425 Ok(for_tuples! { ( #( Tuple::from_sol_type(value.Tuple)? ),* ) })
426 }
427}
428
429#[impl_for_tuples(12)]
430impl<'a> SolEncode<'a> for Tuple {
431 for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
432
433 #[allow(clippy::unused_unit)]
434 fn to_sol_type(&'a self) -> Self::SolType {
435 for_tuples!( ( #( self.Tuple.to_sol_type() ),* ) )
436 }
437}
438
439macro_rules! impl_refs_encode {
441 ($($ty: ty), +$(,)*) => {
442 $(
443 impl<'a, T> SolEncode<'a> for $ty
444 where
445 T: SolEncode<'a>,
446 {
447 type SolType = T::SolType;
448
449 fn to_sol_type(&'a self) -> Self::SolType {
450 <T as SolEncode>::to_sol_type(self)
451 }
452 }
453 )*
454 };
455}
456
457impl_refs_encode! {
458 &T,
459 &mut T,
460 Box<T>,
461}
462
463impl<'a, T> SolEncode<'a> for Cow<'_, T>
464where
465 T: SolEncode<'a> + Clone,
466{
467 type SolType = T::SolType;
468
469 fn to_sol_type(&'a self) -> Self::SolType {
470 <T as SolEncode>::to_sol_type(self.deref())
471 }
472}
473
474macro_rules! impl_str_ref_encode {
476 ($($ty: ty),+ $(,)*) => {
477 $(
478 impl<'a> SolEncode<'a> for $ty {
479 type SolType = &'a str;
480
481 fn to_sol_type(&'a self) -> Self::SolType {
482 self
483 }
484 }
485 )*
486 };
487}
488
489impl_str_ref_encode!(&str, &mut str);
490
491macro_rules! impl_slice_ref_encode {
492 ($($ty: ty),+ $(,)*) => {
493 $(
494 impl<'a, T> SolEncode<'a> for $ty
495 where
496 T: SolEncode<'a>,
497 {
498 type SolType = Vec<T::SolType>;
499
500 fn to_sol_type(&'a self) -> Self::SolType {
501 self.iter().map(<T as SolEncode>::to_sol_type).collect()
502 }
503 }
504 )*
505 };
506}
507
508impl_slice_ref_encode!(&[T], &mut [T]);
509
510impl<T> SolDecode for Option<T>
531where
532 T: SolDecode,
533{
534 type SolType = Option<T::SolType>;
535
536 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
537 value.map(<T as SolDecode>::from_sol_type).transpose()
538 }
539}
540
541impl<'a, T> SolEncode<'a> for Option<T>
542where
543 T: SolEncode<'a>,
544{
545 type SolType = Option<T::SolType>;
546
547 fn to_sol_type(&'a self) -> Self::SolType {
548 self.as_ref().map(T::to_sol_type)
549 }
550}
551
552impl<T> SolDecode for core::marker::PhantomData<T> {
554 type SolType = ();
555
556 fn decode(_: &[u8]) -> Result<Self, Error>
557 where
558 Self: Sized,
559 {
560 Ok(core::marker::PhantomData)
562 }
563
564 fn from_sol_type(_: Self::SolType) -> Result<Self, Error> {
565 Ok(core::marker::PhantomData)
566 }
567}
568
569impl<T> SolEncode<'_> for core::marker::PhantomData<T> {
570 type SolType = ();
571
572 fn encode(&self) -> Vec<u8> {
573 Vec::new()
574 }
575
576 fn to_sol_type(&self) {}
577}
578
579impl SolDecode for AccountId {
581 type SolType = FixedBytes<32>;
582
583 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
584 Ok(AccountId(value.0))
585 }
586}
587
588impl<'a> SolEncode<'a> for AccountId {
589 type SolType = &'a FixedBytes<32>;
590
591 fn to_sol_type(&'a self) -> Self::SolType {
592 FixedBytes::from_ref(self.as_ref())
593 }
594}
595
596impl SolDecode for Hash {
598 type SolType = FixedBytes<32>;
599
600 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
601 Ok(Hash::from(value.0))
602 }
603}
604
605impl<'a> SolEncode<'a> for Hash {
606 type SolType = &'a FixedBytes<32>;
607
608 fn to_sol_type(&'a self) -> Self::SolType {
609 use core::borrow::Borrow;
610 FixedBytes::from_ref(self.borrow())
611 }
612}
613
614impl SolDecode for H256 {
616 type SolType = FixedBytes<32>;
617
618 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
619 Ok(H256(value.0))
620 }
621}
622
623impl<'a> SolEncode<'a> for H256 {
624 type SolType = &'a FixedBytes<32>;
625
626 fn to_sol_type(&'a self) -> Self::SolType {
627 FixedBytes::from_ref(self.as_fixed_bytes())
628 }
629}
630
631impl SolDecode for Weight {
633 type SolType = (u64, u64);
634
635 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
636 Ok(Weight::from_parts(value.0, value.1))
637 }
638}
639
640impl SolEncode<'_> for Weight {
641 type SolType = (u64, u64);
642
643 fn to_sol_type(&self) -> Self::SolType {
644 (self.ref_time(), self.proof_size())
645 }
646}