ink_env/call/
common.rs

1// Copyright (C) Use Ink (UK) Ltd.
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
15//! Utilities, types and abstractions common to call and instantiation routines.
16
17use core::marker::PhantomData;
18
19use ink_primitives::{
20    abi::{
21        Ink,
22        Sol,
23    },
24    sol::{
25        SolErrorDecode,
26        SolResultDecode,
27        SolResultDecodeError,
28    },
29    LangError,
30    MessageResult,
31};
32use pallet_revive_uapi::ReturnErrorCode;
33use scale::{
34    Decode,
35    DecodeAll,
36};
37
38/// Represents a return type.
39///
40/// Used as a marker type to define the return type of an ink! message in call builders.
41#[derive(Debug)]
42pub struct ReturnType<T>(PhantomData<fn() -> T>);
43
44impl<T> Clone for ReturnType<T> {
45    #[inline]
46    fn clone(&self) -> Self {
47        *self
48    }
49}
50
51impl<T> Copy for ReturnType<T> {}
52
53impl<T> Default for ReturnType<T> {
54    #[inline]
55    fn default() -> Self {
56        Self(Default::default())
57    }
58}
59
60/// A parameter that has been set to some value.
61#[derive(Debug, Copy, Clone)]
62pub struct Set<T>(pub T);
63
64impl<T> Set<T> {
65    /// Returns the set value.
66    #[inline]
67    pub fn value(self) -> T {
68        self.0
69    }
70}
71
72/// A parameter that has not been set, yet.
73#[derive(Debug)]
74pub struct Unset<T>(PhantomData<fn() -> T>);
75
76impl<T> Clone for Unset<T> {
77    #[inline]
78    fn clone(&self) -> Self {
79        *self
80    }
81}
82
83impl<T> Copy for Unset<T> {}
84
85impl<T> Default for Unset<T> {
86    #[inline]
87    fn default() -> Self {
88        Self(Default::default())
89    }
90}
91
92/// Implemented by [`Set`] and [`Unset`] in order to unwrap their value.
93///
94/// This is useful in case the use-site does not know if it is working with
95/// a set or an unset value generically unwrap it using a closure for fallback.
96pub trait Unwrap {
97    /// The output type of the `unwrap_or_else` operation.
98    type Output;
99
100    /// Returns the set value or evaluates the given closure.
101    fn unwrap_or_else<F>(self, f: F) -> Self::Output
102    where
103        F: FnOnce() -> Self::Output;
104}
105
106impl<T> Unwrap for Unset<T> {
107    type Output = T;
108
109    #[inline]
110    fn unwrap_or_else<F>(self, f: F) -> Self::Output
111    where
112        F: FnOnce() -> Self::Output,
113    {
114        f()
115    }
116}
117
118impl<T> Unwrap for Set<T> {
119    type Output = T;
120
121    #[inline]
122    fn unwrap_or_else<F>(self, _: F) -> Self::Output
123    where
124        F: FnOnce() -> Self::Output,
125    {
126        self.value()
127    }
128}
129
130/// A trait for decoding the output of a message based on the ABI.
131///
132/// # Note
133///
134/// This is necessary because messages supporting different ABI have different return
135/// types. For example, Solidity ABI encoded messages return the output directly without
136/// `MessageResult`.
137pub trait DecodeMessageResult<Abi>: Sized {
138    /// Decodes the output of a message call, requiring the output
139    /// to be wrapped with `MessageResult` (if not included in the output).
140    fn decode_output(
141        buffer: &[u8],
142        did_revert: bool,
143    ) -> crate::Result<MessageResult<Self>>;
144}
145
146impl<R> DecodeMessageResult<Ink> for R
147where
148    R: Decode,
149    MessageResult<R>: Decode,
150{
151    fn decode_output(mut buffer: &[u8], _: bool) -> crate::Result<MessageResult<Self>> {
152        let decoded = MessageResult::<R>::decode_all(&mut buffer)?;
153        Ok(decoded)
154    }
155}
156
157impl<R> DecodeMessageResult<Sol> for R
158where
159    R: SolResultDecode,
160{
161    fn decode_output(
162        buffer: &[u8],
163        did_revert: bool,
164    ) -> crate::Result<MessageResult<Self>> {
165        // Solidity ABI Encoded contracts return the data without
166        // `MessageResult`.
167        let decoded = R::decode(buffer, did_revert)?;
168        Ok(Ok(decoded))
169    }
170}
171
172impl From<SolResultDecodeError> for crate::Error {
173    fn from(value: SolResultDecodeError) -> Self {
174        match value {
175            SolResultDecodeError::NonResultFromRevert => {
176                Self::ReturnError(ReturnErrorCode::CalleeReverted)
177            }
178            SolResultDecodeError::Decode => Self::DecodeSol(ink_primitives::sol::Error),
179        }
180    }
181}
182
183/// A trait for decoding constructor error data based on ABI.
184///
185/// # Note
186///
187/// This is necessary because constructors supporting different ABIs encode return data
188/// differently.
189///
190/// For example, ink! ABI encoded constructors return data encoded as
191/// `ConstructorResult<Result<_, Error>, LangErr>` where `Error` is either the user
192/// defined error for fallible constructors, or unit (i.e. `()`) for infallible
193/// constructors. On the other hand, Solidity ABI encoded constructors always return the
194/// output data directly and the state of the revert flag determines whether its "normal"
195/// return data or error data.
196///
197/// This trait assumes the caller has already checked that the revert flag is set.
198pub trait DecodeConstructorError<Abi>: Sized {
199    /// Decodes constructor error data.
200    fn decode_error_output(buffer: &[u8]) -> ConstructorError<Self>;
201}
202
203/// A decoded constructor error.
204pub enum ConstructorError<E> {
205    /// A user defined error.
206    Contract(E),
207    /// A `LangError`.
208    Lang(LangError),
209    /// An environmental error.
210    Env(crate::Error),
211}
212
213impl<E> DecodeConstructorError<Ink> for E
214where
215    E: Decode,
216{
217    fn decode_error_output(mut buffer: &[u8]) -> ConstructorError<Self> {
218        // ink! ABI encoded constructors return data encoded as
219        // `ConstructorResult<Result<_, Error>, LangErr>` where `Error` is either the user
220        // defined error for fallible entry points or unit (i.e. `()`) for
221        // infallible entry points.
222        let out_return_value = &mut buffer;
223
224        // Debug friendly SCALE decode errors.
225        const INVALID_OUTER_RESULT: &str = "Invalid outer constructor Result encoding, \
226        expected 0 or 1 as the first byte";
227        const INVALID_INNER_RESULT: &str = "Invalid inner constructor Result encoding, \
228        expected 0 or 1 as the first byte";
229        const REVERT_BUT_NOT_ERROR_DATA: &str =
230            "The callee reverted, but did not encode an error in the output buffer.";
231        fn scale_decode_err<T>(desc: &'static str) -> ConstructorError<T> {
232            ConstructorError::Env(crate::Error::Decode(desc.into()))
233        }
234
235        let Ok(lang_result_variant) = <_ as scale::Input>::read_byte(out_return_value)
236        else {
237            return scale_decode_err(INVALID_OUTER_RESULT);
238        };
239        match lang_result_variant {
240            // 0 == `ConstructorResult::Ok` variant
241            0 => {
242                let Ok(inner_result_variant) =
243                    <_ as scale::Input>::read_byte(out_return_value)
244                else {
245                    return scale_decode_err(INVALID_INNER_RESULT);
246                };
247                match inner_result_variant {
248                    // 0 == `Ok` variant
249                    0 => scale_decode_err(REVERT_BUT_NOT_ERROR_DATA),
250                    // 1 == `Err` variant
251                    1 => {
252                        let decoded = <E as scale::Decode>::decode(out_return_value);
253                        match decoded {
254                            Ok(contract_err) => ConstructorError::Contract(contract_err),
255                            Err(error) => {
256                                ConstructorError::Env(crate::Error::Decode(error))
257                            }
258                        }
259                    }
260                    _ => scale_decode_err(INVALID_INNER_RESULT),
261                }
262            }
263            // 1 == `ConstructorResult::Err` variant
264            1 => {
265                let decoded = <LangError as scale::Decode>::decode(out_return_value);
266                match decoded {
267                    Ok(lang_err) => ConstructorError::Lang(lang_err),
268                    Err(error) => ConstructorError::Env(crate::Error::Decode(error)),
269                }
270            }
271            _ => scale_decode_err(INVALID_OUTER_RESULT),
272        }
273    }
274}
275
276impl<E> DecodeConstructorError<Sol> for E
277where
278    E: SolErrorDecode,
279{
280    fn decode_error_output(buffer: &[u8]) -> ConstructorError<Self> {
281        // Solidity ABI encoded entry points return error data directly.
282        let decoded = SolErrorDecode::decode(buffer);
283        match decoded {
284            Ok(contract_err) => ConstructorError::Contract(contract_err),
285            Err(error) => ConstructorError::Env(crate::Error::DecodeSol(error)),
286        }
287    }
288}