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}