fuels_programs/calls/traits/
transaction_tuner.rs1use fuels_accounts::Account;
2use fuels_core::types::{
3 errors::{Context, Result, error},
4 transaction::{ScriptTransaction, TxPolicies},
5 transaction_builders::{
6 BuildableTransaction, ScriptTransactionBuilder, TransactionBuilder, VariableOutputPolicy,
7 },
8};
9
10use crate::{
11 DEFAULT_MAX_FEE_ESTIMATION_TOLERANCE,
12 calls::{
13 ContractCall, ScriptCall,
14 utils::{build_with_tb, sealed, transaction_builder_from_contract_calls},
15 },
16};
17
18#[async_trait::async_trait]
19pub trait TransactionTuner: sealed::Sealed {
20 async fn transaction_builder<T: Account>(
21 &self,
22 tx_policies: TxPolicies,
23 variable_output_policy: VariableOutputPolicy,
24 account: &T,
25 ) -> Result<ScriptTransactionBuilder>;
26
27 async fn build_tx<T: Account>(
28 &self,
29 tb: ScriptTransactionBuilder,
30 account: &T,
31 ) -> Result<ScriptTransaction>;
32}
33
34#[async_trait::async_trait]
35impl TransactionTuner for ContractCall {
36 async fn transaction_builder<T: Account>(
37 &self,
38 tx_policies: TxPolicies,
39 variable_output_policy: VariableOutputPolicy,
40 account: &T,
41 ) -> Result<ScriptTransactionBuilder> {
42 transaction_builder_from_contract_calls(
43 std::slice::from_ref(self),
44 tx_policies,
45 variable_output_policy,
46 account,
47 )
48 .await
49 }
50
51 async fn build_tx<T: Account>(
52 &self,
53 tb: ScriptTransactionBuilder,
54 account: &T,
55 ) -> Result<ScriptTransaction> {
56 build_with_tb(std::slice::from_ref(self), tb, account).await
57 }
58}
59
60#[async_trait::async_trait]
61impl TransactionTuner for ScriptCall {
62 async fn transaction_builder<T: Account>(
63 &self,
64 tx_policies: TxPolicies,
65 variable_output_policy: VariableOutputPolicy,
66 _account: &T,
67 ) -> Result<ScriptTransactionBuilder> {
68 let (inputs, outputs) = self.prepare_inputs_outputs()?;
69
70 Ok(ScriptTransactionBuilder::default()
71 .with_variable_output_policy(variable_output_policy)
72 .with_tx_policies(tx_policies)
73 .with_script(self.script_binary.clone())
74 .with_script_data(self.compute_script_data()?)
75 .with_inputs(inputs)
76 .with_outputs(outputs)
77 .with_gas_estimation_tolerance(DEFAULT_MAX_FEE_ESTIMATION_TOLERANCE)
78 .with_max_fee_estimation_tolerance(DEFAULT_MAX_FEE_ESTIMATION_TOLERANCE))
79 }
80
81 async fn build_tx<T: Account>(
82 &self,
83 mut tb: ScriptTransactionBuilder,
84 account: &T,
85 ) -> Result<ScriptTransaction> {
86 account.add_witnesses(&mut tb)?;
87 account
88 .adjust_for_fee(&mut tb, 0)
89 .await
90 .context("failed to adjust inputs to cover for missing base asset")?;
91
92 tb.build(account.try_provider()?).await
93 }
94}
95
96impl sealed::Sealed for Vec<ContractCall> {}
97
98#[async_trait::async_trait]
99impl TransactionTuner for Vec<ContractCall> {
100 async fn transaction_builder<T: Account>(
101 &self,
102 tx_policies: TxPolicies,
103 variable_output_policy: VariableOutputPolicy,
104 account: &T,
105 ) -> Result<ScriptTransactionBuilder> {
106 validate_contract_calls(self)?;
107
108 transaction_builder_from_contract_calls(self, tx_policies, variable_output_policy, account)
109 .await
110 }
111
112 async fn build_tx<T: Account>(
114 &self,
115 tb: ScriptTransactionBuilder,
116 account: &T,
117 ) -> Result<ScriptTransaction> {
118 validate_contract_calls(self)?;
119
120 build_with_tb(self, tb, account).await
121 }
122}
123
124fn validate_contract_calls(calls: &[ContractCall]) -> Result<()> {
125 if calls.is_empty() {
126 return Err(error!(
127 Other,
128 "no calls added. Have you used '.add_calls()'?"
129 ));
130 }
131
132 Ok(())
133}