1use std::marker::PhantomData;
16
17use ink_env::{
18 call::utils::DecodeMessageResult,
19 Environment,
20};
21use ink_primitives::{
22 abi::AbiEncodeWith,
23 DepositLimit,
24};
25use sp_weights::Weight;
26
27use super::{
28 balance_to_deposit_limit,
29 InstantiateDryRunResult,
30 Keypair,
31};
32use crate::{
33 backend::BuilderClient,
34 builders::CreateBuilderPartial,
35 CallBuilderFinal,
36 CallDryRunResult,
37 CallResult,
38 ContractsBackend,
39 InstantiationResult,
40 UploadResult,
41 H256,
42};
43
44pub struct CallBuilder<'a, E, Args, RetType, B, Abi>
46where
47 E: Environment,
48 Args: AbiEncodeWith<Abi> + Clone,
49 RetType: Send + DecodeMessageResult<Abi>,
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 + DecodeMessageResult<Abi>,
67 B: BuilderClient<E>,
68 Abi: Sync + Clone,
69{
70 pub fn new(
72 client: &'a mut B,
73 caller: &'a Keypair,
74 message: &'a CallBuilderFinal<E, Args, RetType, Abi>,
75 ) -> CallBuilder<'a, E, Args, RetType, B, Abi>
76 where
77 E::Balance: From<u32>,
78 {
79 Self {
80 client,
81 caller,
82 message,
83 value: 0u32.into(),
84 extra_gas_portion: None,
85 gas_limit: None,
86 storage_deposit_limit: 0u32.into(),
87 }
88 }
89
90 pub fn value(&mut self, value: E::Balance) -> &mut Self {
92 self.value = value;
93 self
94 }
95
96 pub fn extra_gas_portion(&mut self, per_cent: u64) -> &mut Self {
105 if per_cent == 0 {
106 self.extra_gas_portion = None
107 } else {
108 self.extra_gas_portion = Some(per_cent)
109 }
110 self
111 }
112
113 pub fn gas_limit(&mut self, limit: Weight) -> &mut Self {
120 if limit == Weight::from_parts(0, 0) {
121 self.gas_limit = None
122 } else {
123 self.gas_limit = Some(limit)
124 }
125 self
126 }
127
128 pub fn storage_deposit_limit(
130 &mut self,
131 storage_deposit_limit: E::Balance,
132 ) -> &mut Self {
133 self.storage_deposit_limit = storage_deposit_limit;
134 self
135 }
136
137 pub async fn submit(
142 &mut self,
143 ) -> Result<CallResult<E, RetType, B::EventLog, Abi>, B::Error>
144 where
145 CallBuilderFinal<E, Args, RetType, Abi>: Clone,
146 {
147 let _map = B::map_account(self.client, self.caller).await; let dry_run = B::bare_call_dry_run(
150 self.client,
151 self.caller,
152 self.message,
153 self.value,
154 balance_to_deposit_limit::<E>(self.storage_deposit_limit),
155 )
156 .await?;
157
158 let gas_limit = if let Some(limit) = self.gas_limit {
159 limit
160 } else {
161 let gas_required = dry_run.exec_result.gas_required;
162 let proof_size = gas_required.proof_size();
163 let ref_time = gas_required.ref_time();
164 calculate_weight(proof_size, ref_time, self.extra_gas_portion)
165 };
166
167 let (events, trace) = B::bare_call(
168 self.client,
169 self.caller,
170 self.message,
171 self.value,
172 gas_limit,
173 DepositLimit::Balance(dry_run.exec_result.storage_deposit.charge_or_zero()),
175 )
176 .await?;
177
178 Ok(CallResult {
179 dry_run,
180 events,
181 trace,
182 })
183 }
184
185 pub async fn dry_run(&mut self) -> Result<CallDryRunResult<E, RetType, Abi>, B::Error>
187 where
188 CallBuilderFinal<E, Args, RetType, Abi>: Clone,
189 {
190 B::bare_call_dry_run(
191 self.client,
192 self.caller,
193 self.message,
194 self.value,
195 balance_to_deposit_limit::<E>(self.storage_deposit_limit),
196 )
197 .await
198 }
199}
200
201pub struct InstantiateBuilder<'a, E, Contract, Args, R, B, Abi>
203where
204 E: Environment,
205 Args: AbiEncodeWith<Abi> + Clone,
206 Contract: Clone,
207 B: ContractsBackend<E>,
208{
209 client: &'a mut B,
210 caller: &'a Keypair,
211 contract_name: &'a str,
212 constructor: &'a mut CreateBuilderPartial<E, Contract, Args, R, Abi>,
213 value: E::Balance,
214 extra_gas_portion: Option<u64>,
215 gas_limit: Option<Weight>,
216 storage_deposit_limit: DepositLimit<E::Balance>,
217}
218
219impl<'a, E, Contract, Args, R, B, Abi>
220 InstantiateBuilder<'a, E, Contract, Args, R, B, Abi>
221where
222 E: Environment,
223 Args: AbiEncodeWith<Abi> + Clone + Send + Sync,
224 Contract: Clone,
225 B: BuilderClient<E>,
226 Abi: Send + Sync + Clone,
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, Abi>,
234 ) -> InstantiateBuilder<'a, E, Contract, Args, R, B, Abi>
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::UnsafeOnlyForDryRun,
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, Abi>, 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, Abi>, 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}