multiversx_sc_scenario/scenario/model/step/
sc_query_step.rs

1use multiversx_sc::{abi::TypeAbiFrom, types::H256};
2use num_traits::Zero;
3
4use crate::{
5    api::StaticApi,
6    multiversx_sc::{codec::TopEncodeMulti, types::ContractCall},
7    scenario::model::{AddressValue, BytesValue, TxExpect, TxQuery},
8    scenario_model::TxResponse,
9};
10
11use super::{process_contract_call, TypedScQuery};
12
13#[derive(Debug, Clone)]
14pub struct ScQueryStep {
15    pub id: String,
16    pub tx_id: Option<String>,
17    pub explicit_tx_hash: Option<H256>,
18    pub comment: Option<String>,
19    pub tx: Box<TxQuery>,
20    pub expect: Option<TxExpect>,
21    pub response: Option<TxResponse>,
22}
23
24impl Default for ScQueryStep {
25    fn default() -> Self {
26        Self {
27            id: Default::default(),
28            tx_id: Default::default(),
29            explicit_tx_hash: Default::default(),
30            comment: Default::default(),
31            tx: Default::default(),
32            expect: Some(TxExpect::ok()),
33            response: Default::default(),
34        }
35    }
36}
37
38impl ScQueryStep {
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    pub fn to<A>(mut self, address: A) -> Self
44    where
45        AddressValue: From<A>,
46    {
47        self.tx.to = AddressValue::from(address);
48        self
49    }
50
51    pub fn function(mut self, expr: &str) -> Self {
52        self.tx.function = expr.to_string();
53        self
54    }
55
56    pub fn argument(mut self, expr: &str) -> Self {
57        self.tx.arguments.push(BytesValue::from(expr));
58        self
59    }
60
61    /// Sets following fields based on the smart contract proxy:
62    /// - "to"
63    /// - "function"
64    /// - "arguments"
65    #[deprecated(
66        since = "0.49.0",
67        note = "Please use the unified transaction syntax instead."
68    )]
69    #[allow(deprecated)]
70    pub fn call<CC>(mut self, contract_call: CC) -> TypedScQuery<CC::OriginalResult>
71    where
72        CC: multiversx_sc::types::ContractCallBase<StaticApi>,
73    {
74        let (to_str, function, egld_value_expr, mandos_args) = process_contract_call(contract_call);
75        assert!(
76            egld_value_expr.value.is_zero(),
77            "cannot send EGLD value in queries"
78        );
79        self = self.to(to_str.as_str());
80        self = self.function(function.as_str());
81        for arg in mandos_args {
82            self = self.argument(arg.as_str());
83        }
84        self.into()
85    }
86
87    /// Sets following fields based on the smart contract proxy:
88    /// - "to"
89    /// - "function"
90    /// - "arguments"
91    /// - "expect"
92    ///     - "out"
93    ///     - "status" set to 0
94    #[deprecated(
95        since = "0.49.0",
96        note = "Please use the unified transaction syntax instead."
97    )]
98    #[allow(deprecated)]
99    pub fn call_expect<CC, ExpectedResult>(
100        self,
101        contract_call: CC,
102        expected_value: ExpectedResult,
103    ) -> TypedScQuery<CC::OriginalResult>
104    where
105        CC: ContractCall<StaticApi>,
106        ExpectedResult: TypeAbiFrom<CC::OriginalResult> + TopEncodeMulti,
107    {
108        let typed = self.call(contract_call);
109        typed.expect_value(expected_value)
110    }
111
112    /// Adds a custom expect section to the tx.
113    pub fn expect(mut self, expect: TxExpect) -> Self {
114        self.expect = Some(expect);
115        self
116    }
117
118    /// Explicitly states that no tx expect section should be added and no checks should be performed.
119    ///
120    /// Note: by default a basic `TxExpect::ok()` is added, which checks that status is 0 and nothing else.
121    pub fn no_expect(mut self) -> Self {
122        self.expect = None;
123        self
124    }
125
126    /// Unwraps the response, if available.
127    pub fn response(&self) -> &TxResponse {
128        self.response
129            .as_ref()
130            .expect("SC query response not yet available")
131    }
132
133    pub fn save_response(&mut self, tx_response: TxResponse) {
134        if let Some(expect) = &mut self.expect {
135            if expect.build_from_response {
136                expect.update_from_response(&tx_response)
137            }
138        }
139        self.response = Some(tx_response);
140    }
141}