multiversx_sc_snippets/interactor/
interactor_sender.rs

1use std::collections::HashMap;
2
3use crate::sdk::{data::transaction::Transaction, wallet::Wallet};
4use multiversx_sc_scenario::multiversx_sc::types::Address;
5use multiversx_sdk::data::account::Account;
6use multiversx_sdk::data::esdt::EsdtBalance;
7use multiversx_sdk::gateway::{
8    GatewayAsyncService, GetAccountEsdtTokensRequest, GetAccountRequest, GetAccountStorageRequest,
9};
10
11use crate::InteractorBase;
12
13/// A user account that can sign transactions (a pem is present).
14pub struct Sender {
15    pub address: Address,
16    pub hrp: String,
17    pub wallet: Wallet,
18    pub current_nonce: Option<u64>,
19}
20
21impl<GatewayProxy> InteractorBase<GatewayProxy>
22where
23    GatewayProxy: GatewayAsyncService,
24{
25    pub async fn recall_nonce(&self, address: &Address) -> u64 {
26        let account = self
27            .proxy
28            .request(GetAccountRequest::new(&address.to_bech32(self.get_hrp())))
29            .await
30            .expect("failed to retrieve account nonce");
31
32        account.nonce
33    }
34
35    pub async fn get_account(&self, address: &Address) -> Account {
36        self.proxy
37            .request(GetAccountRequest::new(&address.to_bech32(self.get_hrp())))
38            .await
39            .expect("failed to retrieve account")
40    }
41
42    pub async fn get_account_storage(&self, address: &Address) -> HashMap<String, String> {
43        self.proxy
44            .request(GetAccountStorageRequest::new(
45                &address.to_bech32(self.get_hrp()),
46            ))
47            .await
48            .expect("failed to retrieve account")
49    }
50
51    pub async fn get_account_esdt(&self, address: &Address) -> HashMap<String, EsdtBalance> {
52        self.proxy
53            .request(GetAccountEsdtTokensRequest::new(
54                &address.to_bech32(self.get_hrp()),
55            ))
56            .await
57            .expect("failed to retrieve account")
58    }
59
60    /// Updates:
61    /// - the transaction with the nonce read from the network
62    /// - the sender's current_nonce
63    pub(crate) async fn set_tx_nonce_update_sender(
64        &mut self,
65        sender_address: &Address,
66        transaction: &mut Transaction,
67    ) {
68        // read
69        let sender = self
70            .sender_map
71            .get(sender_address)
72            .expect("the wallet that was supposed to sign is not registered");
73
74        // recall
75        let nonce = self.recall_nonce(&sender.address).await;
76        println!("sender's recalled nonce: {nonce}");
77
78        // set tx nonce
79        transaction.nonce = nonce;
80        println!("-- tx nonce: {}", transaction.nonce);
81
82        // update
83        let sender = self
84            .sender_map
85            .get_mut(sender_address)
86            .expect("the wallet that was supposed to sign is not registered");
87        sender.current_nonce = Some(nonce + 1);
88    }
89
90    pub(crate) fn sign_tx(&self, sender_address: &Address, transaction: &mut Transaction) {
91        // read
92        let sender = self
93            .sender_map
94            .get(sender_address)
95            .expect("the wallet that was supposed to sign is not registered");
96
97        // sign
98        let signature = sender.wallet.sign_tx(transaction);
99        transaction.signature = Some(hex::encode(signature));
100    }
101}