dharitri_sc_snippets/
account_tool.rs

1use crate::sdk_core::data::dcdt::DcdtBalance;
2use dharitri_chain_scenario_format::interpret_trait::IntoRaw;
3use dharitri_sc_scenario::{
4    imports::Bech32Address,
5    scenario_model::{Account, BytesKey, BytesValue, Scenario, SetStateStep, Step},
6};
7use dharitri_sdk::gateway::{GatewayAsyncService, SetStateAccount};
8use dharitri_sdk::gateway::{
9    GetAccountDcdtRolesRequest, GetAccountDcdtTokensRequest, GetAccountRequest,
10    GetAccountStorageRequest,
11};
12use std::collections::{BTreeMap, HashMap};
13
14/// Called directly from CLI, from `sc-meta`.
15///
16/// Retrieves an account data via the API,
17/// then formats it as a scenario set state step.
18pub async fn print_account_as_scenario_set_state<GatewayProxy: GatewayAsyncService>(
19    gateway_proxy: GatewayProxy,
20    address_bech32_string: String,
21) {
22    let address = Bech32Address::from_bech32_string(address_bech32_string);
23    let (_, set_state) = retrieve_account_as_scenario_set_state(&gateway_proxy, &address).await;
24    let scenario = build_scenario(set_state);
25    println!("{}", scenario.into_raw().to_json_string());
26}
27
28fn build_scenario(set_state: SetStateStep) -> Scenario {
29    Scenario {
30        name: None,
31        comment: None,
32        check_gas: None,
33        steps: vec![Step::SetState(set_state)],
34    }
35}
36
37pub async fn retrieve_account_as_scenario_set_state<GatewayProxy: GatewayAsyncService>(
38    api: &GatewayProxy,
39    bech32_address: &Bech32Address,
40) -> (SetStateAccount, SetStateStep) {
41    let address = bech32_address.as_address();
42    let sdk_account = api.request(GetAccountRequest::new(address)).await.unwrap();
43
44    let account_dcdt = api
45        .request(GetAccountDcdtTokensRequest::new(address))
46        .await
47        .unwrap_or_else(|err| {
48            eprintln!("failed to retrieve DCDT tokens for address {bech32_address}: {err}");
49            HashMap::new()
50        });
51    let account_dcdt_roles = api
52        .request(GetAccountDcdtRolesRequest::new(address))
53        .await
54        .unwrap_or_else(|err| {
55            eprintln!("failed to retrieve DCDT roles for address {bech32_address}: {err}");
56            HashMap::new()
57        });
58    let account_storage = api
59        .request(GetAccountStorageRequest::new(address))
60        .await
61        .unwrap_or_else(|err| {
62            panic!("failed to retrieve storage for address {bech32_address}: {err}")
63        });
64
65    let account_state = set_account(
66        sdk_account.clone(),
67        account_storage.clone(),
68        account_dcdt,
69        account_dcdt_roles,
70    );
71
72    let set_state_account = SetStateAccount::from(sdk_account).with_storage(account_storage);
73    let set_state_step = SetStateStep::new();
74    (
75        set_state_account,
76        set_state_step.put_account(bech32_address, account_state),
77    )
78}
79
80fn set_account(
81    account: crate::sdk::data::account::Account,
82    account_storage: HashMap<String, String>,
83    account_dcdt: HashMap<String, DcdtBalance>,
84    account_dcdt_roles: HashMap<String, Vec<String>>,
85) -> Account {
86    let mut account_state = Account::new()
87        .nonce(account.nonce)
88        .balance(account.balance.as_str())
89        .code(BytesValue::from_hex(&account.code));
90    account_state.username = Some(format!("str:{}", account.username.as_str()).into());
91    account_state.storage = convert_storage(account_storage);
92
93    for (_, dcdt_balance) in account_dcdt.iter() {
94        let token_id_expr = format!("str:{}", dcdt_balance.token_identifier);
95        account_state =
96            account_state.dcdt_balance(token_id_expr.as_str(), dcdt_balance.balance.as_str());
97    }
98
99    for (token_id, dcdt_roles) in account_dcdt_roles {
100        let token_id_expr = format!("str:{token_id}");
101        account_state = account_state.dcdt_roles(token_id_expr.as_str(), dcdt_roles);
102    }
103
104    account_state
105}
106
107fn convert_storage(account_storage: HashMap<String, String>) -> BTreeMap<BytesKey, BytesValue> {
108    account_storage
109        .into_iter()
110        .filter(|(k, _)| !k.starts_with("4e554d424154"))
111        .map(|(k, v)| (BytesKey::from_hex(&k), BytesValue::from_hex(&v)))
112        .collect()
113}