use crate::{
GAS_MULTIPLIER, Gas,
constants::Value,
state::{WithOverlay, accounts::Accounts},
};
use gear_common::GasMultiplier;
use gear_core::ids::ActorId;
use std::{collections::HashMap, thread::LocalKey};
thread_local! {
pub(super) static BANK_ACCOUNTS: WithOverlay<HashMap<ActorId, BankBalance>> = Default::default();
}
fn storage() -> &'static LocalKey<WithOverlay<HashMap<ActorId, BankBalance>>> {
&BANK_ACCOUNTS
}
#[derive(Default, Debug, Clone, Copy)]
pub(super) struct BankBalance {
pub(super) gas: Value,
pub(super) value: Value,
}
#[derive(Default, Debug)]
pub(crate) struct Bank;
impl Bank {
pub(crate) fn deposit_value(&self, id: ActorId, value: Value, keep_alive: bool) {
Accounts::decrease(id, value, keep_alive);
storage().with(|accs| {
accs.data_mut()
.entry(id)
.or_insert(BankBalance { gas: 0, value: 0 })
.value += value;
});
}
pub(crate) fn deposit_gas(&self, id: ActorId, gas: Gas, keep_alive: bool) {
let gas_value = GAS_MULTIPLIER.gas_to_value(gas);
Accounts::decrease(id, gas_value, keep_alive);
storage().with(|accs| {
accs.data_mut()
.entry(id)
.or_insert(BankBalance { gas: 0, value: 0 })
.gas += gas_value;
});
}
pub(crate) fn spend_gas(&self, id: ActorId, gas: Gas, multiplier: GasMultiplier<Value, Gas>) {
let gas_value = multiplier.gas_to_value(gas);
storage().with(|accs| {
accs.data_mut()
.get_mut(&id)
.unwrap_or_else(|| panic!("Bank::spend_gas: actor id {id:?} not found in bank"))
.gas -= gas_value;
});
}
pub(crate) fn withdraw_gas(
&self,
id: ActorId,
gas_left: Gas,
multiplier: GasMultiplier<Value, Gas>,
) {
let gas_left_value = multiplier.gas_to_value(gas_left);
storage().with(|accs| {
accs.data_mut()
.get_mut(&id)
.unwrap_or_else(|| panic!("Bank::spend_gas: actor id {id:?} not found in bank"))
.gas -= gas_left_value;
});
if !Accounts::can_deposit(id, gas_left_value) {
return;
}
Accounts::increase(id, gas_left_value);
}
pub(crate) fn transfer_value(&self, from: ActorId, to: ActorId, value: Value) {
if value == 0 {
return;
}
storage().with(|accs| {
accs.data_mut()
.get_mut(&from)
.unwrap_or_else(|| {
panic!("Bank::transfer_value: actor id {from:?} not found in bank")
})
.value -= value;
});
if !Accounts::can_deposit(to, value) {
return;
}
Accounts::increase(to, value);
}
pub(crate) fn transfer_locked_value(&mut self, from: ActorId, to: ActorId, value: Value) {
if value == 0 {
return;
}
storage().with(|accs| {
accs.data_mut()
.get_mut(&from)
.unwrap_or_else(|| {
panic!("Bank::transfer_value: actor id {from:?} not found in bank")
})
.value -= value;
});
storage().with(|accs| {
accs.data_mut()
.entry(to)
.or_insert(BankBalance { gas: 0, value: 0 })
.value += value;
});
}
pub(crate) fn clear(&self) {
storage().with(|accs| {
accs.data_mut().clear();
});
}
}