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