multiversx_sc_scenario/scenario/model/step/
sc_call_step.rs1use multiversx_sc::types::H256;
2
3use crate::{
4 api::StaticApi,
5 scenario::model::{AddressValue, BigUintValue, BytesValue, TxCall, TxESDT, TxExpect, U64Value},
6 scenario_model::TxResponse,
7};
8
9use crate::multiversx_sc::types::ManagedArgBuffer;
10
11#[derive(Debug, Clone)]
12pub struct ScCallStep {
13 pub id: String,
14 pub tx_id: Option<String>,
15 pub explicit_tx_hash: Option<H256>,
16 pub comment: Option<String>,
17 pub tx: Box<TxCall>,
18 pub expect: Option<TxExpect>,
19 pub response: Option<TxResponse>,
20}
21
22impl Default for ScCallStep {
23 fn default() -> Self {
24 Self {
25 id: Default::default(),
26 tx_id: Default::default(),
27 explicit_tx_hash: Default::default(),
28 comment: Default::default(),
29 tx: Default::default(),
30 expect: Some(TxExpect::ok()),
31 response: Default::default(),
32 }
33 }
34}
35
36impl ScCallStep {
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn from<A>(mut self, address: A) -> Self
42 where
43 AddressValue: From<A>,
44 {
45 self.tx.from = AddressValue::from(address);
46 self
47 }
48
49 pub fn to<A>(mut self, address: A) -> Self
50 where
51 AddressValue: From<A>,
52 {
53 self.tx.to = AddressValue::from(address);
54 self
55 }
56
57 pub fn egld_value<A>(mut self, amount: A) -> Self
58 where
59 BigUintValue: From<A>,
60 {
61 if !self.tx.esdt_value.is_empty() && self.tx.egld_value.value > 0u32.into() {
62 panic!("Cannot transfer both EGLD and ESDT");
63 }
64
65 self.tx.egld_value = BigUintValue::from(amount);
66 self
67 }
68
69 pub fn esdt_transfer<T, N, A>(mut self, token_id: T, token_nonce: N, amount: A) -> Self
70 where
71 BytesValue: From<T>,
72 U64Value: From<N>,
73 BigUintValue: From<A>,
74 {
75 if self.tx.egld_value.value > 0u32.into() {
76 panic!("Cannot transfer both EGLD and ESDT");
77 }
78
79 self.tx.esdt_value.push(TxESDT {
80 esdt_token_identifier: BytesValue::from(token_id),
81 nonce: U64Value::from(token_nonce),
82 esdt_value: BigUintValue::from(amount),
83 });
84
85 self
86 }
87
88 pub fn multi_esdt_transfer<T>(mut self, tokens: T) -> Self
89 where
90 T: IntoIterator<Item = TxESDT>,
91 {
92 if self.tx.egld_value.value > 0u32.into() {
93 panic!("Cannot transfer both EGLD and ESDT");
94 }
95
96 self.tx.esdt_value.extend(tokens);
97
98 self
99 }
100
101 pub fn function(mut self, expr: &str) -> Self {
102 self.tx.function = expr.to_string();
103 self
104 }
105
106 pub fn tx_hash<T>(mut self, tx_hash_expr: T) -> Self
107 where
108 H256: From<T>,
109 {
110 self.explicit_tx_hash = Some(tx_hash_expr.into());
111 self
112 }
113
114 pub fn argument<A>(mut self, expr: A) -> Self
115 where
116 BytesValue: From<A>,
117 {
118 self.tx.arguments.push(BytesValue::from(expr));
119 self
120 }
121
122 pub fn gas_limit<V>(mut self, value: V) -> Self
123 where
124 U64Value: From<V>,
125 {
126 self.tx.gas_limit = U64Value::from(value);
127 self
128 }
129
130 pub fn expect(mut self, expect: TxExpect) -> Self {
132 self.expect = Some(expect);
133 self
134 }
135
136 pub fn no_expect(mut self) -> Self {
140 self.expect = None;
141 self
142 }
143
144 pub fn response(&self) -> &TxResponse {
146 self.response
147 .as_ref()
148 .expect("SC call response not yet available")
149 }
150
151 pub fn save_response(&mut self, mut tx_response: TxResponse) {
152 if let Some(expect) = &mut self.expect {
153 if expect.build_from_response {
154 expect.update_from_response(&tx_response)
155 }
156 }
157 if tx_response.tx_hash.is_none() {
158 tx_response.tx_hash = self
159 .explicit_tx_hash
160 .as_ref()
161 .map(|vm_hash| vm_hash.as_array().into());
162 }
163 self.response = Some(tx_response);
164 }
165}
166
167impl AsMut<ScCallStep> for ScCallStep {
168 fn as_mut(&mut self) -> &mut ScCallStep {
169 self
170 }
171}
172
173pub fn convert_call_args(arg_buffer: &ManagedArgBuffer<StaticApi>) -> Vec<String> {
174 arg_buffer
175 .to_raw_args_vec()
176 .iter()
177 .map(|arg| format!("0x{}", hex::encode(arg)))
178 .collect()
179}