multiversx_sc_scenario/scenario/model/account_data/
account_check.rs

1use multiversx_sc::codec::{top_encode_to_vec_u8_or_panic, TopEncode};
2
3use crate::{
4    scenario::model::{
5        BigUintValue, BytesKey, BytesValue, CheckEsdt, CheckEsdtInstances, CheckEsdtMap,
6        CheckEsdtMapContents, CheckStorage, CheckStorageDetails, CheckValue, U64Value,
7    },
8    scenario_format::{
9        interpret_trait::{InterpretableFrom, InterpreterContext, IntoRaw},
10        serde_raw::CheckAccountRaw,
11    },
12    scenario_model::CheckEsdtData,
13};
14use std::collections::BTreeMap;
15
16#[derive(Debug, Default, Clone)]
17pub struct CheckAccount {
18    pub comment: Option<String>,
19    pub nonce: CheckValue<U64Value>,
20    pub balance: CheckValue<BigUintValue>,
21    pub esdt: CheckEsdtMap,
22    pub username: CheckValue<BytesValue>,
23    pub storage: CheckStorage,
24    pub code: CheckValue<BytesValue>,
25    pub code_metadata: CheckValue<BytesValue>,
26    pub owner: CheckValue<BytesValue>, // WARNING! Not currently checked. TODO: implement check
27    pub developer_rewards: CheckValue<BigUintValue>,
28    pub async_call_data: CheckValue<BytesValue>,
29}
30
31impl CheckAccount {
32    pub fn new() -> Self {
33        Self::default()
34    }
35
36    pub fn nonce<V>(mut self, nonce: V) -> Self
37    where
38        U64Value: InterpretableFrom<V>,
39    {
40        self.nonce = CheckValue::Equal(U64Value::interpret_from(
41            nonce,
42            &InterpreterContext::default(),
43        ));
44        self
45    }
46
47    pub fn balance<V>(mut self, balance_expr: V) -> Self
48    where
49        BigUintValue: InterpretableFrom<V>,
50    {
51        self.balance = CheckValue::Equal(BigUintValue::interpret_from(
52            balance_expr,
53            &InterpreterContext::default(),
54        ));
55        self
56    }
57
58    pub fn code<V>(mut self, code_expr: V) -> Self
59    where
60        BytesValue: InterpretableFrom<V>,
61    {
62        self.code = CheckValue::Equal(BytesValue::interpret_from(
63            code_expr,
64            &InterpreterContext::default(),
65        ));
66        self
67    }
68
69    pub fn code_metadata<V>(mut self, code_metadata_expr: V) -> Self
70    where
71        BytesValue: InterpretableFrom<V>,
72    {
73        self.code_metadata = CheckValue::Equal(BytesValue::interpret_from(
74            code_metadata_expr,
75            &InterpreterContext::default(),
76        ));
77        self
78    }
79
80    pub fn esdt_balance<K, V>(mut self, token_id_expr: K, balance_expr: V) -> Self
81    where
82        BytesKey: From<K>,
83        BigUintValue: From<V>,
84    {
85        let token_id = BytesKey::from(token_id_expr);
86        let balance = BigUintValue::from(balance_expr);
87
88        match &mut self.esdt {
89            CheckEsdtMap::Unspecified | CheckEsdtMap::Star => {
90                let mut new_esdt_map = BTreeMap::new();
91                let _ = new_esdt_map.insert(token_id, CheckEsdt::Short(balance));
92
93                let new_check_esdt_map = CheckEsdtMapContents {
94                    contents: new_esdt_map,
95                    other_esdts_allowed: true,
96                };
97
98                self.esdt = CheckEsdtMap::Equal(new_check_esdt_map);
99            }
100            CheckEsdtMap::Equal(check_esdt_map) => {
101                if check_esdt_map.contents.contains_key(&token_id) {
102                    let prev_entry = check_esdt_map.contents.get_mut(&token_id).unwrap();
103                    match prev_entry {
104                        CheckEsdt::Short(prev_balance_check) => *prev_balance_check = balance,
105                        CheckEsdt::Full(prev_esdt_check) => match prev_esdt_check.instances {
106                            CheckEsdtInstances::Star => todo!(),
107                            CheckEsdtInstances::Equal(_) => todo!(),
108                        },
109                    }
110                }
111            }
112        }
113
114        self
115    }
116
117    pub fn esdt_nft_balance_and_attributes<K, N, V, T>(
118        mut self,
119        token_id_expr: K,
120        nonce_expr: N,
121        balance_expr: V,
122        attributes_expr: Option<T>,
123    ) -> Self
124    where
125        BytesKey: From<K>,
126        U64Value: From<N>,
127        BigUintValue: From<V>,
128        T: TopEncode,
129    {
130        let token_id = BytesKey::from(token_id_expr);
131
132        if let CheckEsdtMap::Unspecified = &self.esdt {
133            let mut check_esdt = CheckEsdt::Full(CheckEsdtData::default());
134
135            if let Some(attributes_expr) = attributes_expr {
136                check_esdt.add_balance_and_attributes_check(
137                    nonce_expr,
138                    balance_expr,
139                    top_encode_to_vec_u8_or_panic(&attributes_expr),
140                );
141            } else {
142                check_esdt.add_balance_and_attributes_check(
143                    nonce_expr,
144                    balance_expr,
145                    Vec::<u8>::new(),
146                );
147            }
148
149            let mut new_esdt_map = BTreeMap::new();
150            let _ = new_esdt_map.insert(token_id, check_esdt);
151
152            let new_check_esdt_map = CheckEsdtMapContents {
153                contents: new_esdt_map,
154                other_esdts_allowed: true,
155            };
156
157            self.esdt = CheckEsdtMap::Equal(new_check_esdt_map);
158        }
159
160        self
161    }
162
163    pub fn check_storage(mut self, key: &str, value: &str) -> Self {
164        let mut details = match self.storage {
165            CheckStorage::Star => CheckStorageDetails::default(),
166            CheckStorage::Equal(details) => details,
167        };
168        details.storages.insert(
169            BytesKey::interpret_from(key, &InterpreterContext::default()),
170            CheckValue::Equal(BytesValue::interpret_from(
171                value,
172                &InterpreterContext::default(),
173            )),
174        );
175        self.storage = CheckStorage::Equal(details);
176        self
177    }
178}
179
180impl InterpretableFrom<Box<CheckAccountRaw>> for CheckAccount {
181    fn interpret_from(from: Box<CheckAccountRaw>, context: &InterpreterContext) -> Self {
182        CheckAccount {
183            comment: from.comment,
184            nonce: CheckValue::<U64Value>::interpret_from(from.nonce, context),
185            balance: CheckValue::<BigUintValue>::interpret_from(from.balance, context),
186            esdt: CheckEsdtMap::interpret_from(from.esdt, context),
187            username: CheckValue::<BytesValue>::interpret_from(from.username, context),
188            storage: CheckStorage::interpret_from(from.storage, context),
189            code: CheckValue::<BytesValue>::interpret_from(from.code, context),
190            code_metadata: CheckValue::<BytesValue>::interpret_from(from.code_metadata, context),
191            owner: CheckValue::<BytesValue>::interpret_from(from.owner, context),
192            developer_rewards: CheckValue::<BigUintValue>::interpret_from(
193                from.developer_rewards,
194                context,
195            ),
196            async_call_data: CheckValue::<BytesValue>::interpret_from(
197                from.async_call_data,
198                context,
199            ),
200        }
201    }
202}
203
204impl IntoRaw<CheckAccountRaw> for CheckAccount {
205    fn into_raw(self) -> CheckAccountRaw {
206        CheckAccountRaw {
207            comment: self.comment,
208            nonce: self.nonce.into_raw(),
209            balance: self.balance.into_raw(),
210            esdt: self.esdt.into_raw(),
211            username: self.username.into_raw(),
212            storage: self.storage.into_raw(),
213            code: self.code.into_raw_explicit(), // TODO: convert back to into_raw after VM CI upgrade
214            code_metadata: self.code_metadata.into_raw(),
215            owner: self.owner.into_raw_explicit(), // TODO: convert back to into_raw after VM CI upgrade
216            developer_rewards: self.developer_rewards.into_raw(),
217            async_call_data: self.async_call_data.into_raw(),
218        }
219    }
220}