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