extraction and parsing for balances, draft version
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
parent
63e35a4120
commit
dc20ba936a
@ -5,7 +5,7 @@ use subxt::utils::H256;
|
||||
use subxt::config::substrate::DigestItem;
|
||||
|
||||
use crate::{
|
||||
types::{ActionLevel, EraInfo, CasperExtrinsicDetails},
|
||||
types::{SystemAccount, ActionLevel, EraInfo, CasperExtrinsicDetails},
|
||||
};
|
||||
|
||||
use subxt::utils::AccountId32;
|
||||
@ -30,6 +30,9 @@ pub enum Action {
|
||||
NewAccount(String),
|
||||
NewAddressBookRecord(String, String),
|
||||
|
||||
BalanceRequest([u8; 32], bool),
|
||||
BalanceResponse([u8; 32], SystemAccount),
|
||||
|
||||
RenameAccount(String),
|
||||
RenameAddressBookRecord(String),
|
||||
UpdateAccountName(String),
|
||||
|
@ -107,6 +107,9 @@ impl App {
|
||||
for component in self.components.iter_mut() {
|
||||
component.register_action_handler(self.action_tx.clone())?;
|
||||
}
|
||||
for component in self.components.iter_mut() {
|
||||
component.register_network_handler(self.network_tx.clone())?;
|
||||
}
|
||||
for component in self.components.iter_mut() {
|
||||
component.register_config_handler(self.config.clone())?;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use ratatui::{
|
||||
Frame,
|
||||
};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use crate::{palette, action::Action, config::Config, tui::Event};
|
||||
|
||||
@ -17,6 +18,11 @@ pub mod wallet;
|
||||
pub mod empty;
|
||||
|
||||
pub trait Component {
|
||||
fn register_network_handler(&mut self, tx: Sender<Action>) -> Result<()> {
|
||||
let _ = tx;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
|
||||
let _ = tx;
|
||||
Ok(())
|
||||
|
@ -23,24 +23,35 @@ use subxt::{
|
||||
},
|
||||
};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use super::{PartialComponent, Component, CurrentTab};
|
||||
use crate::casper::CasperConfig;
|
||||
use crate::types::ActionLevel;
|
||||
use crate::types::{SystemAccount, ActionLevel};
|
||||
use crate::{
|
||||
action::Action,
|
||||
config::Config,
|
||||
palette::StylePalette,
|
||||
};
|
||||
|
||||
struct AccountInfo {
|
||||
name: String,
|
||||
address: String,
|
||||
account_id: [u8; 32],
|
||||
seed: String,
|
||||
pair_signer: PairSigner<CasperConfig, Pair>,
|
||||
}
|
||||
|
||||
pub struct Accounts {
|
||||
is_active: bool,
|
||||
wallet_keys_file: PathBuf,
|
||||
action_tx: Option<UnboundedSender<Action>>,
|
||||
network_tx: Option<Sender<Action>>,
|
||||
wallet_keys_file: PathBuf,
|
||||
palette: StylePalette,
|
||||
scroll_state: ScrollbarState,
|
||||
table_state: TableState,
|
||||
wallet_keys: Vec<(String, String, String, PairSigner<CasperConfig, Pair>)>,
|
||||
wallet_keys: Vec<AccountInfo>,
|
||||
balances: std::collections::HashMap<[u8; 32], SystemAccount>,
|
||||
}
|
||||
|
||||
impl Default for Accounts {
|
||||
@ -55,16 +66,25 @@ impl Accounts {
|
||||
is_active: false,
|
||||
wallet_keys_file: Default::default(),
|
||||
action_tx: None,
|
||||
network_tx: None,
|
||||
scroll_state: ScrollbarState::new(0),
|
||||
table_state: TableState::new(),
|
||||
wallet_keys: Vec::new(),
|
||||
balances: Default::default(),
|
||||
palette: StylePalette::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn send_balance_request(&mut self, account_id: [u8; 32], remove: bool) {
|
||||
if let Some(action_tx) = &self.network_tx {
|
||||
let _ = action_tx.send(Action::BalanceRequest(account_id, remove));
|
||||
}
|
||||
}
|
||||
|
||||
fn create_new_account(&mut self, name: String) {
|
||||
let (pair, seed) = Pair::generate();
|
||||
let secret_seed = hex::encode(seed);
|
||||
let account_id = pair.public().0;
|
||||
let pair_signer = PairSigner::<CasperConfig, Pair>::new(pair);
|
||||
let address = AccountId32::from(seed.clone())
|
||||
.to_ss58check_with_version(Ss58AddressFormat::custom(1996));
|
||||
@ -76,14 +96,21 @@ impl Accounts {
|
||||
));
|
||||
}
|
||||
|
||||
self.wallet_keys.push((name, address, secret_seed, pair_signer));
|
||||
self.send_balance_request(account_id, false);
|
||||
self.wallet_keys.push(AccountInfo {
|
||||
name,
|
||||
address,
|
||||
account_id,
|
||||
seed: secret_seed,
|
||||
pair_signer,
|
||||
});
|
||||
self.last_row();
|
||||
self.save_to_file();
|
||||
}
|
||||
|
||||
fn rename_account(&mut self, new_name: String) {
|
||||
if let Some(index) = self.table_state.selected() {
|
||||
let old_name = self.wallet_keys[index].0.clone();
|
||||
let old_name = self.wallet_keys[index].name.clone();
|
||||
|
||||
if let Some(action_tx) = &self.action_tx {
|
||||
let _ = action_tx.send(Action::WalletLog(
|
||||
@ -92,7 +119,7 @@ impl Accounts {
|
||||
));
|
||||
}
|
||||
|
||||
self.wallet_keys[index].0 = new_name;
|
||||
self.wallet_keys[index].name = new_name;
|
||||
self.save_to_file();
|
||||
|
||||
}
|
||||
@ -102,7 +129,7 @@ impl Accounts {
|
||||
if let Some(index) = self.table_state.selected() {
|
||||
if let Some(action_tx) = &self.action_tx {
|
||||
let _ = action_tx.send(Action::RenameAccount(
|
||||
self.wallet_keys[index].0.clone()
|
||||
self.wallet_keys[index].name.clone()
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -134,13 +161,14 @@ impl Accounts {
|
||||
if let Some(index) = self.table_state.selected() {
|
||||
if self.wallet_keys.len() > 1 {
|
||||
let wallet = self.wallet_keys.remove(index);
|
||||
self.send_balance_request(wallet.account_id, true);
|
||||
self.previous_row();
|
||||
self.save_to_file();
|
||||
|
||||
if let Some(action_tx) = &self.action_tx {
|
||||
let _ = action_tx.send(Action::WalletLog(
|
||||
format!("wallet `{}` with public address {} removed",
|
||||
&wallet.0, &wallet.1),
|
||||
&wallet.name, &wallet.address),
|
||||
ActionLevel::Warn,
|
||||
));
|
||||
}
|
||||
@ -151,7 +179,7 @@ impl Accounts {
|
||||
fn save_to_file(&mut self) {
|
||||
let mut file = File::create(&self.wallet_keys_file).unwrap();
|
||||
for wallet in self.wallet_keys.iter() {
|
||||
writeln!(file, "{}:0x{}", wallet.0, &wallet.2).unwrap();
|
||||
writeln!(file, "{}:0x{}", wallet.name, &wallet.seed).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,11 +201,19 @@ impl Accounts {
|
||||
.expect("stored seed is valid length; qed");
|
||||
|
||||
let pair = Pair::from_seed(&seed);
|
||||
let address = AccountId32::from(pair.public().0)
|
||||
let account_id = pair.public().0;
|
||||
let address = AccountId32::from(account_id)
|
||||
.to_ss58check_with_version(Ss58AddressFormat::custom(1996));
|
||||
let pair_signer = PairSigner::<CasperConfig, Pair>::new(pair);
|
||||
|
||||
self.wallet_keys.push((wallet_name.to_string(), address, wallet_key.to_string(), pair_signer));
|
||||
self.send_balance_request(account_id, false);
|
||||
self.wallet_keys.push(AccountInfo {
|
||||
name: wallet_name.to_string(),
|
||||
account_id,
|
||||
address,
|
||||
seed: wallet_key.to_string(),
|
||||
pair_signer,
|
||||
});
|
||||
}
|
||||
if let Some(action_tx) = &self.action_tx {
|
||||
let _ = action_tx.send(Action::WalletLog(
|
||||
@ -220,6 +256,7 @@ impl Accounts {
|
||||
};
|
||||
|
||||
let secret_seed = hex::encode(seed);
|
||||
let account_id = pair.public().0;
|
||||
let address = AccountId32::from(pair.public().0)
|
||||
.to_ss58check_with_version(Ss58AddressFormat::custom(1996));
|
||||
let pair_signer = PairSigner::<CasperConfig, Pair>::new(pair);
|
||||
@ -227,7 +264,14 @@ impl Accounts {
|
||||
let mut new_file = File::create(file_path)?;
|
||||
writeln!(new_file, "ghostie:0x{}", &secret_seed)?;
|
||||
|
||||
self.wallet_keys.push(("ghostie".to_string(), address, secret_seed, pair_signer));
|
||||
self.send_balance_request(account_id, false);
|
||||
self.wallet_keys.push(AccountInfo {
|
||||
name: "ghostie".to_string(),
|
||||
address,
|
||||
account_id,
|
||||
seed: secret_seed,
|
||||
pair_signer,
|
||||
});
|
||||
}
|
||||
};
|
||||
self.table_state.select(Some(0));
|
||||
@ -238,8 +282,10 @@ impl Accounts {
|
||||
|
||||
fn send_wallet_change(&mut self, index: usize) {
|
||||
if let Some(action_tx) = &self.action_tx {
|
||||
let (_, _, _, pair) = &self.wallet_keys[index];
|
||||
let _ = action_tx.send(Action::UsedAccount(pair.account_id().clone()));
|
||||
let _ = action_tx.send(Action::UsedAccount(self.wallet_keys[index]
|
||||
.pair_signer
|
||||
.account_id()
|
||||
.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,6 +333,11 @@ impl Accounts {
|
||||
self.table_state.select(Some(i));
|
||||
self.scroll_state = self.scroll_state.position(i);
|
||||
}
|
||||
|
||||
fn prepare_u128(&self, value: u128, after: usize, ticker: Option<&str>) -> String {
|
||||
let value = value as f64 / 10f64.powi(18);
|
||||
format!("{:.after$}{}", value, ticker.unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialComponent for Accounts {
|
||||
@ -299,7 +350,11 @@ impl PartialComponent for Accounts {
|
||||
}
|
||||
|
||||
impl Component for Accounts {
|
||||
// TODO network_tx is needed here NOT action_tx
|
||||
fn register_network_handler(&mut self, tx: Sender<Action>) -> Result<()> {
|
||||
self.network_tx = Some(tx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
|
||||
self.action_tx = Some(tx);
|
||||
Ok(())
|
||||
@ -328,6 +383,9 @@ impl Component for Accounts {
|
||||
match action {
|
||||
Action::NewAccount(name) => self.create_new_account(name),
|
||||
Action::UpdateAccountName(new_name) => self.rename_account(new_name),
|
||||
Action::BalanceResponse(account_id, balance) => {
|
||||
let _ = self.balances.insert(account_id, balance);
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
Ok(None)
|
||||
@ -355,15 +413,21 @@ impl Component for Accounts {
|
||||
let table = Table::new(
|
||||
self.wallet_keys
|
||||
.iter()
|
||||
.map(|info| Row::new(vec![
|
||||
Cell::from(Text::from(info.0.clone()).alignment(Alignment::Left)),
|
||||
Cell::from(Text::from(info.1.clone()).alignment(Alignment::Center)),
|
||||
Cell::from(Text::from("31 CSPR".to_string()).alignment(Alignment::Right)),
|
||||
])),
|
||||
.map(|info| {
|
||||
let balance = self.balances
|
||||
.get(&info.account_id)
|
||||
.map(|b| b.free)
|
||||
.unwrap_or_default();
|
||||
Row::new(vec![
|
||||
Cell::from(Text::from(info.name.clone()).alignment(Alignment::Left)),
|
||||
Cell::from(Text::from(info.address.clone()).alignment(Alignment::Center)),
|
||||
Cell::from(Text::from(self.prepare_u128(balance, 2, Some(" CSPR"))).alignment(Alignment::Right)),
|
||||
])
|
||||
}),
|
||||
[
|
||||
Constraint::Min(5),
|
||||
Constraint::Max(51),
|
||||
Constraint::Min(10),
|
||||
Constraint::Min(11),
|
||||
],
|
||||
)
|
||||
.highlight_style(self.palette.create_highlight_style())
|
||||
|
@ -5,6 +5,9 @@ use ratatui::{
|
||||
Frame,
|
||||
};
|
||||
|
||||
use std::sync::mpsc::Sender;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
mod balance;
|
||||
mod transfer;
|
||||
mod address_book;
|
||||
@ -17,7 +20,6 @@ mod add_address_book_record;
|
||||
mod rename_address_book_record;
|
||||
|
||||
use balance::Balance;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use transfer::Transfer;
|
||||
use address_book::AddressBook;
|
||||
use add_account::AddAccount;
|
||||
@ -94,6 +96,13 @@ impl Wallet {
|
||||
}
|
||||
|
||||
impl Component for Wallet {
|
||||
fn register_network_handler(&mut self, tx: Sender<Action>) -> Result<()> {
|
||||
for component in self.components.iter_mut() {
|
||||
component.register_network_handler(tx.clone())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
|
||||
for component in self.components.iter_mut() {
|
||||
component.register_action_handler(tx.clone())?;
|
||||
|
@ -27,6 +27,7 @@ pub struct Network {
|
||||
rpc_client: RpcClient,
|
||||
best_hash: Option<H256>,
|
||||
finalized_hash: Option<H256>,
|
||||
accounts_to_watch: std::collections::HashSet<[u8; 32]>
|
||||
}
|
||||
|
||||
impl Network {
|
||||
@ -43,6 +44,7 @@ impl Network {
|
||||
rpc_client,
|
||||
best_hash: None,
|
||||
finalized_hash: None,
|
||||
accounts_to_watch: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +52,9 @@ impl Network {
|
||||
match io_event {
|
||||
Action::NewBestHash(hash) => {
|
||||
self.best_hash = Some(hash);
|
||||
for account_id in self.accounts_to_watch.iter() {
|
||||
predefinded_calls::get_balance(&self.action_tx, &self.online_client_api, &account_id).await?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
Action::NewFinalizedHash(hash) => {
|
||||
@ -68,7 +73,16 @@ impl Network {
|
||||
|
||||
Action::GetExistentialDeposit => predefinded_calls::get_existential_deposit(&self.action_tx, &self.online_client_api).await,
|
||||
Action::GetTotalIssuance => predefinded_calls::get_total_issuance(&self.action_tx, &self.online_client_api).await,
|
||||
//Action::UsedAccount(account_id) => predefinded_calls::get_balance(&self.action_tx, &self.online_client_api, account_id).await,
|
||||
|
||||
Action::BalanceRequest(account_id, remove) => {
|
||||
if remove {
|
||||
let _ = self.accounts_to_watch.remove(&account_id);
|
||||
Ok(())
|
||||
} else {
|
||||
let _ = self.accounts_to_watch.insert(account_id);
|
||||
predefinded_calls::get_balance(&self.action_tx, &self.online_client_api, &account_id).await
|
||||
}
|
||||
}
|
||||
_ => Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
self,
|
||||
runtime_types::sp_consensus_slots,
|
||||
},
|
||||
types::EraInfo,
|
||||
types::{SystemAccount, EraInfo},
|
||||
CasperAccountId, CasperConfig
|
||||
};
|
||||
|
||||
@ -148,18 +148,33 @@ pub async fn get_existential_deposit(
|
||||
}
|
||||
|
||||
|
||||
//pub async fn get_balance(
|
||||
// action_tx: &UnboundedSender<Action>,
|
||||
// api: &OnlineClient<CasperConfig>,
|
||||
// account_id: subxt::utils::AccountId32,
|
||||
//) -> Result<()> {
|
||||
// let storage_key = casper_network::storage().system().account(&account_id);
|
||||
// let balance = api.storage()
|
||||
// .at_latest()
|
||||
// .await?
|
||||
// .fetch(&storage_key)
|
||||
// .await?;
|
||||
//
|
||||
// action_tx.send(Action::SetTotalIssuance(total_issuance))?;
|
||||
// Ok(())
|
||||
//}
|
||||
pub async fn get_balance(
|
||||
action_tx: &UnboundedSender<Action>,
|
||||
api: &OnlineClient<CasperConfig>,
|
||||
account_id: &[u8; 32],
|
||||
) -> Result<()> {
|
||||
let account_id_converted = subxt::utils::AccountId32::from(*account_id);
|
||||
let storage_key = casper_network::storage().system().account(account_id_converted);
|
||||
|
||||
let maybe_balance = api
|
||||
.storage()
|
||||
.at_latest()
|
||||
.await?
|
||||
.fetch(&storage_key)
|
||||
.await?;
|
||||
|
||||
let balance = match maybe_balance {
|
||||
Some(balance) => {
|
||||
SystemAccount {
|
||||
nonce: balance.nonce,
|
||||
free: balance.data.free,
|
||||
reserved: balance.data.reserved,
|
||||
frozen: balance.data.frozen,
|
||||
}
|
||||
},
|
||||
None => SystemAccount::default(),
|
||||
};
|
||||
|
||||
action_tx.send(Action::BalanceResponse(*account_id, balance))?;
|
||||
Ok(())
|
||||
}
|
||||
|
10
src/types/account.rs
Normal file
10
src/types/account.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use codec::Decode;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Decode)]
|
||||
pub struct SystemAccount {
|
||||
pub nonce: u32,
|
||||
pub free: u128,
|
||||
pub reserved: u128,
|
||||
pub frozen: u128,
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
mod era;
|
||||
mod extrinsics;
|
||||
mod log;
|
||||
mod account;
|
||||
|
||||
pub use extrinsics::CasperExtrinsicDetails;
|
||||
pub use era::EraInfo;
|
||||
pub use log::ActionLevel;
|
||||
pub use account::SystemAccount;
|
||||
|
Loading…
Reference in New Issue
Block a user