ink_primitives/sol/
params.rs

1// Copyright (C) ink! contributors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use alloy_sol_types::{
16    abi::{
17        self,
18        Encoder,
19    },
20    SolType as AlloySolType,
21};
22use impl_trait_for_tuples::impl_for_tuples;
23use ink_prelude::vec::Vec;
24
25use super::{
26    encodable::{
27        Encodable,
28        EncodableParams,
29    },
30    Error,
31    SolDecode,
32    SolEncode,
33    SolTypeDecode,
34    SolTypeEncode,
35};
36
37/// Solidity ABI decode from parameter data (e.g. function, event or error parameters).
38///
39/// # Note
40///
41/// This trait is sealed and cannot be implemented for types outside `ink_primitives`.
42pub trait SolParamsDecode: SolDecode + Sized + private::Sealed {
43    /// Name of equivalent Solidity ABI type.
44    const SOL_NAME: &'static str = <Self as SolDecode>::SOL_NAME;
45
46    /// Solidity ABI decode parameter data into this type.
47    fn decode(data: &[u8]) -> Result<Self, Error>;
48}
49
50/// Solidity ABI encode as a parameter sequence (e.g. function, event or error
51/// parameters).
52///
53/// # Note
54///
55/// This trait is sealed and cannot be implemented for types outside `ink_primitives`.
56pub trait SolParamsEncode<'a>: SolEncode<'a> + private::Sealed {
57    /// Name of equivalent Solidity ABI type.
58    const SOL_NAME: &'static str = <Self as SolEncode<'a>>::SOL_NAME;
59
60    /// Solidity ABI encode the value as a parameter sequence.
61    fn encode(&'a self) -> Vec<u8>;
62}
63
64// We follow the Rust standard library's convention of implementing traits for tuples up
65// to twelve items long.
66// Ref: <https://doc.rust-lang.org/std/primitive.tuple.html#trait-implementations>
67#[impl_for_tuples(1, 12)]
68#[tuple_types_custom_trait_bound(SolDecode)]
69impl SolParamsDecode for Tuple {
70    fn decode(data: &[u8]) -> Result<Self, Error> {
71        abi::decode_params::<
72            <<<Self as SolDecode>::SolType as SolTypeDecode>::AlloyType as AlloySolType>::Token<'_>,
73        >(data)
74            .map_err(Error::from)
75            .and_then(<<Self as SolDecode>::SolType as SolTypeDecode>::detokenize)
76            .and_then(<Self as SolDecode>::from_sol_type)
77    }
78}
79
80#[impl_for_tuples(1, 12)]
81#[tuple_types_custom_trait_bound(SolEncode<'a>)]
82impl<'a> SolParamsEncode<'a> for Tuple {
83    fn encode(&'a self) -> Vec<u8> {
84        let params = self.to_sol_type();
85        let token = <<Self as SolEncode>::SolType as SolTypeEncode>::tokenize(&params);
86        let mut encoder = Encoder::with_capacity(token.total_words());
87        EncodableParams::encode_params(&token, &mut encoder);
88        encoder.into_bytes()
89    }
90}
91
92// Optimized implementations for unit (i.e. `()`).
93impl SolParamsDecode for () {
94    fn decode(_: &[u8]) -> Result<Self, Error> {
95        // NOTE: Solidity ABI decoding doesn't validate input length.
96        Ok(())
97    }
98}
99
100impl SolParamsEncode<'_> for () {
101    fn encode(&self) -> Vec<u8> {
102        Vec::new()
103    }
104}
105
106#[impl_for_tuples(12)]
107#[tuple_types_no_default_trait_bound]
108impl private::Sealed for Tuple {}
109
110mod private {
111    /// Seals implementations of `SolParamsEncode` and `SolParamsDecode`.
112    pub trait Sealed {}
113}