ink_env/call/call_builder/call.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 U256,
19};
20use pallet_revive_uapi::CallFlags;
21
22use crate::{
23 call::{
24 common::{
25 ReturnType,
26 Set,
27 Unset,
28 },
29 execution::EmptyArgumentList,
30 utils::DecodeMessageResult,
31 CallBuilder,
32 CallParams,
33 ExecutionInput,
34 },
35 types::{
36 Environment,
37 Gas,
38 },
39 Error,
40};
41
42/// The default call type for cross-contract calls, for calling into the latest `call`
43/// host function. This adds the additional weight limit parameter `proof_size_limit` as
44/// well as `storage_deposit_limit`.
45#[derive(Clone)]
46pub struct Call {
47 callee: Address,
48 ref_time_limit: u64,
49 proof_size_limit: u64,
50 storage_deposit_limit: Option<U256>,
51 transferred_value: U256,
52 call_flags: CallFlags,
53}
54
55impl Call {
56 /// Returns a clean builder for [`Call`].
57 pub fn new(callee: Address) -> Self {
58 Self {
59 callee,
60 ref_time_limit: u64::MAX,
61 proof_size_limit: u64::MAX,
62 storage_deposit_limit: None,
63 transferred_value: U256::zero(),
64 call_flags: CallFlags::empty(),
65 }
66 }
67}
68
69impl<E, Args, RetType> CallBuilder<E, Set<Call>, Args, RetType>
70where
71 E: Environment,
72{
73 /// Sets the `ref_time_limit` part of the weight limit for the current cross-contract
74 /// call.
75 ///
76 /// `ref_time` refers to the amount of computational time that can be
77 /// used for execution, in picoseconds. You can find more info
78 /// [here](https://use.ink/basics/gas).
79 pub fn ref_time_limit(self, ref_time_limit: Gas) -> Self {
80 let call_type = self.call_type.value();
81 CallBuilder {
82 call_type: Set(Call {
83 ref_time_limit,
84 ..call_type
85 }),
86 ..self
87 }
88 }
89
90 /// Sets the `proof_size_limit` part of the weight limit for the current
91 /// cross-contract call.
92 ///
93 /// `proof_size` refers to the amount of storage in bytes that a transaction
94 /// is allowed to read. You can find more info
95 /// [here](https://use.ink/basics/gas).
96 ///
97 /// **Note**
98 ///
99 /// This limit is only relevant for parachains, not for standalone chains which do not
100 /// require sending a Proof-of-validity to the relay chain.
101 pub fn proof_size_limit(self, proof_size_limit: Gas) -> Self {
102 let call_type = self.call_type.value();
103 CallBuilder {
104 call_type: Set(Call {
105 proof_size_limit,
106 ..call_type
107 }),
108 ..self
109 }
110 }
111
112 /// Sets the `storage_deposit_limit` for the current cross-contract call.
113 ///
114 /// The `storage_deposit_limit` specifies the amount of user funds that
115 /// can be charged for creating storage. You can find more info
116 /// [here](https://use.ink/basics/gas).
117 pub fn storage_deposit_limit(self, storage_deposit_limit: U256) -> Self {
118 let call_type = self.call_type.value();
119 CallBuilder {
120 call_type: Set(Call {
121 storage_deposit_limit: Some(storage_deposit_limit),
122 ..call_type
123 }),
124 ..self
125 }
126 }
127
128 /// Sets the `transferred_value` for the current cross-contract call.
129 ///
130 /// This value specifies the amount of user funds that are transferred
131 /// to the other contract with this call.
132 pub fn transferred_value(self, transferred_value: U256) -> Self {
133 let call_type = self.call_type.value();
134 CallBuilder {
135 call_type: Set(Call {
136 transferred_value,
137 ..call_type
138 }),
139 ..self
140 }
141 }
142
143 /// Sets the `call_flags` for the current cross-contract call.
144 ///
145 /// These flags are used to change the behavior of the contract call.
146 pub fn call_flags(self, call_flags: CallFlags) -> Self {
147 let call_type = self.call_type.value();
148 CallBuilder {
149 call_type: Set(Call {
150 call_flags,
151 ..call_type
152 }),
153 ..self
154 }
155 }
156}
157
158impl<E, Args, RetType, Abi>
159 CallBuilder<E, Set<Call>, Set<ExecutionInput<Args, Abi>>, Set<ReturnType<RetType>>>
160where
161 E: Environment,
162{
163 /// Finalizes the call builder to call a function.
164 pub fn params(self) -> CallParams<E, Call, Args, RetType, Abi> {
165 CallParams {
166 call_type: self.call_type.value(),
167 _return_type: Default::default(),
168 exec_input: self.exec_input.value(),
169 _phantom: self._phantom,
170 }
171 }
172}
173
174impl<E, RetType, Abi>
175 CallBuilder<
176 E,
177 Set<Call>,
178 Unset<ExecutionInput<EmptyArgumentList<Abi>, Abi>>,
179 Unset<RetType>,
180 >
181where
182 E: Environment,
183 Abi: Default,
184{
185 /// Finalizes the call builder to call a function.
186 pub fn params(self) -> CallParams<E, Call, EmptyArgumentList<Abi>, (), Abi> {
187 CallParams {
188 call_type: self.call_type.value(),
189 _return_type: Default::default(),
190 exec_input: Default::default(),
191 _phantom: self._phantom,
192 }
193 }
194}
195
196impl<E, Abi>
197 CallBuilder<
198 E,
199 Set<Call>,
200 Unset<ExecutionInput<EmptyArgumentList<Abi>, Abi>>,
201 Unset<ReturnType<()>>,
202 >
203where
204 E: Environment,
205 EmptyArgumentList<Abi>: AbiEncodeWith<Abi>,
206 (): DecodeMessageResult<Abi>,
207 Abi: Default,
208{
209 /// Invokes the cross-chain function call.
210 ///
211 /// # Panics
212 ///
213 /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`] or an
214 /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle
215 /// those use the [`try_invoke`][`CallBuilder::try_invoke`] method instead.
216 pub fn invoke(self) {
217 self.params().invoke()
218 }
219
220 /// Invokes the cross-chain function call.
221 ///
222 /// # Note
223 ///
224 /// On failure this returns an outer [`ink::env::Error`][`crate::Error`] or inner
225 /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be
226 /// handled by the caller.
227 pub fn try_invoke(self) -> Result<ink_primitives::MessageResult<()>, Error> {
228 self.params().try_invoke()
229 }
230}
231
232impl<E, Args, R, Abi>
233 CallBuilder<E, Set<Call>, Set<ExecutionInput<Args, Abi>>, Set<ReturnType<R>>>
234where
235 E: Environment,
236 Args: AbiEncodeWith<Abi>,
237 R: DecodeMessageResult<Abi>,
238 Abi: Default,
239{
240 /// Invokes the cross-chain function call and returns the result.
241 ///
242 /// # Panics
243 ///
244 /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`] or an
245 /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle
246 /// those use the [`try_invoke`][`CallBuilder::try_invoke`] method instead.
247 pub fn invoke(self) -> R {
248 self.params().invoke()
249 }
250
251 /// Invokes the cross-chain function call and returns the result.
252 ///
253 /// # Note
254 ///
255 /// On failure this returns an outer [`ink::env::Error`][`crate::Error`] or inner
256 /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be
257 /// handled by the caller.
258 pub fn try_invoke(self) -> Result<ink_primitives::MessageResult<R>, Error> {
259 self.params().try_invoke()
260 }
261}
262
263impl<E, Args, R, Abi> CallParams<E, Call, Args, R, Abi>
264where
265 E: Environment,
266{
267 /// Returns the contract address of the called contract instance.
268 #[inline]
269 pub fn callee(&self) -> &Address {
270 &self.call_type.callee
271 }
272
273 /// Returns the chosen ref time limit for the called contract execution.
274 #[inline]
275 pub fn ref_time_limit(&self) -> u64 {
276 self.call_type.ref_time_limit
277 }
278
279 /// Returns the chosen proof size limit for the called contract execution.
280 #[inline]
281 pub fn proof_size_limit(&self) -> u64 {
282 self.call_type.proof_size_limit
283 }
284
285 /// Returns the chosen storage deposit limit for the called contract execution.
286 /// todo
287 #[inline]
288 pub fn storage_deposit_limit(&self) -> Option<U256> {
289 self.call_type.storage_deposit_limit
290 }
291
292 /// Returns the transferred value for the called contract.
293 #[inline]
294 pub fn transferred_value(&self) -> &U256 {
295 &self.call_type.transferred_value
296 }
297
298 /// Returns the call flags.
299 #[inline]
300 pub fn call_flags(&self) -> &CallFlags {
301 &self.call_type.call_flags
302 }
303}
304
305impl<E, Args, R, Abi> CallParams<E, Call, Args, R, Abi>
306where
307 E: Environment,
308 Args: AbiEncodeWith<Abi>,
309 R: DecodeMessageResult<Abi>,
310{
311 /// Invokes the contract with the given built-up call parameters.
312 ///
313 /// Returns the result of the contract execution.
314 ///
315 /// # Panics
316 ///
317 /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`] or an
318 /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle
319 /// those use the [`try_invoke`][`CallParams::try_invoke`] method instead.
320 pub fn invoke(&self) -> R {
321 crate::invoke_contract(self)
322 .unwrap_or_else(|env_error| {
323 panic!("Cross-contract call failed with {env_error:?}")
324 })
325 .unwrap_or_else(|lang_error| {
326 panic!("Cross-contract call failed with {lang_error:?}")
327 })
328 }
329
330 /// Invokes the contract with the given built-up call parameters.
331 ///
332 /// Returns the result of the contract execution.
333 ///
334 /// # Note
335 ///
336 /// On failure this returns an outer [`ink::env::Error`][`crate::Error`] or inner
337 /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be
338 /// handled by the caller.
339 pub fn try_invoke(&self) -> Result<ink_primitives::MessageResult<R>, crate::Error> {
340 crate::invoke_contract(self)
341 }
342}