1use std::marker::PhantomData;
16
17use ink_env::{
18 Environment,
19 call::utils::{
20 DecodeMessageResult,
21 EncodeArgsWith,
22 },
23};
24use sp_weights::Weight;
25
26use super::{
27 InstantiateDryRunResult,
28 Keypair,
29};
30use crate::{
31 CallBuilderFinal,
32 CallDryRunResult,
33 CallResult,
34 ContractsBackend,
35 H256,
36 InstantiationResult,
37 UploadResult,
38 backend::BuilderClient,
39 builders::CreateBuilderPartial,
40};
41
42pub struct CallBuilder<'a, E, Args, RetType, B, Abi>
44where
45 E: Environment,
46 Args: EncodeArgsWith<Abi> + Clone,
47 RetType: Send + DecodeMessageResult<Abi>,
48 B: BuilderClient<E>,
49 Abi: Clone,
50{
51 client: &'a mut B,
52 caller: &'a Keypair,
53 message: &'a CallBuilderFinal<E, Args, RetType, Abi>,
54 value: E::Balance,
55 extra_gas_portion: Option<u64>,
56 gas_limit: Option<Weight>,
57 storage_deposit_limit: Option<E::Balance>,
58}
59
60impl<'a, E, Args, RetType, B, Abi> CallBuilder<'a, E, Args, RetType, B, Abi>
61where
62 E: Environment,
63 Args: Sync + EncodeArgsWith<Abi> + Clone,
64 RetType: Send + DecodeMessageResult<Abi>,
65 B: BuilderClient<E>,
66 Abi: Sync + Clone,
67{
68 pub fn new(
70 client: &'a mut B,
71 caller: &'a Keypair,
72 message: &'a CallBuilderFinal<E, Args, RetType, Abi>,
73 ) -> CallBuilder<'a, E, Args, RetType, B, Abi>
74 where
75 E::Balance: From<u32>,
76 {
77 Self {
78 client,
79 caller,
80 message,
81 value: 0u32.into(),
82 extra_gas_portion: None,
83 gas_limit: None,
84 storage_deposit_limit: None,
85 }
86 }
87
88 pub fn value(&mut self, value: E::Balance) -> &mut Self {
90 self.value = value;
91 self
92 }
93
94 pub fn extra_gas_portion(&mut self, per_cent: u64) -> &mut Self {
103 if per_cent == 0 {
104 self.extra_gas_portion = None
105 } else {
106 self.extra_gas_portion = Some(per_cent)
107 }
108 self
109 }
110
111 pub fn gas_limit(&mut self, limit: Weight) -> &mut Self {
118 if limit == Weight::from_parts(0, 0) {
119 self.gas_limit = None
120 } else {
121 self.gas_limit = Some(limit)
122 }
123 self
124 }
125
126 pub fn storage_deposit_limit(
128 &mut self,
129 storage_deposit_limit: E::Balance,
130 ) -> &mut Self {
131 self.storage_deposit_limit = Some(storage_deposit_limit);
132 self
133 }
134
135 pub async fn submit(
140 &mut self,
141 ) -> Result<CallResult<E, RetType, B::EventLog, Abi>, B::Error>
142 where
143 CallBuilderFinal<E, Args, RetType, Abi>: Clone,
144 {
145 let _map = B::map_account(self.client, self.caller).await; let dry_run = B::bare_call_dry_run(
148 self.client,
149 self.caller,
150 self.message,
151 self.value,
152 self.storage_deposit_limit,
153 )
154 .await?;
155
156 let gas_limit = if let Some(limit) = self.gas_limit {
157 limit
158 } else {
159 let gas_required = dry_run.exec_result.gas_required;
160 let proof_size = gas_required.proof_size();
161 let ref_time = gas_required.ref_time();
162 calculate_weight(proof_size, ref_time, self.extra_gas_portion)
163 };
164
165 let (events, trace) = B::bare_call(
166 self.client,
167 self.caller,
168 self.message,
169 self.value,
170 gas_limit,
171 dry_run.exec_result.storage_deposit.charge_or_zero(),
172 )
173 .await?;
174
175 Ok(CallResult {
176 dry_run,
177 events,
178 trace,
179 })
180 }
181
182 pub async fn dry_run(&mut self) -> Result<CallDryRunResult<E, RetType, Abi>, B::Error>
184 where
185 CallBuilderFinal<E, Args, RetType, Abi>: Clone,
186 {
187 B::bare_call_dry_run(
188 self.client,
189 self.caller,
190 self.message,
191 self.value,
192 self.storage_deposit_limit,
193 )
194 .await
195 }
196}
197
198pub struct InstantiateBuilder<'a, E, Contract, Args, R, B, Abi>
200where
201 E: Environment,
202 Args: EncodeArgsWith<Abi> + Clone,
203 Contract: Clone,
204 B: ContractsBackend<E>,
205{
206 client: &'a mut B,
207 caller: &'a Keypair,
208 contract_name: &'a str,
209 constructor: &'a mut CreateBuilderPartial<E, Contract, Args, R, Abi>,
210 value: E::Balance,
211 extra_gas_portion: Option<u64>,
212 gas_limit: Option<Weight>,
213 storage_deposit_limit: Option<E::Balance>,
214}
215
216impl<'a, E, Contract, Args, R, B, Abi>
217 InstantiateBuilder<'a, E, Contract, Args, R, B, Abi>
218where
219 E: Environment,
220 Args: EncodeArgsWith<Abi> + Clone + Send + Sync,
221 Contract: Clone,
222 B: BuilderClient<E>,
223 Abi: Send + Sync + Clone,
224{
225 pub fn new(
227 client: &'a mut B,
228 caller: &'a Keypair,
229 contract_name: &'a str,
230 constructor: &'a mut CreateBuilderPartial<E, Contract, Args, R, Abi>,
231 ) -> InstantiateBuilder<'a, E, Contract, Args, R, B, Abi>
232 where
233 E::Balance: From<u32>,
234 {
235 Self {
236 client,
237 caller,
238 contract_name,
239 constructor,
240 value: 0u32.into(),
241 extra_gas_portion: None,
242 gas_limit: None,
243 storage_deposit_limit: None,
244 }
245 }
246
247 pub fn value(&mut self, value: E::Balance) -> &mut Self {
249 self.value = value;
250 self
251 }
252
253 pub fn extra_gas_portion(&mut self, per_cent: u64) -> &mut Self {
262 if per_cent == 0 {
263 self.extra_gas_portion = None
264 } else {
265 self.extra_gas_portion = Some(per_cent)
266 }
267 self
268 }
269
270 pub fn gas_limit(&mut self, limit: Weight) -> &mut Self {
277 if limit == Weight::from_parts(0, 0) {
278 self.gas_limit = None
279 } else {
280 self.gas_limit = Some(limit)
281 }
282 self
283 }
284
285 pub fn storage_deposit_limit(
289 &mut self,
290 storage_deposit_limit: Option<E::Balance>,
291 ) -> &mut Self {
292 self.storage_deposit_limit = storage_deposit_limit;
293 self
294 }
295
296 pub async fn submit(
301 &mut self,
302 ) -> Result<InstantiationResult<E, B::EventLog, Abi>, B::Error> {
303 let _map = B::map_account(self.client, self.caller).await; let dry_run = B::bare_instantiate_dry_run(
307 self.client,
308 self.contract_name,
309 self.caller,
310 self.constructor,
311 self.value,
312 self.storage_deposit_limit.clone(),
313 )
314 .await?;
315
316 let gas_limit = if let Some(limit) = self.gas_limit {
317 limit
318 } else {
319 let gas_required = dry_run.contract_result.gas_required;
320 let proof_size = gas_required.proof_size();
321 let ref_time = gas_required.ref_time();
322 calculate_weight(proof_size, ref_time, self.extra_gas_portion)
323 };
324
325 let instantiate_result = B::bare_instantiate(
326 self.client,
327 B::load_code(self.client, self.contract_name),
328 self.caller,
329 self.constructor,
330 self.value,
331 gas_limit,
332 dry_run.contract_result.storage_deposit.charge_or_zero(),
333 )
334 .await?;
335
336 Ok(InstantiationResult {
337 addr: instantiate_result.addr,
338 account_id: instantiate_result.account_id,
339 dry_run,
340 events: instantiate_result.events,
341 trace: instantiate_result.trace,
342 code_hash: instantiate_result.code_hash,
343 })
344 }
345
346 pub async fn dry_run(&mut self) -> Result<InstantiateDryRunResult<E, Abi>, B::Error> {
348 B::bare_instantiate_dry_run(
349 self.client,
350 self.contract_name,
351 self.caller,
352 self.constructor,
353 self.value,
354 self.storage_deposit_limit.clone(),
355 )
356 .await
357 }
358}
359
360pub struct UploadBuilder<'a, E, B>
362where
363 E: Environment,
364 B: BuilderClient<E>,
365{
366 client: &'a mut B,
367 contract_name: &'a str,
368 caller: &'a Keypair,
369 storage_deposit_limit: Option<E::Balance>,
370}
371
372impl<'a, E, B> UploadBuilder<'a, E, B>
373where
374 E: Environment,
375 B: BuilderClient<E>,
376{
377 pub fn new(client: &'a mut B, contract_name: &'a str, caller: &'a Keypair) -> Self {
379 Self {
380 client,
381 contract_name,
382 caller,
383 storage_deposit_limit: None,
384 }
385 }
386
387 pub fn storage_deposit_limit(
389 &mut self,
390 storage_deposit_limit: Option<E::Balance>,
391 ) -> &mut Self {
392 self.storage_deposit_limit = storage_deposit_limit;
393 self
394 }
395
396 pub async fn submit(&mut self) -> Result<UploadResult<E, B::EventLog>, B::Error> {
398 B::bare_upload(
399 self.client,
400 self.contract_name,
401 self.caller,
402 self.storage_deposit_limit,
403 )
404 .await
405 }
406}
407
408pub struct RemoveCodeBuilder<'a, E, B>
410where
411 E: Environment,
412 B: BuilderClient<E>,
413{
414 client: &'a mut B,
415 caller: &'a Keypair,
416 code_hash: crate::H256,
417 _phantom: PhantomData<fn() -> E>,
418}
419
420impl<'a, E, B> RemoveCodeBuilder<'a, E, B>
421where
422 E: Environment,
423 B: BuilderClient<E>,
424{
425 pub fn new(client: &'a mut B, caller: &'a Keypair, code_hash: H256) -> Self {
427 Self {
428 client,
429 caller,
430 code_hash,
431 _phantom: Default::default(),
432 }
433 }
434
435 pub async fn submit(&mut self) -> Result<B::EventLog, B::Error> {
437 B::bare_remove_code(self.client, self.caller, self.code_hash).await
438 }
439}
440
441fn calculate_weight(
442 mut proof_size: u64,
443 mut ref_time: u64,
444 portion: Option<u64>,
445) -> Weight {
446 if let Some(m) = portion {
447 ref_time += ref_time / 100 * m;
448 proof_size += proof_size / 100 * m;
449 }
450 Weight::from_parts(ref_time, proof_size)
451}