Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add new features #300

Merged
merged 2 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
pub(crate) mod app_version;
pub(crate) mod mining;
// pub(crate) mod mining;
pub(crate) mod networks;
pub(crate) mod preferences;
pub(crate) mod query;
pub(crate) mod tx;
pub(crate) mod wallets;
pub(crate) mod web_logs;
pub(crate) mod user_preferences;

//pub use app_version::*;
4 changes: 2 additions & 2 deletions src-tauri/src/commands/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ pub async fn coin_transfer(
};

let mut config = get_cfg()?;
inject_private_key_to_cfg(&mut config)?;
let mut sender = Sender::from_app_cfg(&config, None, legacy).await?;
inject_private_key_to_cfg(&mut config, _sender)?;
let mut sender = Sender::from_app_cfg(&config, Some(_sender.to_string()), legacy).await?;
sender
.transfer(receiver_account, amount as f64, false)
.await?;
Expand Down
61 changes: 61 additions & 0 deletions src-tauri/src/commands/user_preferences.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::carpe_error::CarpeError;
use serde::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::{PathBuf};
use crate::configs::default_config_path;

#[derive(Serialize, Deserialize)]
pub struct UserPreferences {
accounts_list_sort_column: Option<String>,
accounts_list_sort_order: Option<String>,
}

// Utility function to retrieve the full path to the preferences file
fn get_preferences_path() -> Result<PathBuf, CarpeError> {
let app_dir_path = default_config_path(); // Assuming this returns a PathBuf or Path

// Check if the path exists, if not, return an error
if !app_dir_path.exists() {
return Err(CarpeError::misc("App directory not found"));
}

Ok(app_dir_path.join("user_preferences.json"))
}

#[tauri::command(async)]
pub async fn get_user_preferences() -> Result<UserPreferences, CarpeError> {
let file_path = get_preferences_path()?;
match File::open(&file_path) {
Ok(mut file) => {
let mut contents = String::new();
if let Err(e) = file.read_to_string(&mut contents) {
return Err(CarpeError::misc(&format!("Failed to read from preferences file: {}", e)));
}
serde_json::from_str(&contents).map_err(|e| CarpeError::misc(&format!("Failed to parse preferences: {}", e)))
},
Err(e) => Err(CarpeError::misc(&format!("Failed to open preferences file: {}", e))),
}
}

#[tauri::command(async)]
pub async fn set_accounts_list_preference(sort_column: String, sort_order: String) -> Result<(), CarpeError> {
let file_path = get_preferences_path()?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&file_path)
.map_err(|e| CarpeError::misc(&format!("Failed to open preferences file for writing: {}", e)))?;

let preferences = UserPreferences {
accounts_list_sort_column: Some(sort_column),
accounts_list_sort_order: Some(sort_order),
};

let serialized_data = serde_json::to_string_pretty(&preferences)
.map_err(|e| CarpeError::misc(&format!("Failed to serialize preferences: {}", e)))?;

file.write_all(serialized_data.as_bytes())
.map_err(|e| CarpeError::misc(&format!("Failed to write preferences file: {}", e)))
}
127 changes: 115 additions & 12 deletions src-tauri/src/commands/wallets.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
carpe_error::CarpeError,
commands::query,
configs::{self, default_legacy_account_path, get_cfg, get_client},
configs::{self, default_legacy_account_path, get_cfg, get_client, default_config_path},
configs_profile,
key_manager::{self, get_private_key, inject_private_key_to_cfg},
};
Expand All @@ -17,7 +17,10 @@ use libra_types::{
use libra_wallet::account_keys::{self, KeyChain};
use serde::{Deserialize, Serialize};
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{Write, prelude::*};
use std::fs::OpenOptions;
use std::path::{PathBuf, Path};
use serde_json;

#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct NewKeygen {
Expand Down Expand Up @@ -49,6 +52,7 @@ pub struct CarpeProfile {
on_chain: bool,
balance: SlowWalletBalance,
locale: Option<String>, // TODO: refactor, tauri now offers locale of the OS
note: Option<String>,
}

impl From<&Profile> for CarpeProfile {
Expand All @@ -63,6 +67,7 @@ impl From<&Profile> for CarpeProfile {
total: core_profile.balance.total,
}, // TODO: refactor upstream to have Clone
locale: core_profile.locale.clone(),
note: None,
}
}
}
Expand Down Expand Up @@ -123,6 +128,12 @@ pub async fn init_from_private_key(
Ok(core_profile.into())
}

