multiversx_chain_vm/host/context/
tx_cache_balance_util.rs1use multiversx_chain_core::EGLD_000000_TOKEN_IDENTIFIER;
2use num_bigint::BigUint;
3
4use crate::{
5 blockchain::state::EsdtInstanceMetadata, host::context::TxPanic,
6 system_sc::is_system_sc_address, types::VMAddress,
7};
8
9use super::TxCache;
10
11impl TxCache {
12 pub fn subtract_egld_balance(
13 &self,
14 address: &VMAddress,
15 call_value: &BigUint,
16 ) -> Result<(), TxPanic> {
17 self.with_account_mut(address, |account| {
18 if call_value > &account.egld_balance {
19 return Err(TxPanic::vm_error("failed transfer (insufficient funds)"));
20 }
21 account.egld_balance -= call_value;
22 Ok(())
23 })
24 }
25
26 pub fn subtract_tx_gas(&self, address: &VMAddress, gas_limit: u64, gas_price: u64) {
27 self.with_account_mut(address, |account| {
28 let gas_cost = BigUint::from(gas_limit) * BigUint::from(gas_price);
29 assert!(
30 account.egld_balance >= gas_cost,
31 "Not enough balance to pay gas upfront"
32 );
33 account.egld_balance -= &gas_cost;
34 });
35 }
36
37 pub fn increase_egld_balance(&self, address: &VMAddress, amount: &BigUint) {
38 self.with_account_mut(address, |account| {
39 account.egld_balance += amount;
40 });
41 }
42
43 pub fn subtract_esdt_balance(
44 &self,
45 address: &VMAddress,
46 esdt_token_identifier: &[u8],
47 nonce: u64,
48 value: &BigUint,
49 ) -> Result<EsdtInstanceMetadata, TxPanic> {
50 self.with_account_mut(address, |account| {
51 let esdt_data_map = &mut account.esdt;
52 let esdt_data = esdt_data_map
53 .get_mut_by_identifier(esdt_token_identifier)
54 .ok_or_else(err_insufficient_funds)?;
55
56 let esdt_instances = &mut esdt_data.instances;
57 let esdt_instance = esdt_instances
58 .get_mut_by_nonce(nonce)
59 .ok_or_else(err_insufficient_funds)?;
60
61 let esdt_balance = &mut esdt_instance.balance;
62 if &*esdt_balance < value {
63 return Err(err_insufficient_funds());
64 }
65
66 *esdt_balance -= value;
67
68 Ok(esdt_instance.metadata.clone())
69 })
70 }
71
72 pub fn increase_esdt_balance(
73 &self,
74 address: &VMAddress,
75 esdt_token_identifier: &[u8],
76 nonce: u64,
77 value: &BigUint,
78 esdt_metadata: EsdtInstanceMetadata,
79 ) {
80 self.with_account_mut(address, |account| {
81 account.esdt.increase_balance(
82 esdt_token_identifier.to_vec(),
83 nonce,
84 value,
85 esdt_metadata,
86 );
87 });
88 }
89
90 pub fn transfer_egld_balance(
91 &self,
92 from: &VMAddress,
93 to: &VMAddress,
94 value: &BigUint,
95 ) -> Result<(), TxPanic> {
96 if !is_system_sc_address(from) {
97 self.subtract_egld_balance(from, value)?;
98 }
99 if !is_system_sc_address(to) {
100 self.increase_egld_balance(to, value);
101 }
102 Ok(())
103 }
104
105 pub fn transfer_esdt_balance(
106 &self,
107 from: &VMAddress,
108 to: &VMAddress,
109 esdt_token_identifier: &[u8],
110 nonce: u64,
111 value: &BigUint,
112 ) -> Result<(), TxPanic> {
113 if esdt_token_identifier == EGLD_000000_TOKEN_IDENTIFIER.as_bytes() {
114 return self.transfer_egld_balance(from, to, value);
115 }
116
117 if !is_system_sc_address(from) && !is_system_sc_address(to) {
118 let metadata = self.subtract_esdt_balance(from, esdt_token_identifier, nonce, value)?;
119 self.increase_esdt_balance(to, esdt_token_identifier, nonce, value, metadata);
120 }
121 Ok(())
122 }
123}
124
125fn err_insufficient_funds() -> TxPanic {
126 TxPanic::vm_error("insufficient funds")
127}