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 SolResultEncode,
66 },
67 types::{
68 SolTopicEncode,
69 SolTypeDecode,
70 SolTypeEncode,
71 },
72};
73
74use crate::types::{
75 AccountId,
76 Address,
77 Hash,
78};
79
80pub trait SolDecode: Sized {
119 type SolType: SolTypeDecode;
121
122 const SOL_NAME: &'static str =
124 <<Self::SolType as SolTypeDecode>::AlloyType as AlloySolType>::SOL_NAME;
125
126 fn decode(data: &[u8]) -> Result<Self, Error> {
128 <Self::SolType as SolTypeDecode>::decode(data).and_then(Self::from_sol_type)
129 }
130
131 fn from_sol_type(value: Self::SolType) -> Result<Self, Error>;
133}
134
135pub trait SolEncode<'a> {
169 type SolType: SolTypeEncode + SolTopicEncode;
175
176 const SOL_NAME: &'static str =
178 <<Self::SolType as SolTypeEncode>::AlloyType as AlloySolType>::SOL_NAME;
179
180 #[doc(hidden)]
182 const DYNAMIC: bool =
183 <<Self::SolType as SolTypeEncode>::AlloyType as AlloySolType>::DYNAMIC;
184
185 fn encode(&'a self) -> Vec<u8> {
187 <Self::SolType as SolTypeEncode>::encode(&self.to_sol_type())
188 }
189
190 fn encode_topic<H>(&'a self, hasher: H) -> [u8; 32]
192 where
193 H: Fn(&[u8], &mut [u8; 32]),
194 {
195 <Self::SolType as SolTopicEncode>::encode_topic(&self.to_sol_type(), hasher)
196 }
197
198 fn to_sol_type(&'a self) -> Self::SolType;
201}
202
203pub fn encode_sequence<T: for<'a> SolParamsEncode<'a>>(value: &T) -> Vec<u8> {
214 SolParamsEncode::encode(value)
215}
216
217pub fn decode_sequence<T: SolParamsDecode>(data: &[u8]) -> Result<T, Error> {
225 SolParamsDecode::decode(data)
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
230pub struct Error;
231
232impl From<alloy_sol_types::Error> for Error {
233 fn from(_: alloy_sol_types::Error) -> Self {
234 Self
235 }
236}
237
238impl core::fmt::Display for Error {
239 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
240 f.write_str("Solidity ABI encode/decode error")
241 }
242}
243
244macro_rules! impl_primitive_decode {
245 ($($ty: ty),+ $(,)*) => {
246 $(
247 impl SolDecode for $ty {
248 type SolType = $ty;
249
250 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
251 Ok(value)
252 }
253 }
254 )*
255 };
256}
257
258macro_rules! impl_primitive_encode {
259 ($($ty: ty),+ $(,)*) => {
260 $(
261 impl SolEncode<'_> for $ty {
262 type SolType = $ty;
263
264 fn to_sol_type(&self) -> Self::SolType {
265 *self
266 }
267 }
268 )*
269 };
270}
271
272macro_rules! impl_primitive {
273 ($($ty: ty),+ $(,)*) => {
274 $(
275 impl_primitive_decode!($ty);
276
277 impl_primitive_encode!($ty);
278 )*
279 };
280}
281
282macro_rules! impl_primitive_encode_by_ref {
283 ($($ty: ty, $ref_ty: ty),+ $(,)*) => {
284 $(
285 impl<'a> SolEncode<'a> for $ty {
286 type SolType = &'a $ref_ty;
287
288 fn to_sol_type(&'a self) -> Self::SolType {
289 self
290 }
291 }
292 )*
293 };
294}
295
296macro_rules! impl_primitive_by_ref {
297 ($($ty: ty, $ref_ty: ty),+ $(,)*) => {
298 $(
299 impl_primitive_decode!($ty);
300
301 impl_primitive_encode_by_ref!($ty, $ref_ty);
302 )*
303 };
304}
305
306impl_primitive! {
307 bool,
309 i8, i16, i32, i64, i128,
311 u8, u16, u32, u64, u128, U256,
313 Address,
315}
316
317impl_primitive_by_ref! {
318 String, str,
320 Box<str>, str,
321}
322
323impl<T: SolDecode, const N: usize> SolDecode for [T; N] {
325 type SolType = [T::SolType; N];
326
327 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
328 value
332 .into_iter()
333 .map(<T as SolDecode>::from_sol_type)
334 .process_results(|iter| iter.collect_array())?
335 .ok_or(Error)
336 }
337}
338
339impl<'a, T: SolEncode<'a>, const N: usize> SolEncode<'a> for [T; N] {
340 type SolType = [T::SolType; N];
341
342 fn to_sol_type(&'a self) -> Self::SolType {
343 self.each_ref().map(<T as SolEncode>::to_sol_type)
344 }
345}
346
347impl<T: SolDecode> SolDecode for Vec<T> {
349 type SolType = Vec<T::SolType>;
350
351 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
352 value
353 .into_iter()
354 .map(<T as SolDecode>::from_sol_type)
355 .collect()
356 }
357}
358
359impl<'a, T: SolEncode<'a>> SolEncode<'a> for Vec<T> {
360 type SolType = Vec<T::SolType>;
361
362 fn to_sol_type(&'a self) -> Self::SolType {
363 self.iter().map(<T as SolEncode>::to_sol_type).collect()
364 }
365}
366
367impl<T: SolDecode> SolDecode for Box<[T]> {
369 type SolType = Box<[T::SolType]>;
370
371 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
372 value
373 .into_iter()
374 .map(<T as SolDecode>::from_sol_type)
375 .process_results(|iter| iter.collect())
376 }
377}
378
379impl<'a, T: SolEncode<'a>> SolEncode<'a> for Box<[T]> {
380 type SolType = Box<[T::SolType]>;
381
382 fn to_sol_type(&'a self) -> Self::SolType {
383 self.iter().map(<T as SolEncode>::to_sol_type).collect()
384 }
385}
386
387#[impl_for_tuples(12)]
391impl SolDecode for Tuple {
392 for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
393
394 #[allow(clippy::unused_unit)]
395 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
396 Ok(for_tuples! { ( #( Tuple::from_sol_type(value.Tuple)? ),* ) })
397 }
398}
399
400#[impl_for_tuples(12)]
401impl<'a> SolEncode<'a> for Tuple {
402 for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
403
404 #[allow(clippy::unused_unit)]
405 fn to_sol_type(&'a self) -> Self::SolType {
406 for_tuples!( ( #( self.Tuple.to_sol_type() ),* ) )
407 }
408}
409
410macro_rules! impl_refs_encode {
412 ($($ty: ty), +$(,)*) => {
413 $(
414 impl<'a, T> SolEncode<'a> for $ty
415 where
416 T: SolEncode<'a>,
417 {
418 type SolType = T::SolType;
419
420 fn to_sol_type(&'a self) -> Self::SolType {
421 <T as SolEncode>::to_sol_type(self)
422 }
423 }
424 )*
425 };
426}
427
428impl_refs_encode! {
429 &T,
430 &mut T,
431 Box<T>,
432}
433
434impl<'a, T> SolEncode<'a> for Cow<'_, T>
435where
436 T: SolEncode<'a> + Clone,
437{
438 type SolType = T::SolType;
439
440 fn to_sol_type(&'a self) -> Self::SolType {
441 <T as SolEncode>::to_sol_type(self.deref())
442 }
443}
444
445macro_rules! impl_str_ref_encode {
447 ($($ty: ty),+ $(,)*) => {
448 $(
449 impl<'a> SolEncode<'a> for $ty {
450 type SolType = &'a str;
451
452 fn to_sol_type(&'a self) -> Self::SolType {
453 self
454 }
455 }
456 )*
457 };
458}
459
460impl_str_ref_encode!(&str, &mut str);
461
462macro_rules! impl_slice_ref_encode {
463 ($($ty: ty),+ $(,)*) => {
464 $(
465 impl<'a, T> SolEncode<'a> for $ty
466 where
467 T: SolEncode<'a>,
468 {
469 type SolType = Vec<T::SolType>;
470
471 fn to_sol_type(&'a self) -> Self::SolType {
472 self.iter().map(<T as SolEncode>::to_sol_type).collect()
473 }
474 }
475 )*
476 };
477}
478
479impl_slice_ref_encode!(&[T], &mut [T]);
480
481impl<T> SolDecode for Option<T>
502where
503 T: SolDecode,
504{
505 type SolType = Option<T::SolType>;
506
507 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
508 value.map(<T as SolDecode>::from_sol_type).transpose()
509 }
510}
511
512impl<'a, T> SolEncode<'a> for Option<T>
513where
514 T: SolEncode<'a>,
515{
516 type SolType = Option<T::SolType>;
517
518 fn to_sol_type(&'a self) -> Self::SolType {
519 self.as_ref().map(T::to_sol_type)
520 }
521}
522
523impl<T> SolDecode for core::marker::PhantomData<T> {
525 type SolType = ();
526
527 fn decode(_: &[u8]) -> Result<Self, Error>
528 where
529 Self: Sized,
530 {
531 Ok(core::marker::PhantomData)
533 }
534
535 fn from_sol_type(_: Self::SolType) -> Result<Self, Error> {
536 Ok(core::marker::PhantomData)
537 }
538}
539
540impl<T> SolEncode<'_> for core::marker::PhantomData<T> {
541 type SolType = ();
542
543 fn encode(&self) -> Vec<u8> {
544 Vec::new()
545 }
546
547 fn to_sol_type(&self) {}
548}
549
550impl SolDecode for AccountId {
552 type SolType = FixedBytes<32>;
553
554 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
555 Ok(AccountId(value.0))
556 }
557}
558
559impl<'a> SolEncode<'a> for AccountId {
560 type SolType = &'a FixedBytes<32>;
561
562 fn to_sol_type(&'a self) -> Self::SolType {
563 FixedBytes::from_ref(self.as_ref())
564 }
565}
566
567impl SolDecode for Hash {
569 type SolType = FixedBytes<32>;
570
571 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
572 Ok(Hash::from(value.0))
573 }
574}
575
576impl<'a> SolEncode<'a> for Hash {
577 type SolType = &'a FixedBytes<32>;
578
579 fn to_sol_type(&'a self) -> Self::SolType {
580 use core::borrow::Borrow;
581 FixedBytes::from_ref(self.borrow())
582 }
583}
584
585impl SolDecode for H256 {
587 type SolType = FixedBytes<32>;
588
589 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
590 Ok(H256(value.0))
591 }
592}
593
594impl<'a> SolEncode<'a> for H256 {
595 type SolType = &'a FixedBytes<32>;
596
597 fn to_sol_type(&'a self) -> Self::SolType {
598 FixedBytes::from_ref(self.as_fixed_bytes())
599 }
600}
601
602impl SolDecode for Weight {
604 type SolType = (u64, u64);
605
606 fn from_sol_type(value: Self::SolType) -> Result<Self, Error> {
607 Ok(Weight::from_parts(value.0, value.1))
608 }
609}
610
611impl SolEncode<'_> for Weight {
612 type SolType = (u64, u64);
613
614 fn to_sol_type(&self) -> Self::SolType {
615 (self.ref_time(), self.proof_size())
616 }
617}