ink_env/call/call_builder/
delegate.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
15use crate::{
16    call::{
17        common::{
18            ReturnType,
19            Set,
20            Unset,
21        },
22        execution::EmptyArgumentList,
23        utils::DecodeMessageResult,
24        CallBuilder,
25        CallParams,
26        ExecutionInput,
27    },
28    types::Environment,
29    Error,
30};
31use ink_primitives::{
32    reflect::{
33        AbiDecodeWith,
34        AbiEncodeWith,
35    },
36    H160,
37};
38use pallet_revive_uapi::CallFlags;
39
40/// The `delegatecall` call type. Performs a call with the given code hash.
41#[derive(Clone)]
42pub struct DelegateCall {
43    // todo comments please
44    address: H160,
45    flags: CallFlags,
46    ref_time_limit: u64,
47    proof_size_limit: u64,
48    // todo U256
49    deposit_limit: Option<[u8; 32]>,
50}
51
52impl DelegateCall {
53    /// Returns a clean builder for [`DelegateCall`]
54    pub const fn new(address: H160) -> Self {
55        DelegateCall {
56            address,
57            flags: CallFlags::empty(),
58            ref_time_limit: u64::MAX,
59            proof_size_limit: u64::MAX,
60            deposit_limit: None,
61        }
62    }
63
64    /// Sets the `address` to perform a delegate call with.
65    pub fn address(self, address: H160) -> Self {
66        DelegateCall {
67            address,
68            flags: CallFlags::empty(),
69            ref_time_limit: u64::MAX,
70            proof_size_limit: u64::MAX,
71            deposit_limit: None,
72        }
73    }
74}
75
76impl<E, Args, RetType> CallBuilder<E, Set<DelegateCall>, Args, RetType>
77where
78    E: Environment,
79{
80    /// Sets the `address` to perform a delegate call with.
81    pub fn address(self, address: H160) -> Self {
82        let call_type = self.call_type.value();
83        CallBuilder {
84            call_type: Set(DelegateCall {
85                address,
86                ..call_type
87            }),
88            ..self
89        }
90    }
91
92    /// Sets the `CallFlags` to perform a delegate call with.
93    pub fn call_flags(self, call_flags: CallFlags) -> Self {
94        CallBuilder {
95            call_type: Set(DelegateCall {
96                flags: call_flags,
97                ..self.call_type.value()
98            }),
99            exec_input: self.exec_input,
100            return_type: self.return_type,
101            _phantom: Default::default(),
102        }
103    }
104}
105
106impl<E, Args, RetType, Abi>
107    CallBuilder<
108        E,
109        Set<DelegateCall>,
110        Set<ExecutionInput<Args, Abi>>,
111        Set<ReturnType<RetType>>,
112    >
113where
114    E: Environment,
115{
116    /// Finalizes the call builder to call a function.
117    pub fn params(self) -> CallParams<E, DelegateCall, Args, RetType, Abi> {
118        CallParams {
119            call_type: self.call_type.value(),
120            _return_type: Default::default(),
121            exec_input: self.exec_input.value(),
122            _phantom: self._phantom,
123        }
124    }
125}
126
127impl<E, RetType, Abi>
128    CallBuilder<
129        E,
130        Set<DelegateCall>,
131        Unset<ExecutionInput<EmptyArgumentList<Abi>, Abi>>,
132        Unset<RetType>,
133    >
134where
135    E: Environment,
136    EmptyArgumentList<Abi>: AbiEncodeWith<Abi>,
137    (): AbiDecodeWith<Abi> + DecodeMessageResult<Abi>,
138    Abi: Default,
139{
140    /// Finalizes the call builder to call a function.
141    pub fn params(self) -> CallParams<E, DelegateCall, EmptyArgumentList<Abi>, (), Abi> {
142        CallParams {
143            call_type: self.call_type.value(),
144            _return_type: Default::default(),
145            exec_input: Default::default(),
146            _phantom: self._phantom,
147        }
148    }
149}
150
151impl<E, Abi>
152    CallBuilder<
153        E,
154        Set<DelegateCall>,
155        Unset<ExecutionInput<EmptyArgumentList<Abi>, Abi>>,
156        Unset<ReturnType<()>>,
157    >
158where
159    E: Environment,
160    EmptyArgumentList<Abi>: AbiEncodeWith<Abi>,
161    (): AbiDecodeWith<Abi> + DecodeMessageResult<Abi>,
162    Abi: Default,
163{
164    /// Invokes the cross-chain function call using Delegate Call semantics.
165    ///
166    /// # Panics
167    ///
168    /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`]
169    /// If you want to handle those use the [`try_invoke`][`CallBuilder::try_invoke`]
170    /// method instead.
171    pub fn invoke(self) {
172        self.params().invoke()
173    }
174
175    /// Invokes the cross-chain function call using Delegate Call semantics.
176    ///
177    /// # Note
178    ///
179    /// On failure this an [`ink::env::Error`][`crate::Error`] which can be handled by the
180    /// caller.
181    pub fn try_invoke(self) -> Result<ink_primitives::MessageResult<()>, Error> {
182        self.params().try_invoke()
183    }
184}
185
186impl<E, Args, R, Abi>
187    CallBuilder<E, Set<DelegateCall>, Set<ExecutionInput<Args, Abi>>, Set<ReturnType<R>>>
188where
189    E: Environment,
190    Args: AbiEncodeWith<Abi>,
191    R: AbiDecodeWith<Abi> + DecodeMessageResult<Abi>,
192{
193    /// Invokes the cross-chain function call using Delegate Call semantics and returns
194    /// the result.
195    ///
196    /// # Panics
197    ///
198    /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`] or an
199    /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle
200    /// those use the [`try_invoke`][`CallBuilder::try_invoke`] method instead.
201    pub fn invoke(self) -> R {
202        self.params().invoke()
203    }
204
205    /// Invokes the cross-chain function call using Delegate Call semantics and returns
206    /// the result.
207    ///
208    /// # Note
209    ///
210    /// On failure this returns an outer [`ink::env::Error`][`crate::Error`] or inner
211    /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be
212    /// handled by the caller.
213    pub fn try_invoke(self) -> Result<ink_primitives::MessageResult<R>, Error> {
214        self.params().try_invoke()
215    }
216}
217
218impl<E, Args, R, Abi> CallParams<E, DelegateCall, Args, R, Abi>
219where
220    E: Environment,
221{
222    /// Returns the call flags.
223    #[inline]
224    pub fn call_flags(&self) -> &CallFlags {
225        &self.call_type.flags
226    }
227
228    /// Returns the contract address which we use to perform a delegate call.
229    #[inline]
230    pub fn address(&self) -> &H160 {
231        &self.call_type.address
232    }
233
234    /// Returns the `ref_time_limit` which we use to perform a delegate call.
235    #[inline]
236    pub fn ref_time_limit(&self) -> u64 {
237        self.call_type.ref_time_limit
238    }
239
240    /// Returns the `proof_size_limit` which we use to perform a delegate call.
241    #[inline]
242    pub fn proof_size_limit(&self) -> u64 {
243        self.call_type.proof_size_limit
244    }
245
246    /// Returns the `deposit_limit` which we use to perform a delegate call.
247    #[inline]
248    pub fn deposit_limit(&self) -> &Option<[u8; 32]> {
249        &self.call_type.deposit_limit
250    }
251}
252
253impl<E, Args, R, Abi> CallParams<E, DelegateCall, Args, R, Abi>
254where
255    E: Environment,
256    Args: AbiEncodeWith<Abi>,
257    R: AbiDecodeWith<Abi> + DecodeMessageResult<Abi>,
258{
259    /// Invoke the contract using Delegate Call semantics with the given built-up call
260    /// parameters.
261    ///
262    /// Returns the result of the contract execution.
263    ///
264    /// # Panics
265    ///
266    /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`] or an
267    /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle
268    /// those use the [`try_invoke`][`CallParams::try_invoke`] method instead.
269    pub fn invoke(&self) -> R {
270        crate::invoke_contract_delegate(self)
271            .unwrap_or_else(|env_error| {
272                panic!("Cross-contract call failed with {env_error:?}")
273            })
274            .unwrap_or_else(|lang_error| {
275                panic!("Cross-contract call failed with {lang_error:?}")
276            })
277    }
278
279    /// Invoke the contract using Delegate Call semantics with the given built-up call
280    /// parameters.
281    ///
282    /// Returns the result of the contract execution.
283    ///
284    /// # Note
285    ///
286    /// On failure this returns an outer [`ink::env::Error`][`crate::Error`] or inner
287    /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be
288    /// handled by the caller.
289    pub fn try_invoke(&self) -> Result<ink_primitives::MessageResult<R>, crate::Error> {
290        crate::invoke_contract_delegate(self)
291    }
292}