fuels_programs/calls/
contract_call.rs

1use std::{collections::HashMap, fmt::Debug};
2
3use fuel_tx::AssetId;
4use fuels_core::{
5    constants::DEFAULT_CALL_PARAMS_AMOUNT,
6    error,
7    types::{
8        bech32::{Bech32Address, Bech32ContractId},
9        errors::Result,
10        input::Input,
11        output::Output,
12        param_types::ParamType,
13        Selector,
14    },
15};
16
17use crate::{assembly::contract_call::ContractCallData, calls::utils::sealed};
18
19#[derive(Debug, Clone)]
20/// Contains all data relevant to a single contract call
21pub struct ContractCall {
22    pub contract_id: Bech32ContractId,
23    pub encoded_args: Result<Vec<u8>>,
24    pub encoded_selector: Selector,
25    pub call_parameters: CallParameters,
26    pub external_contracts: Vec<Bech32ContractId>,
27    pub output_param: ParamType,
28    pub is_payable: bool,
29    pub custom_assets: HashMap<(AssetId, Option<Bech32Address>), u64>,
30    pub inputs: Vec<Input>,
31    pub outputs: Vec<Output>,
32}
33
34impl ContractCall {
35    pub(crate) fn data(&self, base_asset_id: AssetId) -> Result<ContractCallData> {
36        let encoded_args = self
37            .encoded_args
38            .as_ref()
39            .map_err(|e| error!(Codec, "cannot encode contract call arguments: {e}"))?
40            .to_owned();
41
42        Ok(ContractCallData {
43            amount: self.call_parameters.amount(),
44            asset_id: self.call_parameters.asset_id().unwrap_or(base_asset_id),
45            contract_id: self.contract_id.clone().into(),
46            fn_selector_encoded: self.encoded_selector.clone(),
47            encoded_args,
48            gas_forwarded: self.call_parameters.gas_forwarded,
49        })
50    }
51
52    pub fn with_contract_id(self, contract_id: Bech32ContractId) -> Self {
53        ContractCall {
54            contract_id,
55            ..self
56        }
57    }
58
59    pub fn with_call_parameters(self, call_parameters: CallParameters) -> ContractCall {
60        ContractCall {
61            call_parameters,
62            ..self
63        }
64    }
65
66    pub fn add_custom_asset(&mut self, asset_id: AssetId, amount: u64, to: Option<Bech32Address>) {
67        *self.custom_assets.entry((asset_id, to)).or_default() += amount;
68    }
69
70    /// Add custom outputs to the `ContractCall`.
71    pub fn with_outputs(mut self, outputs: Vec<Output>) -> Self {
72        self.outputs = outputs;
73        self
74    }
75
76    /// Add custom inputs to the `ContractCall`.
77    pub fn with_inputs(mut self, inputs: Vec<Input>) -> Self {
78        self.inputs = inputs;
79        self
80    }
81}
82
83impl sealed::Sealed for ContractCall {}
84
85#[derive(Debug, Clone)]
86pub struct CallParameters {
87    amount: u64,
88    asset_id: Option<AssetId>,
89    gas_forwarded: Option<u64>,
90}
91
92impl CallParameters {
93    pub fn new(amount: u64, asset_id: AssetId, gas_forwarded: u64) -> Self {
94        Self {
95            amount,
96            asset_id: Some(asset_id),
97            gas_forwarded: Some(gas_forwarded),
98        }
99    }
100
101    pub fn with_amount(mut self, amount: u64) -> Self {
102        self.amount = amount;
103        self
104    }
105
106    pub fn amount(&self) -> u64 {
107        self.amount
108    }
109
110    pub fn with_asset_id(mut self, asset_id: AssetId) -> Self {
111        self.asset_id = Some(asset_id);
112        self
113    }
114
115    pub fn asset_id(&self) -> Option<AssetId> {
116        self.asset_id
117    }
118
119    pub fn with_gas_forwarded(mut self, gas_forwarded: u64) -> Self {
120        self.gas_forwarded = Some(gas_forwarded);
121        self
122    }
123
124    pub fn gas_forwarded(&self) -> Option<u64> {
125        self.gas_forwarded
126    }
127}
128
129impl Default for CallParameters {
130    fn default() -> Self {
131        Self {
132            amount: DEFAULT_CALL_PARAMS_AMOUNT,
133            asset_id: None,
134            gas_forwarded: None,
135        }
136    }
137}