222 lines
8.4 KiB
Rust
222 lines
8.4 KiB
Rust
|
use std::error::Error;
|
||
|
use std::fs::File;
|
||
|
use chrono::{NaiveDateTime};
|
||
|
use crate::transaction::{Transaction, Input, Output};
|
||
|
|
||
|
pub mod account;
|
||
|
pub mod transaction;
|
||
|
use std::env;
|
||
|
use std::borrow::Borrow;
|
||
|
|
||
|
fn parse_bisq_transactions(account:&String) -> Result<Vec<Transaction>, Box<dyn Error>>{
|
||
|
// Build the CSV reader and iterate over each record.
|
||
|
let file = File::open(String::from(account) + "/bisq/transactions.csv")?;
|
||
|
let mut rdr = csv::Reader::from_reader(file);
|
||
|
let mut trade_transactions: Vec<Transaction>= vec!();
|
||
|
for result in rdr.records() {
|
||
|
// The iterator yields Result<StringRecord, Error>, so we check the
|
||
|
// error here..
|
||
|
let record = result?;
|
||
|
let details = &record[1];
|
||
|
let date = &record[0];
|
||
|
let date_time = NaiveDateTime::parse_from_str(date,"%b %e, %Y %I:%M:%S %p")?;
|
||
|
let amount:f64 = record[4].parse().unwrap();
|
||
|
|
||
|
if details.contains("Maker and tx fee") {
|
||
|
let mut transaction = Transaction::new(date_time, format!("Maker Fee"));
|
||
|
transaction.add_input(Input{
|
||
|
source: String::from("Assets:Trading"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from("Expenses:MakerFee"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_comment(record[2].to_string());
|
||
|
trade_transactions.push(transaction);
|
||
|
}
|
||
|
|
||
|
if details.contains("Taker and tx fee") {
|
||
|
let mut transaction = Transaction::new(date_time, format!("Taker Fee"));
|
||
|
transaction.add_input(Input{
|
||
|
source: String::from("Assets:Trading"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from("Expenses:TakerFee"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_comment(record[2].to_string());
|
||
|
trade_transactions.push(transaction);
|
||
|
}
|
||
|
|
||
|
if details.contains("Multisig deposit") {
|
||
|
let mut transaction = Transaction::new(date_time, format!("Multisig Deposit"));
|
||
|
transaction.add_input(Input{
|
||
|
source: String::from("Assets:Trading"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from("Expenses:TradingDeposit"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_comment(record[2].to_string());
|
||
|
trade_transactions.push(transaction);
|
||
|
}
|
||
|
|
||
|
if details.contains("Multisig payout") {
|
||
|
let mut transaction = Transaction::new(date_time, format!("Multisig Payout"));
|
||
|
transaction.add_input(Input{
|
||
|
source: String::from("Expenses:TradingDeposit"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from("Assets:Trading"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_comment(record[2].to_string());
|
||
|
trade_transactions.push(transaction);
|
||
|
}
|
||
|
|
||
|
if details.contains("Withdrawn from wallet") {
|
||
|
let mut transaction = Transaction::new(date_time, format!("Widthdrawal from Bisq Trading Wallet"));
|
||
|
transaction.add_input(Input{
|
||
|
source: String::from("Assets:Trading"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from("Assets:General"),
|
||
|
amount: ((amount.abs() * 100.0).round() / 100.0),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from("Expenses:TxFee"),
|
||
|
amount: ((amount.abs() - ((amount.abs() * 100.0).round() / 100.0)) * 100000000.0).round() / 100000000.0,
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_comment(record[2].to_string());
|
||
|
trade_transactions.push(transaction);
|
||
|
}
|
||
|
|
||
|
|
||
|
if details.contains("Received funds") {
|
||
|
let mut transaction = Transaction::new(date_time, format!("Deposit into Bisq Trading Wallet"));
|
||
|
transaction.add_input(Input{
|
||
|
source: String::from("Assets:General"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from("Assets:Trading"),
|
||
|
amount: amount.abs(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
transaction.add_comment(record[2].to_string());
|
||
|
trade_transactions.push(transaction);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return Ok(trade_transactions);
|
||
|
}
|
||
|
|
||
|
|
||
|
fn parse_bisq_trades(account:&String) -> Result<Vec<Transaction>, Box<dyn Error>>{
|
||
|
// Build the CSV reader and iterate over each record.
|
||
|
let file = File::open(String::from(account) + "/bisq/tradeHistory.csv")?;
|
||
|
let mut rdr = csv::Reader::from_reader(file);
|
||
|
let mut trade_transactions: Vec<Transaction>= vec!();
|
||
|
for result in rdr.records() {
|
||
|
// The iterator yields Result<StringRecord, Error>, so we check the
|
||
|
// error here..
|
||
|
let record = result?;
|
||
|
let id = &record[0];
|
||
|
let date = &record[1];
|
||
|
let date_time = NaiveDateTime::parse_from_str(date,"%b %e, %Y %I:%M:%S %p")?;
|
||
|
let bought = &record[4];
|
||
|
let sold = &record[5];
|
||
|
|
||
|
let mut transaction = Transaction::new(date_time, format!("Bisq Trade {}", id));
|
||
|
transaction.add_input(Input{
|
||
|
source: String::from("Assets:Trading"),
|
||
|
amount: sold.replace(" ZEC","").parse().unwrap(),
|
||
|
value: String::from("ZEC")
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from("Expenses:TradingDeposit"),
|
||
|
amount: bought.parse().unwrap(),
|
||
|
value: String::from("BTC")
|
||
|
});
|
||
|
trade_transactions.push(transaction);
|
||
|
|
||
|
}
|
||
|
return Ok(trade_transactions);
|
||
|
}
|
||
|
|
||
|
|
||
|
fn parse_donations(account:&String) -> Result<Vec<Transaction>, Box<dyn Error>>{
|
||
|
// Build the CSV reader and iterate over each record.
|
||
|
let file = File::open(String::from(account) + "/donations.csv")?;
|
||
|
let mut rdr = csv::Reader::from_reader(file);
|
||
|
let mut trade_transactions: Vec<Transaction>= vec!();
|
||
|
for result in rdr.records() {
|
||
|
// The iterator yields Result<StringRecord, Error>, so we check the
|
||
|
// error here..
|
||
|
let record = result?;
|
||
|
let date = &record[0];
|
||
|
let date_time = NaiveDateTime::parse_from_str(date,"%b %e, %Y %I:%M:%S %p")?;
|
||
|
let details = &record[1];
|
||
|
let amount = &record[2];
|
||
|
let denomination = &record[3];
|
||
|
let account = &record[4];
|
||
|
|
||
|
|
||
|
let mut transaction = Transaction::new(date_time, format!("{}", details));
|
||
|
transaction.add_input(Input{
|
||
|
source: String::from("Income:Donations"),
|
||
|
amount: amount.parse().unwrap(),
|
||
|
value: String::from(denomination),
|
||
|
});
|
||
|
transaction.add_output(Output{
|
||
|
destination: String::from(account),
|
||
|
amount: amount.parse().unwrap(),
|
||
|
value: String::from(denomination),
|
||
|
});
|
||
|
trade_transactions.push(transaction);
|
||
|
|
||
|
}
|
||
|
return Ok(trade_transactions);
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
|
||
|
let args: Vec<String> = env::args().collect();
|
||
|
let mut ledger = account::Account::new();
|
||
|
|
||
|
let donations = parse_donations(args[1].borrow()).unwrap();
|
||
|
for transaction in donations.iter() {
|
||
|
ledger.add_transaction(transaction.clone());
|
||
|
}
|
||
|
|
||
|
let trade_transactions = parse_bisq_trades(args[1].borrow()).unwrap();
|
||
|
for transaction in trade_transactions.iter() {
|
||
|
ledger.add_transaction(transaction.clone());
|
||
|
}
|
||
|
|
||
|
let bisq_transactions = parse_bisq_transactions(args[1].borrow()).unwrap();
|
||
|
for transaction in bisq_transactions.iter() {
|
||
|
ledger.add_transaction(transaction.clone());
|
||
|
}
|
||
|
|
||
|
ledger.transactions.sort_by_key(|transaction|transaction.date);
|
||
|
ledger.print();
|
||
|
}
|