#[derive(Serialize, Deserialize)]
struct Note {
account: String,
note: String,
}

/// read all accounts from profile
#[tauri::command(async)]
pub fn get_all_accounts() -> Result<Vec<CarpeProfile>, CarpeError> {
Expand All @@ -131,6 +142,93 @@ pub fn get_all_accounts() -> Result<Vec<CarpeProfile>, CarpeError> {
Ok(mapped)
}

/// read all accounts from profile plus notes
#[tauri::command]
pub fn get_all_accounts_with_notes() -> Result<Vec<CarpeProfile>, CarpeError> {
let mut accounts = get_all_accounts()?;
let _ = assign_notes_to_accounts(&mut accounts);
Ok(accounts)
}

fn notes_file_path() -> PathBuf {
let app_dir_path = default_config_path(); // Assuming this returns a PathBuf or Path
return app_dir_path.join("account_notes.json");
}


fn read_notes() -> Result<Vec<Note>, CarpeError> {
let file_path = notes_file_path();

// Check if the file exists before attempting to open it
if !Path::new(&file_path).exists() {
return Ok(vec![]); // Return an empty vector if the file does not exist
}

let mut file = match File::open(&file_path) {
Ok(f) => f,
Err(_e) => return Err(CarpeError::misc("Failed to open notes file")),
};

let mut contents = String::new();
if let Err(_e) = file.read_to_string(&mut contents) {
return Err(CarpeError::misc("Failed to read from notes file"));
}

match serde_json::from_str(&contents) {
Ok(notes) => Ok(notes),
Err(_e) => Err(CarpeError::misc("Failed to parse notes JSON")),
}
}

fn assign_notes_to_accounts(accounts: &mut Vec<CarpeProfile>) -> Result<(), CarpeError> {
let notes = read_notes()?;
for account in accounts.iter_mut() {
let note_option = notes.iter()
.find(|note| note.account == account.account.to_string().to_uppercase())
.map(|note| note.note.clone());
account.note = note_option;
}
Ok(())
}
#[tauri::command]
pub fn associate_note_with_account(account: String, note: String) -> Result<(), CarpeError> {
let file_path = notes_file_path();
let mut notes = read_notes().map_err(|_e| CarpeError::misc("Failed to read notes"))?;
let address = account.to_uppercase();

// Check if the account already exists and update the note if it does
let mut found = false;
for account_note in notes.iter_mut() {
if account_note.account == address {
account_note.note = note.clone();
found = true;
break;
}
}

// If the account does not exist, add a new note
if !found {
notes.push(Note { account: address, note });
}

let notes_json = serde_json::to_string(&notes)
.map_err(|_e| CarpeError::misc("Failed to serialize notes"))?;

let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open(&file_path)
.map_err(|_e| CarpeError::misc("Failed to open file for writing"))?;

file.write_all(notes_json.as_bytes())
.map_err(|_e| CarpeError::misc("Failed to write to file"))?;

Ok(())
}



/// read all accounts from profile
#[tauri::command(async)]
pub fn get_default_profile() -> Result<CarpeProfile, CarpeError> {
Expand All @@ -150,23 +248,22 @@ pub async fn refresh_accounts() -> Result<Vec<CarpeProfile>, CarpeError> {
map_get_balance(&mut app_cfg.user_profiles).await?;
app_cfg.save_file()?;

let mapped: Vec<CarpeProfile> = app_cfg.user_profiles.iter().map(|p| p.into()).collect();
let mut mapped: Vec<CarpeProfile> = app_cfg.user_profiles.iter().map(|p| p.into()).collect();
let _ = assign_notes_to_accounts(&mut mapped);
Ok(mapped)
}

#[tauri::command(async)]
/// check if this account is a slow wallet
pub async fn is_slow(account: AccountAddress) -> anyhow::Result<bool, CarpeError> {
let c = get_client()?;
println!("is slow");
let b = c
.view_ext(
"0x1::slow_wallet::is_slow",
None,
Some(account.to_hex_literal()),
)
.await?;
dbg!(&b);
match b.as_array().context("no bool found")?[0].as_bool() {
Some(b) => Ok(b),
None => Ok(false),
Expand Down Expand Up @@ -210,17 +307,23 @@ pub async fn get_originating_address(
}
}

/// Switch tx profiles, change 0L.toml to use selected account
/// Switch tx profiles, change libra.yaml to use selected account
#[tauri::command(async)]
// IMPORTANT: don't return the profile, since it has keys
pub async fn switch_profile(account: AccountAddress) -> Result<CarpeProfile, CarpeError> {
let mut app_cfg = get_cfg()?;
let p = app_cfg.get_profile(Some(account.to_string()))?;
app_cfg.workspace.set_default(p.nickname.clone());
app_cfg.save_file()?;
// TODO: gross, fix upstream `app_cfg.rs` to prevent the borrow issues here
let profile = app_cfg.get_profile(Some(account.to_string()))?;
Ok(profile.into())

// TODO: gross, fix upstream `app_cfg.rs` to prevent the borrow issues here
let mut profile = app_cfg.get_profile(Some(account.to_string()))?;

// Assign account note
let mut profiles: Vec<CarpeProfile> = vec![profile.into()];
assign_notes_to_accounts(&mut profiles)?;

Ok(profiles.into_iter().next().unwrap().into())
}

// remove all accounts which are being tracked.
Expand Down Expand Up @@ -266,11 +369,11 @@ async fn test_fetch_originating() {
}

#[tauri::command(async)]
pub async fn set_slow_wallet(legacy: bool) -> Result<(), CarpeError> {
pub async fn set_slow_wallet(legacy: bool, _sender: AccountAddress) -> Result<(), CarpeError> {
// NOTE: unsure Serde was catching all cases check serialization
let mut config = get_cfg()?;
inject_private_key_to_cfg(&mut config)?;
let mut sender = Sender::from_app_cfg(&config, None, legacy).await?;
inject_private_key_to_cfg(&mut config, _sender)?;
let mut sender = Sender::from_app_cfg(&config, Some(_sender.to_string()), legacy).await?;

let t = SetSlowTx {};
t.run(&mut sender).await?;
Expand Down
7 changes: 5 additions & 2 deletions src-tauri/src/key_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,12 @@ pub fn get_keypair(
/// insert the public key into the AppCfg temporarily so that we don't need
/// to prompt user for mnemonic.
// NOTE to future devs: DANGER: make sure this is never called in a flow that uses save_file(). The upstream prevents the key from serializing, but it should be guarded here as well.
pub fn inject_private_key_to_cfg(app_cfg_mut: &mut AppCfg) -> anyhow::Result<(), CarpeError> {
pub fn inject_private_key_to_cfg(
app_cfg_mut: &mut AppCfg,
account: AccountAddress,
) -> anyhow::Result<(), CarpeError> {
// gets the default profile
let profile = app_cfg_mut.get_profile_mut(None)?;
let profile = app_cfg_mut.get_profile_mut(Some(account.to_string()))?;
let pri_key = get_private_key(&profile.account).map_err(|e| CarpeError {
category: ErrorCat::Configs,
uid: E_KEY_NOT_REGISTERED,
Expand Down
22 changes: 14 additions & 8 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ async fn main() {
commands::wallets::get_default_profile,
commands::wallets::refresh_accounts,
commands::wallets::get_all_accounts,
commands::wallets::get_all_accounts_with_notes,
commands::wallets::associate_note_with_account,
commands::wallets::keygen,
commands::wallets::init_from_mnem,
commands::wallets::init_from_private_key,
Expand All @@ -114,14 +116,14 @@ async fn main() {
commands::tx::coin_transfer,
// claim_make_whole,
//////// Tower ////////
commands::query::get_onchain_tower_state,
commands::mining::miner_once,
commands::mining::start_backlog_sender_listener,
commands::mining::get_local_height,
commands::mining::get_epoch_rules,
commands::mining::submit_backlog,
commands::mining::get_last_local_proof,
commands::mining::debug_highest_proof_path,
// commands::query::get_onchain_tower_state,
// commands::mining::miner_once,
// commands::mining::start_backlog_sender_listener,
// commands::mining::get_local_height,
// commands::mining::get_epoch_rules,
// commands::mining::submit_backlog,
// commands::mining::get_last_local_proof,
// commands::mining::debug_highest_proof_path,
// submit_proof_zero,

//////// Preferences ////////
Expand All @@ -135,6 +137,10 @@ async fn main() {
commands::preferences::set_preferences_locale,
commands::preferences::get_miner_txs_cost,
commands::preferences::set_miner_txs_cost,

//////// User Preferences ////////
commands::user_preferences::get_user_preferences,
commands::user_preferences::set_accounts_list_preference,
///////// Debug ////////
commands::app_version::get_app_version,
commands::web_logs::log_this,
Expand Down
Loading
Loading