fuels_programs/calls/traits/
transaction_tuner.rs

1use 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    /// Returns the script that executes the contract calls
113    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}