1use super::{
16 balance_to_deposit_limit,
17 InstantiateDryRunResult,
18 Keypair,
19};
20use crate::{
21 backend::BuilderClient,
22 builders::CreateBuilderPartial,
23 CallBuilderFinal,
24 CallDryRunResult,
25 CallResult,
26 ContractsBackend,
27 InstantiationResult,
28 UploadResult,
29 H256,
30};
31use ink_env::Environment;
32use ink_primitives::{
33 reflect::{
34 AbiDecodeWith,
35 AbiEncodeWith,
36 ScaleEncoding,
37 },
38 DepositLimit,
39};
40use sp_weights::Weight;
41use std::marker::PhantomData;
42
43pub struct CallBuilder<'a, E, Args, RetType, B, Abi>
45where
46 E: Environment,
47 Args: AbiEncodeWith<Abi> + Clone,
48 RetType: Send + AbiDecodeWith<Abi>,
49
50 B: BuilderClient<E>,
51 Abi: Clone,
52{
53 client: &'a mut B,
54 caller: &'a Keypair,
55 message: &'a CallBuilderFinal<E, Args, RetType, Abi>,
56 value: E::Balance,
57 extra_gas_portion: Option<u64>,
58 gas_limit: Option<Weight>,
59 storage_deposit_limit: E::Balance,
60}
61
62impl<'a, E, Args, RetType, B, Abi> CallBuilder<'a, E, Args, RetType, B, Abi>
63where
64 E: Environment,
65 Args: Sync + AbiEncodeWith<Abi> + Clone,
66 RetType: Send + AbiDecodeWith<Abi>,
67
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: 0u32.into(),
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 = storage_deposit_limit;
135 self
136 }
137
138 pub async fn submit(
143 &mut self,
144 ) -> Result<CallResult<E, RetType, B::EventLog>, 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::<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>, 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::<E>(self.storage_deposit_limit),
197 )
198 .await
199 }
200}
201
202pub struct InstantiateBuilder<'a, E, Contract, Args, R, B>
204where
205 E: Environment,
206 Args: AbiEncodeWith<ScaleEncoding> + Clone,
207 Contract: Clone,
208
209 B: ContractsBackend<E>,
210{
211 client: &'a mut B,
212 caller: &'a Keypair,
213 contract_name: &'a str,
214 constructor: &'a mut CreateBuilderPartial<E, Contract, Args, R>,
215 value: E::Balance,
216 extra_gas_portion: Option<u64>,
217 gas_limit: Option<Weight>,
218 storage_deposit_limit: DepositLimit<E::Balance>,
219}
220
221impl<'a, E, Contract, Args, R, B> InstantiateBuilder<'a, E, Contract, Args, R, B>
222where
223 E: Environment,
224 Args: AbiEncodeWith<ScaleEncoding> + Clone + Send + Sync,
225 Contract: Clone,
226 B: BuilderClient<E>,
227{
228 pub fn new(
230 client: &'a mut B,
231 caller: &'a Keypair,
232 contract_name: &'a str,
233 constructor: &'a mut CreateBuilderPartial<E, Contract, Args, R>,
234 ) -> InstantiateBuilder<'a, E, Contract, Args, R, B>
235 where
236 E::Balance: From<u32>,
237 {
238 Self {
239 client,
240 caller,
241 contract_name,
242 constructor,
243 value: 0u32.into(),
244 extra_gas_portion: None,
245 gas_limit: None,
246 storage_deposit_limit: DepositLimit::Unchecked,
247 }
248 }
249
250 pub fn value(&mut self, value: E::Balance) -> &mut Self {
252 self.value = value;
253 self
254 }
255
256 pub fn extra_gas_portion(&mut self, per_cent: u64) -> &mut Self {
265 if per_cent == 0 {
266 self.extra_gas_portion = None
267 } else {
268 self.extra_gas_portion = Some(per_cent)
269 }
270 self
271 }
272
273 pub fn gas_limit(&mut self, limit: Weight) -> &mut Self {
280 if limit == Weight::from_parts(0, 0) {
281 self.gas_limit = None
282 } else {
283 self.gas_limit = Some(limit)
284 }
285 self
286 }
287
288 pub fn storage_deposit_limit(
290 &mut self,
291 storage_deposit_limit: DepositLimit<E::Balance>,
292 ) -> &mut Self {
293 self.storage_deposit_limit = storage_deposit_limit;
294 self
295 }
296
297 pub async fn submit(
302 &mut self,
303 ) -> Result<InstantiationResult<E, B::EventLog>, B::Error> {
304 let _map = B::map_account(self.client, self.caller).await; let dry_run = B::bare_instantiate_dry_run(
308 self.client,
309 self.contract_name,
310 self.caller,
311 self.constructor,
312 self.value,
313 self.storage_deposit_limit.clone(),
314 )
315 .await?;
316
317 let gas_limit = if let Some(limit) = self.gas_limit {
318 limit
319 } else {
320 let gas_required = dry_run.contract_result.gas_required;
321 let proof_size = gas_required.proof_size();
322 let ref_time = gas_required.ref_time();
323 calculate_weight(proof_size, ref_time, self.extra_gas_portion)
324 };
325
326 let instantiate_result = B::bare_instantiate(
327 self.client,
328 self.contract_name,
329 self.caller,
330 self.constructor,
331 self.value,
332 gas_limit,
333 balance_to_deposit_limit::<E>(
334 dry_run.contract_result.storage_deposit.charge_or_zero(),
335 ),
336 )
337 .await?;
338
339 Ok(InstantiationResult {
340 addr: instantiate_result.addr,
341 dry_run,
342 events: instantiate_result.events,
343 trace: instantiate_result.trace,
344 code_hash: instantiate_result.code_hash,
345 })
346 }
347
348 pub async fn dry_run(&mut self) -> Result<InstantiateDryRunResult<E>, B::Error> {
350 B::bare_instantiate_dry_run(
351 self.client,
352 self.contract_name,
353 self.caller,
354 self.constructor,
355 self.value,
356 self.storage_deposit_limit.clone(),
357 )
358 .await
359 }
360}
361
362pub struct UploadBuilder<'a, E, B>
364where
365 E: Environment,
366 B: BuilderClient<E>,
367{
368 client: &'a mut B,
369 contract_name: &'a str,
370 caller: &'a Keypair,
371 storage_deposit_limit: E::Balance,
372}
373
374impl<'a, E, B> UploadBuilder<'a, E, B>
375where
376 E: Environment,
377 B: BuilderClient<E>,
378{
379 pub fn new(client: &'a mut B, contract_name: &'a str, caller: &'a Keypair) -> Self {
381 Self {
382 client,
383 contract_name,
384 caller,
385 storage_deposit_limit: 0u32.into(),
386 }
387 }
388
389 pub fn storage_deposit_limit(
391 &mut self,
392 storage_deposit_limit: E::Balance,
393 ) -> &mut Self {
394 self.storage_deposit_limit = storage_deposit_limit;
395 self
396 }
397
398 pub async fn submit(&mut self) -> Result<UploadResult<E, B::EventLog>, B::Error> {
400 B::bare_upload(
401 self.client,
402 self.contract_name,
403 self.caller,
404 self.storage_deposit_limit,
405 )
406 .await
407 }
408}
409
410pub struct RemoveCodeBuilder<'a, E, B>
412where
413 E: Environment,
414 B: BuilderClient<E>,
415{
416 client: &'a mut B,
417 caller: &'a Keypair,
418 code_hash: crate::H256,
419 _phantom: PhantomData<fn() -> E>,
420}
421
422impl<'a, E, B> RemoveCodeBuilder<'a, E, B>
423where
424 E: Environment,
425 B: BuilderClient<E>,
426{
427 pub fn new(client: &'a mut B, caller: &'a Keypair, code_hash: H256) -> Self {
429 Self {
430 client,
431 caller,
432 code_hash,
433 _phantom: Default::default(),
434 }
435 }
436
437 pub async fn submit(&mut self) -> Result<B::EventLog, B::Error> {
439 B::bare_remove_code(self.client, self.caller, self.code_hash).await
440 }
441}
442
443fn calculate_weight(
444 mut proof_size: u64,
445 mut ref_time: u64,
446 portion: Option<u64>,
447) -> Weight {
448 if let Some(m) = portion {
449 ref_time += ref_time / 100 * m;
450 proof_size += proof_size / 100 * m;
451 }
452 Weight::from_parts(ref_time, proof_size)
453}