From 6da2a61a1e6781548aac181179953412443a2572 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Sat, 15 Jul 2023 21:42:51 +1000 Subject: [PATCH 1/4] loader: Hide HSD screen --- FireWalletLite/Loader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FireWalletLite/Loader.cs b/FireWalletLite/Loader.cs index d587a65..350c0f7 100644 --- a/FireWalletLite/Loader.cs +++ b/FireWalletLite/Loader.cs @@ -8,7 +8,7 @@ namespace FireWalletLite { #region Constants MainForm mainForm = new MainForm(); - bool hideScreen = false; + bool hideScreen = true; Process HSDProcess; #endregion From 1e90ddd6f9c1f41208fc7039206ebe9f72389d5a Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Sat, 15 Jul 2023 21:54:16 +1000 Subject: [PATCH 2/4] main: Added TX history --- FireWalletLite/MainForm.Designer.cs | 13 -- FireWalletLite/MainForm.cs | 239 ++++++++++++++++++++++++++-- 2 files changed, 227 insertions(+), 25 deletions(-) diff --git a/FireWalletLite/MainForm.Designer.cs b/FireWalletLite/MainForm.Designer.cs index d06aa03..971e929 100644 --- a/FireWalletLite/MainForm.Designer.cs +++ b/FireWalletLite/MainForm.Designer.cs @@ -44,7 +44,6 @@ LoginButton = new Button(); panelPortfolio = new Panel(); groupBoxHistory = new GroupBox(); - panelHistory = new Panel(); buttonRenew = new Button(); groupBoxDomains = new GroupBox(); panelDomainList = new Panel(); @@ -59,7 +58,6 @@ ((System.ComponentModel.ISupportInitialize)pictureBoxLogo).BeginInit(); groupBoxLogin.SuspendLayout(); panelPortfolio.SuspendLayout(); - groupBoxHistory.SuspendLayout(); groupBoxDomains.SuspendLayout(); panelNav.SuspendLayout(); groupBoxAccount.SuspendLayout(); @@ -195,7 +193,6 @@ // // groupBoxHistory // - groupBoxHistory.Controls.Add(panelHistory); groupBoxHistory.Location = new Point(102, 226); groupBoxHistory.Name = "groupBoxHistory"; groupBoxHistory.Size = new Size(299, 293); @@ -203,14 +200,6 @@ groupBoxHistory.TabStop = false; groupBoxHistory.Text = "History"; // - // panelHistory - // - panelHistory.Dock = DockStyle.Fill; - panelHistory.Location = new Point(3, 19); - panelHistory.Name = "panelHistory"; - panelHistory.Size = new Size(293, 271); - panelHistory.TabIndex = 0; - // // buttonRenew // buttonRenew.Enabled = false; @@ -331,7 +320,6 @@ groupBoxLogin.ResumeLayout(false); groupBoxLogin.PerformLayout(); panelPortfolio.ResumeLayout(false); - groupBoxHistory.ResumeLayout(false); groupBoxDomains.ResumeLayout(false); panelNav.ResumeLayout(false); groupBoxAccount.ResumeLayout(false); @@ -365,6 +353,5 @@ private ToolStripStatusLabel LabelSyncWarning; private ToolStripDropDownButton DropDownHelp; private GroupBox groupBoxHistory; - private Panel panelHistory; } } \ No newline at end of file diff --git a/FireWalletLite/MainForm.cs b/FireWalletLite/MainForm.cs index 524055f..1388b65 100644 --- a/FireWalletLite/MainForm.cs +++ b/FireWalletLite/MainForm.cs @@ -1,12 +1,15 @@ using System.Diagnostics; +using System.DirectoryServices.ActiveDirectory; using FireWallet; using Newtonsoft.Json.Linq; +using static QRCoder.PayloadGenerator; namespace FireWalletLite { public partial class MainForm : Form { #region Constants and Config + // Directory to store files including logs, theme and hsd node public string dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName.Trim().Replace(" ", "") + "\\"; @@ -22,18 +25,25 @@ namespace FireWalletLite public Dictionary HelpLinks = new Dictionary() { { "Discord", "https://l.woodburn.au/discord" }, - { "Separator" ,""}, + { "Separator", "" }, { "Github", "https://github.com/nathanwoodburn/FireWalletLite" } }; + // Min Confirmations for transactions to be considered valid + public int MinConfirmations = 1; + #endregion + #region Variables + public Dictionary Theme { get; set; } HttpClient httpClient = new HttpClient(); Decimal Balance { get; set; } public String Account = "primary"; public String Password { get; set; } + #endregion + public MainForm() { InitializeComponent(); @@ -46,6 +56,7 @@ namespace FireWalletLite DropDownHelp.DropDownItems.Add(new ToolStripSeparator()); continue; } + ToolStripMenuItem tsmi = new ToolStripMenuItem(link.Key); tsmi.Click += (s, e) => { @@ -58,9 +69,13 @@ namespace FireWalletLite }; DropDownHelp.DropDownItems.Add(tsmi); } - DropDownHelp.Margin = new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - 20, 0, 0, 0); + + DropDownHelp.Margin = + new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - 20, 0, 0, 0); } + #region Theming + private void UpdateTheme() { // Check if file exists @@ -68,6 +83,7 @@ namespace FireWalletLite { CreateConfig(dir); } + if (!File.Exists(dir + "theme.txt")) { CreateConfig(dir); @@ -82,9 +98,11 @@ namespace FireWalletLite string[] split = line.Split(':'); Theme.Add(split[0].Trim(), split[1].Trim()); } + sr.Dispose(); - if (!Theme.ContainsKey("background") || !Theme.ContainsKey("background-alt") || !Theme.ContainsKey("foreground") || !Theme.ContainsKey("foreground-alt")) + if (!Theme.ContainsKey("background") || !Theme.ContainsKey("background-alt") || + !Theme.ContainsKey("foreground") || !Theme.ContainsKey("foreground-alt")) { AddLog("Theme file is missing key"); return; @@ -102,9 +120,11 @@ namespace FireWalletLite { ThemeControl(c); } + this.Width = Screen.PrimaryScreen.Bounds.Width / 5 * 3; this.Height = Screen.PrimaryScreen.Bounds.Height / 5 * 3; } + public void ThemeControl(Control c) { if (c.GetType() == typeof(GroupBox) || c.GetType() == typeof(Panel)) @@ -115,21 +135,26 @@ namespace FireWalletLite ThemeControl(sub); } } + if (c.GetType() == typeof(TextBox) || c.GetType() == typeof(Button) - || c.GetType() == typeof(ComboBox) || c.GetType() == typeof(StatusStrip) || c.GetType() == typeof(ToolStrip) - || c.GetType() == typeof(NumericUpDown)) + || c.GetType() == typeof(ComboBox) || + c.GetType() == typeof(StatusStrip) || c.GetType() == typeof(ToolStrip) + || c.GetType() == typeof(NumericUpDown)) { c.ForeColor = ColorTranslator.FromHtml(Theme["foreground-alt"]); c.BackColor = ColorTranslator.FromHtml(Theme["background-alt"]); } + if (c.GetType() == typeof(Panel)) c.Dock = DockStyle.Fill; } + private void CreateConfig(string dir) { if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } + StreamWriter sw = new StreamWriter(dir + "theme.txt"); sw.WriteLine("background: #000000"); sw.WriteLine("foreground: #8e05c2"); @@ -139,11 +164,15 @@ namespace FireWalletLite sw.Dispose(); AddLog("Created theme file"); } + #endregion + #region Logging + public void AddLog(string message) { - if (message.Contains("Get Error: No connection could be made because the target machine actively refused it")) return; + if (message.Contains( + "Get Error: No connection could be made because the target machine actively refused it")) return; // If file size is over 1MB, rename it to old.log.txt if (File.Exists(dir + "log.txt")) @@ -151,7 +180,8 @@ namespace FireWalletLite FileInfo fi = new FileInfo(dir + "log.txt"); if (fi.Length > 1000000) { - if (File.Exists(dir + "old.log.txt")) File.Delete(dir + "old.log.txt"); // Delete old log file as it is super old + if (File.Exists(dir + "old.log.txt")) + File.Delete(dir + "old.log.txt"); // Delete old log file as it is super old File.Move(dir + "log.txt", dir + "old.log.txt"); } } @@ -160,8 +190,11 @@ namespace FireWalletLite sw.WriteLine(DateTime.Now.ToString() + ": " + message); sw.Dispose(); } + #endregion + bool testedLogin = false; + private void timerUpdate_Tick(object sender, EventArgs e) { if (SyncLabel.Text != "Status: Node Not Connected") @@ -174,10 +207,12 @@ namespace FireWalletLite this.Show(); } } + NodeStatus(); } #region API + private async void NodeStatus() { if (await APIGet("", false) == "Error") @@ -196,15 +231,20 @@ namespace FireWalletLite if (progress < 1) { LabelSyncWarning.Visible = true; - DropDownHelp.Margin = new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - LabelSyncWarning.Width - 20, 0, 0, 0); + DropDownHelp.Margin = + new Padding( + statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - LabelSyncWarning.Width - 20, + 0, 0, 0); } else { LabelSyncWarning.Visible = false; - DropDownHelp.Margin = new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - 20, 0, 0, 0); + DropDownHelp.Margin = new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - 20, + 0, 0, 0); } } + // Try to keep wallet unlocked string path = "wallet/" + Account + "/unlock"; string content = "{\"passphrase\": \"" + Password + "\",\"timeout\": 60}"; @@ -215,6 +255,7 @@ namespace FireWalletLite await APIPost(path, true, content); } + private async Task UpdateBalance() { string response = await APIGet("wallet/" + Account + "/balance?account=default", true); @@ -222,7 +263,8 @@ namespace FireWalletLite JObject resp = JObject.Parse(response); - decimal available = (Convert.ToDecimal(resp["unconfirmed"].ToString()) - Convert.ToDecimal(resp["lockedUnconfirmed"].ToString())) / 1000000; + decimal available = (Convert.ToDecimal(resp["unconfirmed"].ToString()) - + Convert.ToDecimal(resp["lockedUnconfirmed"].ToString())) / 1000000; decimal locked = Convert.ToDecimal(resp["lockedUnconfirmed"].ToString()) / 1000000; available = decimal.Round(available, 2); locked = decimal.Round(locked, 2); @@ -233,12 +275,14 @@ namespace FireWalletLite UpdateDomains(); } + public async Task APIPost(string path, bool wallet, string content) { if (content == "{\"passphrase\": \"\",\"timeout\": 60}") { return ""; } + string ip = "127.0.0.1"; string port = "1203"; if (wallet) port = port + "9"; @@ -256,6 +300,7 @@ namespace FireWalletLite AddLog(await resp.Content.ReadAsStringAsync()); return "Error"; } + return await resp.Content.ReadAsStringAsync(); } @@ -266,9 +311,11 @@ namespace FireWalletLite { Environment.Exit(91); } + return "Error"; } } + public async Task APIGet(string path, bool wallet) { string ip = "127.0.0.1"; @@ -278,7 +325,8 @@ namespace FireWalletLite else port = port + "7"; try { - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://" + ip + ":" + port + "/" + path); + HttpRequestMessage request = + new HttpRequestMessage(HttpMethod.Get, "http://" + ip + ":" + port + "/" + path); // Add API key to header //request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes("x:" + key))); // Send request and log response @@ -289,6 +337,7 @@ namespace FireWalletLite AddLog(await response.Content.ReadAsStringAsync()); return "Error"; } + return await response.Content.ReadAsStringAsync(); } @@ -300,19 +349,24 @@ namespace FireWalletLite { Environment.Exit(91); } + return "Error"; } } + public async Task ValidAddress(string address) { - string output = await APIPost("", false, "{\"method\": \"validateaddress\",\"params\": [ \"" + address + "\" ]}"); + string output = await APIPost("", false, + "{\"method\": \"validateaddress\",\"params\": [ \"" + address + "\" ]}"); JObject APIresp = JObject.Parse(output); JObject result = JObject.Parse(APIresp["result"].ToString()); if (result["isvalid"].ToString() == "True") return true; else return false; } + public string[] Domains { get; set; } public string[] DomainsRenewable { get; set; } + private async void UpdateDomains() { string response = await APIGet("wallet/" + Account + "/name?own=true", true); @@ -362,6 +416,7 @@ namespace FireWalletLite AddLog("Domain " + Domains[i] + " does not have stats"); continue; } + Label expiry = new Label(); JObject stats = JObject.Parse(name["stats"].ToString()); if (stats.ContainsKey("daysUntilExpire")) @@ -403,9 +458,11 @@ namespace FireWalletLite domainForm.Show(); }); } + panelDomainList.Controls.Add(domainTMP); i++; } + labelDomains.Text = "Domains: " + names.Count; if (renewable > 0) @@ -420,6 +477,163 @@ namespace FireWalletLite AddLog(ex.Message); } } + + private async Task GetTXHistory() + { + // Check how many TX there are + string APIresponse = await APIGet("wallet/" + Account, true); + JObject wallet = JObject.Parse(APIresponse); + if (!wallet.ContainsKey("balance")) + { + AddLog("GetInfo Error"); + AddLog(APIresponse); + return; + } + + JObject balance = JObject.Parse(wallet["balance"].ToString()); + int TotalTX = Convert.ToInt32(balance["tx"].ToString()); + int toGet = 10; + + if (toGet > TotalTX) toGet = TotalTX; + int toSkip = TotalTX - toGet; + + // GET TXs + APIresponse = await APIPost("", true, + "{\"method\": \"listtransactions\",\"params\": [\"default\"," + toGet + "," + toSkip + "]}"); + + if (APIresponse == "Error") + { + AddLog("GetInfo Error"); + return; + } + + JObject TXGET = JObject.Parse(APIresponse); + + // Check for error + if (TXGET["error"].ToString() != "") + { + AddLog("GetInfo Error"); + AddLog(APIresponse); + return; + } + + JArray txs = JArray.Parse(TXGET["result"].ToString()); + if (toGet > txs.Count) + toGet = txs.Count; // In case there are less TXs than expected (usually happens when the get TX's fails) + Control[] tmpControls = new Control[toGet]; + for (int i = 0; i < toGet; i++) + { + + // Get last tx + JObject tx = + JObject.Parse(await APIGet("wallet/" + Account + "/tx/" + txs[toGet - i - 1]["txid"].ToString(), + true)); + + string hash = tx["hash"].ToString(); + string date = tx["mdate"].ToString(); + + date = DateTime.Parse(date).ToShortDateString(); + + + + + Panel tmpPanel = new Panel(); + tmpPanel.Width = groupBoxHistory.Width - SystemInformation.VerticalScrollBarWidth - 20; + tmpPanel.Height = 50; + tmpPanel.Location = new Point(5, (i * 55)); + tmpPanel.BorderStyle = BorderStyle.FixedSingle; + tmpPanel.BackColor = ColorTranslator.FromHtml(Theme["background-alt"]); + tmpPanel.ForeColor = ColorTranslator.FromHtml(Theme["foreground-alt"]); + tmpPanel.Controls.Add( + new Label() + { + Text = "Date: " + date, + Location = new Point(10, 5) + } + ); + int confirmations = Convert.ToInt32(tx["confirmations"].ToString()); + if (confirmations < MinConfirmations) + { + Label txPending = new Label() + { + Text = "Pending", + Location = new Point(100, 5) + }; + tmpPanel.Controls.Add(txPending); + txPending.BringToFront(); + } + + + Label labelHash = new Label() + { + Text = "Hash: " + hash.Substring(0, 10) + "..." + hash.Substring(hash.Length - 10), + AutoSize = true, + Location = new Point(10, 25) + }; + + tmpPanel.Controls.Add(labelHash); + + JArray inputs = JArray.Parse(tx["inputs"].ToString()); + JArray outputs = JArray.Parse(tx["outputs"].ToString()); + int inputCount = inputs.Count; + int outputCount = outputs.Count; + + decimal costHNS = decimal.Parse(txs[toGet - i - 1]["amount"].ToString()); + string cost = ""; + if (costHNS < 0) + { + cost = "Spent: " + (costHNS * -1).ToString() + " HNS"; + } + else if (costHNS > 0) + { + cost = "Received: " + costHNS.ToString() + " HNS"; + } + + Label labelInputOutput = new Label() + { + Text = "Inputs: " + inputCount + " Outputs: " + outputCount + "\n" + cost, + AutoSize = true, + Location = new Point(300, 5) + }; + tmpPanel.Controls.Add(labelInputOutput); + + + tmpPanel.Click += (sender, e) => + { + ProcessStartInfo psi = new ProcessStartInfo + { + FileName = TXExplorer + hash, + UseShellExecute = true + }; + Process.Start(psi); + }; + foreach (Control c in tmpPanel.Controls) + { + c.Click += (sender, e) => + { + ProcessStartInfo psi = new ProcessStartInfo + { + FileName = TXExplorer + hash, + UseShellExecute = true + }; + Process.Start(psi); + }; + } + + tmpControls[i] = tmpPanel; + + + } + + groupBoxHistory.Controls.Clear(); + Panel txPanel = new Panel(); + txPanel.Width = groupBoxHistory.Width - SystemInformation.VerticalScrollBarWidth; + txPanel.Controls.AddRange(tmpControls); + txPanel.AutoScroll = true; + txPanel.Dock = DockStyle.Fill; + groupBoxHistory.Controls.Add(txPanel); + } + #endregion private void MainForm_Load(object sender, EventArgs e) { @@ -469,6 +683,7 @@ namespace FireWalletLite } groupBoxDomains.Width = this.Width - groupBoxDomains.Left - 20; await UpdateBalance(); + await GetTXHistory(); panelLogin.Hide(); panelNav.Dock = DockStyle.Left; panelPortfolio.Show(); From 50f50cab0685545c8f1f67f779a91c9874a9dc49 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Sat, 15 Jul 2023 21:59:56 +1000 Subject: [PATCH 3/4] main: Removed input and output count of TXs --- FireWalletLite/MainForm.cs | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/FireWalletLite/MainForm.cs b/FireWalletLite/MainForm.cs index 1388b65..ce8b14d 100644 --- a/FireWalletLite/MainForm.cs +++ b/FireWalletLite/MainForm.cs @@ -572,32 +572,6 @@ namespace FireWalletLite }; tmpPanel.Controls.Add(labelHash); - - JArray inputs = JArray.Parse(tx["inputs"].ToString()); - JArray outputs = JArray.Parse(tx["outputs"].ToString()); - int inputCount = inputs.Count; - int outputCount = outputs.Count; - - decimal costHNS = decimal.Parse(txs[toGet - i - 1]["amount"].ToString()); - string cost = ""; - if (costHNS < 0) - { - cost = "Spent: " + (costHNS * -1).ToString() + " HNS"; - } - else if (costHNS > 0) - { - cost = "Received: " + costHNS.ToString() + " HNS"; - } - - Label labelInputOutput = new Label() - { - Text = "Inputs: " + inputCount + " Outputs: " + outputCount + "\n" + cost, - AutoSize = true, - Location = new Point(300, 5) - }; - tmpPanel.Controls.Add(labelInputOutput); - - tmpPanel.Click += (sender, e) => { ProcessStartInfo psi = new ProcessStartInfo @@ -624,7 +598,6 @@ namespace FireWalletLite } - groupBoxHistory.Controls.Clear(); Panel txPanel = new Panel(); txPanel.Width = groupBoxHistory.Width - SystemInformation.VerticalScrollBarWidth; From af7ce12443b655bc8850b54093e9e2720faab991 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Sat, 15 Jul 2023 22:17:49 +1000 Subject: [PATCH 4/4] main: Code cleanup --- FireWalletLite/DomainForm.cs | 535 ++++++----- FireWalletLite/FirstLoginForm.cs | 103 +- FireWalletLite/Loader.cs | 442 ++++----- FireWalletLite/MainForm.cs | 1523 +++++++++++++++--------------- FireWalletLite/NotifyForm.cs | 479 +++++----- FireWalletLite/Program.cs | 25 +- FireWalletLite/ReceiveForm.cs | 67 +- FireWalletLite/SendForm.cs | 192 ++-- FireWalletLite/SplashScreen.cs | 174 ++-- 9 files changed, 1746 insertions(+), 1794 deletions(-) diff --git a/FireWalletLite/DomainForm.cs b/FireWalletLite/DomainForm.cs index ff2835d..3733b81 100644 --- a/FireWalletLite/DomainForm.cs +++ b/FireWalletLite/DomainForm.cs @@ -2,296 +2,295 @@ using FireWallet; using Newtonsoft.Json.Linq; -namespace FireWalletLite +namespace FireWalletLite; + +public partial class DomainForm : Form { - public partial class DomainForm : Form + private readonly string Domain; + private readonly MainForm Main; + + public DomainForm(MainForm main, string domain) { - private MainForm Main; - private string Domain; - public DomainForm(MainForm main, string domain) + InitializeComponent(); + Main = main; + Domain = domain; + Text = domain + "/"; + // Theme form + BackColor = ColorTranslator.FromHtml(main.Theme["background"]); + ForeColor = ColorTranslator.FromHtml(main.Theme["foreground"]); + foreach (Control control in Controls) main.ThemeControl(control); + labelName.Text = domain + "/"; + } + + private void buttonExplorer_Click(object sender, EventArgs e) + { + var psi = new ProcessStartInfo { - InitializeComponent(); - this.Main = main; - this.Domain = domain; - Text = domain + "/"; - // Theme form - BackColor = ColorTranslator.FromHtml(main.Theme["background"]); - ForeColor = ColorTranslator.FromHtml(main.Theme["foreground"]); - foreach (Control control in Controls) + FileName = Main.DomainExplorer + Domain, + UseShellExecute = true + }; + Process.Start(psi); + } + + private void DomainForm_Load(object sender, EventArgs e) + { + if (!File.Exists(Main.dir + "domains.json")) return; + + var domains = JArray.Parse(File.ReadAllText(Main.dir + "domains.json")); + foreach (JObject domain in domains) + if (domain["name"].ToString() == Domain) + if (domain.ContainsKey("status")) + switch (domain["status"].ToString()) + { + case "transferring": + buttonFinalize.Visible = true; + buttonCancel.Visible = true; + buttonTransfer.Visible = false; + textBoxTransferAddress.Visible = false; + break; + case "closed": + buttonCancel.Visible = false; + buttonFinalize.Visible = false; + break; + } + } + + private async void buttonRenew_Click(object sender, EventArgs e) + { + var content = "{\"method\": \"renew\", \"params\": [\"" + Domain + "\"]}"; + var response = await Main.APIPost("", true, content); + if (response == "Error") + { + var notify = new NotifyForm("Error renewing domain"); + notify.ShowDialog(); + notify.Dispose(); + return; + } + + var jObject = JObject.Parse(response); + if (jObject.ContainsKey("result")) + { + Main.AddLog(jObject["result"].ToString()); + var result = (JObject)jObject["result"]; + if (result.ContainsKey("txid")) { - main.ThemeControl(control); + var txid = result["txid"].ToString(); + var notify = new NotifyForm("Renewed domain", "Explorer", Main.TXExplorer + txid); + notify.ShowDialog(); + notify.Dispose(); } - labelName.Text = domain + "/"; - } - - private void buttonExplorer_Click(object sender, EventArgs e) - { - ProcessStartInfo psi = new ProcessStartInfo + else { - FileName = Main.DomainExplorer + Domain, - UseShellExecute = true - }; - Process.Start(psi); + var notify = new NotifyForm("Error renewing domain"); + notify.ShowDialog(); + notify.Dispose(); + } + } + else + { + var notify = new NotifyForm("Error renewing domain"); + notify.ShowDialog(); + notify.Dispose(); + Main.AddLog(jObject.ToString()); + } + } + + private async void buttonTransfer_Click(object sender, EventArgs e) + { + var address = textBoxTransferAddress.Text; + var valid = await Main.ValidAddress(address); + if (!valid) + { + var notify = new NotifyForm("Invalid address"); + notify.ShowDialog(); + notify.Dispose(); + return; } - private void DomainForm_Load(object sender, EventArgs e) + var path = "wallet/" + Main.Account + "/transfer"; + var content = "{\"passphrase\": \"" + Main.Password + "\", \"name\": \"" + Domain + + "\", \"broadcast\": true, \"sign\": true, \"address\": \"" + address + "\"}"; + var response = await Main.APIPost(path, true, content); + if (response == "Error") { - if (!File.Exists(Main.dir + "domains.json")) return; + var notify = new NotifyForm("Error transferring domain"); + notify.ShowDialog(); + notify.Dispose(); + return; + } - JArray domains = JArray.Parse(File.ReadAllText(Main.dir + "domains.json")); + var jObject = JObject.Parse(response); + if (jObject.ContainsKey("hash")) + { + var txid = jObject["hash"].ToString(); + var notify = new NotifyForm("Transferred domain", "Explorer", Main.TXExplorer + txid); + notify.ShowDialog(); + notify.Dispose(); + AddDomainInfo("transferring"); + } + else + { + var notify = new NotifyForm("Error transferring domain"); + notify.ShowDialog(); + notify.Dispose(); + } + } + + private void buttonFinalize_Click(object sender, EventArgs e) + { + var path = "wallet/" + Main.Account + "/finalize"; + var content = "{\"passphrase\": \"" + Main.Password + "\", \"name\": \"" + Domain + + "\", \"broadcast\": true, \"sign\": true}"; + var response = Main.APIPost(path, true, content).Result; + if (response == "Error") + { + var notify = new NotifyForm("Error finalizing transfer"); + notify.ShowDialog(); + notify.Dispose(); + return; + } + + var jObject = JObject.Parse(response); + if (jObject.ContainsKey("hash")) + { + var txid = jObject["hash"].ToString(); + var notify = new NotifyForm("Finalized domain", "Explorer", Main.TXExplorer + txid); + notify.ShowDialog(); + notify.Dispose(); + AddDomainInfo("closed"); + } + else + { + var notify = new NotifyForm("Error finalizing domain"); + notify.ShowDialog(); + notify.Dispose(); + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + var path = "wallet/" + Main.Account + "/cancel"; + var content = "{\"passphrase\": \"" + Main.Password + "\", \"name\": \"" + Domain + + "\", \"broadcast\": true, \"sign\": true}"; + var response = Main.APIPost(path, true, content).Result; + if (response == "Error") + { + var notify = new NotifyForm("Error cancelling transfer"); + notify.ShowDialog(); + notify.Dispose(); + return; + } + + var jObject = JObject.Parse(response); + if (jObject.ContainsKey("hash")) + { + var txid = jObject["hash"].ToString(); + var notify = new NotifyForm("Canceled transfer", "Explorer", Main.TXExplorer + txid); + notify.ShowDialog(); + notify.Dispose(); + AddDomainInfo("closed"); + } + else + { + var notify = new NotifyForm("Error cancelling transfer"); + notify.ShowDialog(); + notify.Dispose(); + } + } + + private void AddDomainInfo(string status) + { + if (File.Exists(Main.dir + "domains.json")) + { + var found = false; + var domains = JArray.Parse(File.ReadAllText(Main.dir + "domains.json")); foreach (JObject domain in domains) - { if (domain["name"].ToString() == Domain) { + found = true; if (domain.ContainsKey("status")) - { - switch (domain["status"].ToString()) - { - case "transferring": - buttonFinalize.Visible = true; - buttonCancel.Visible = true; - buttonTransfer.Visible = false; - textBoxTransferAddress.Visible = false; - break; - case "closed": - buttonCancel.Visible = false; - buttonFinalize.Visible = false; - break; - } - } - } - } - } - - private async void buttonRenew_Click(object sender, EventArgs e) - { - string content = "{\"method\": \"renew\", \"params\": [\"" + Domain + "\"]}"; - string response = await Main.APIPost("", true, content); - if (response == "Error") - { - NotifyForm notify = new NotifyForm("Error renewing domain"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - JObject jObject = JObject.Parse(response); - if (jObject.ContainsKey("result")) - { - Main.AddLog(jObject["result"].ToString()); - JObject result = (JObject)jObject["result"]; - if (result.ContainsKey("txid")) - { - string txid = result["txid"].ToString(); - NotifyForm notify = new NotifyForm("Renewed domain", "Explorer", Main.TXExplorer + txid); - notify.ShowDialog(); - notify.Dispose(); - } - else - { - NotifyForm notify = new NotifyForm("Error renewing domain"); - notify.ShowDialog(); - notify.Dispose(); - } - } - else - { - NotifyForm notify = new NotifyForm("Error renewing domain"); - notify.ShowDialog(); - notify.Dispose(); - Main.AddLog(jObject.ToString()); - } - } - - private async void buttonTransfer_Click(object sender, EventArgs e) - { - string address = textBoxTransferAddress.Text; - bool valid = await Main.ValidAddress(address); - if (!valid) - { - NotifyForm notify = new NotifyForm("Invalid address"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - string path = "wallet/" + Main.Account + "/transfer"; - string content = "{\"passphrase\": \"" + Main.Password + "\", \"name\": \"" + Domain + "\", \"broadcast\": true, \"sign\": true, \"address\": \"" + address + "\"}"; - string response = await Main.APIPost(path, true, content); - if (response == "Error") - { - NotifyForm notify = new NotifyForm("Error transferring domain"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - JObject jObject = JObject.Parse(response); - if (jObject.ContainsKey("hash")) - { - string txid = jObject["hash"].ToString(); - NotifyForm notify = new NotifyForm("Transferred domain", "Explorer", Main.TXExplorer + txid); - notify.ShowDialog(); - notify.Dispose(); - AddDomainInfo("transferring"); - } - else - { - NotifyForm notify = new NotifyForm("Error transferring domain"); - notify.ShowDialog(); - notify.Dispose(); - } - } - - private void buttonFinalize_Click(object sender, EventArgs e) - { - string path = "wallet/" + Main.Account + "/finalize"; - string content = "{\"passphrase\": \"" + Main.Password + "\", \"name\": \"" + Domain + "\", \"broadcast\": true, \"sign\": true}"; - string response = Main.APIPost(path, true, content).Result; - if (response == "Error") - { - NotifyForm notify = new NotifyForm("Error finalizing transfer"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - JObject jObject = JObject.Parse(response); - if (jObject.ContainsKey("hash")) - { - string txid = jObject["hash"].ToString(); - NotifyForm notify = new NotifyForm("Finalized domain", "Explorer", Main.TXExplorer + txid); - notify.ShowDialog(); - notify.Dispose(); - AddDomainInfo("closed"); - } - else - { - NotifyForm notify = new NotifyForm("Error finalizing domain"); - notify.ShowDialog(); - notify.Dispose(); - } - } - private void buttonCancel_Click(object sender, EventArgs e) - { - string path = "wallet/" + Main.Account + "/cancel"; - string content = "{\"passphrase\": \"" + Main.Password + "\", \"name\": \"" + Domain + "\", \"broadcast\": true, \"sign\": true}"; - string response = Main.APIPost(path, true, content).Result; - if (response == "Error") - { - NotifyForm notify = new NotifyForm("Error cancelling transfer"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - JObject jObject = JObject.Parse(response); - if (jObject.ContainsKey("hash")) - { - string txid = jObject["hash"].ToString(); - NotifyForm notify = new NotifyForm("Canceled transfer", "Explorer", Main.TXExplorer + txid); - notify.ShowDialog(); - notify.Dispose(); - AddDomainInfo("closed"); - } - else - { - NotifyForm notify = new NotifyForm("Error cancelling transfer"); - notify.ShowDialog(); - notify.Dispose(); - } - } - - private void AddDomainInfo(string status) - { - if (File.Exists(Main.dir + "domains.json")) - { - bool found = false; - JArray domains = JArray.Parse(File.ReadAllText(Main.dir + "domains.json")); - foreach (JObject domain in domains) - { - if (domain["name"].ToString() == Domain) - { - found = true; - if (domain.ContainsKey("status")) - { - domain["status"] = status; - } - else - { - domain.Add("status", status); - } - } + domain["status"] = status; + else + domain.Add("status", status); } - if (!found) - { - JObject domain = new JObject(); - domain["name"] = Domain; - domain["status"] = status; - domains.Add(domain); - } - File.WriteAllText(Main.dir + "domains.json", domains.ToString()); - } - else + if (!found) { - JArray domains = new JArray(); - JObject domain = new JObject(); + var domain = new JObject(); domain["name"] = Domain; domain["status"] = status; domains.Add(domain); - File.WriteAllText(Main.dir + "domains.json", domains.ToString()); } + + File.WriteAllText(Main.dir + "domains.json", domains.ToString()); } - - private async void buttonSign_Click(object sender, EventArgs e) + else { - if (buttonSign.Text == "Save") - { - SaveFileDialog saveFileDialog = new SaveFileDialog(); - saveFileDialog.Filter = "Text File|*.txt"; - saveFileDialog.Title = "Save Signature"; - if (saveFileDialog.ShowDialog() == DialogResult.OK) - { - JObject signature = new JObject(); - signature["domain"] = Domain; - signature["message"] = textBoxSignMessage.Text; - signature["signature"] = textBoxSignature.Text; - signature["time"] = DateTime.Now.ToString(); - File.WriteAllText(saveFileDialog.FileName, signature.ToString()); - } - - return; - } - if (textBoxSignMessage.Text == "") - { - NotifyForm notify = new NotifyForm("Enter a message to sign"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - string content = "{\"method\": \"signmessagewithname\", \"params\": [\"" + Domain + "\", \"" + textBoxSignMessage.Text + "\"]}"; - string response = await Main.APIPost("", true, content); - if (response == "Error") - { - NotifyForm notify = new NotifyForm("Error signing message"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - JObject jObject = JObject.Parse(response); - if (jObject.ContainsKey("result")) - { - textBoxSignature.Text = jObject["result"].ToString(); - buttonSign.Text = "Save"; - } - else - { - Main.AddLog(response); - NotifyForm notify = new NotifyForm("Error signing message"); - notify.ShowDialog(); - notify.Dispose(); - } - } - - private void textBoxSignMessage_TextChanged(object sender, EventArgs e) - { - buttonSign.Text = "Sign"; + var domains = new JArray(); + var domain = new JObject(); + domain["name"] = Domain; + domain["status"] = status; + domains.Add(domain); + File.WriteAllText(Main.dir + "domains.json", domains.ToString()); } } -} + + private async void buttonSign_Click(object sender, EventArgs e) + { + if (buttonSign.Text == "Save") + { + var saveFileDialog = new SaveFileDialog(); + saveFileDialog.Filter = "Text File|*.txt"; + saveFileDialog.Title = "Save Signature"; + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + var signature = new JObject(); + signature["domain"] = Domain; + signature["message"] = textBoxSignMessage.Text; + signature["signature"] = textBoxSignature.Text; + signature["time"] = DateTime.Now.ToString(); + File.WriteAllText(saveFileDialog.FileName, signature.ToString()); + } + + return; + } + + if (textBoxSignMessage.Text == "") + { + var notify = new NotifyForm("Enter a message to sign"); + notify.ShowDialog(); + notify.Dispose(); + return; + } + + var content = "{\"method\": \"signmessagewithname\", \"params\": [\"" + Domain + "\", \"" + + textBoxSignMessage.Text + "\"]}"; + var response = await Main.APIPost("", true, content); + if (response == "Error") + { + var notify = new NotifyForm("Error signing message"); + notify.ShowDialog(); + notify.Dispose(); + return; + } + + var jObject = JObject.Parse(response); + if (jObject.ContainsKey("result")) + { + textBoxSignature.Text = jObject["result"].ToString(); + buttonSign.Text = "Save"; + } + else + { + Main.AddLog(response); + var notify = new NotifyForm("Error signing message"); + notify.ShowDialog(); + notify.Dispose(); + } + } + + private void textBoxSignMessage_TextChanged(object sender, EventArgs e) + { + buttonSign.Text = "Sign"; + } +} \ No newline at end of file diff --git a/FireWalletLite/FirstLoginForm.cs b/FireWalletLite/FirstLoginForm.cs index 0443b16..13e87fc 100644 --- a/FireWalletLite/FirstLoginForm.cs +++ b/FireWalletLite/FirstLoginForm.cs @@ -1,59 +1,56 @@ using FireWallet; using Newtonsoft.Json.Linq; -namespace FireWalletLite +namespace FireWalletLite; + +public partial class FirstLoginForm : Form { - public partial class FirstLoginForm : Form + private readonly MainForm main; + private string seedPhrase; + + public FirstLoginForm(string seedPhrase, MainForm mainForm) { - String seedPhrase; - MainForm main; - public FirstLoginForm(string seedPhrase, MainForm mainForm) - { - InitializeComponent(); - this.seedPhrase = seedPhrase; - this.main = mainForm; - // Theme form - this.BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]); - this.ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]); - foreach (Control control in Controls) - { - mainForm.ThemeControl(control); - } - textBoxSeed.Text = seedPhrase; - } - - private async void Start_Click(object sender, EventArgs e) - { - if (textBoxPassword.Text.Length < 8) - { - NotifyForm notifyForm = new NotifyForm("Please choose a longer password!"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - return; - } - if (textBoxPassword.Text != textBoxPassword2.Text) - { - NotifyForm notifyForm = new NotifyForm("Passwords do not match!"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - return; - } - - // Encrypt wallet - string content = "{\"method\":\"encryptwallet\",\"params\":[\"" + textBoxPassword.Text + "\"]}"; - string response = await main.APIPost("",true,content); - main.AddLog("Encrypt wallet: " + response); - JObject jObject = JObject.Parse(response); - if (jObject["error"].ToString() != "") - { - NotifyForm notifyForm = new NotifyForm("Error encrypting wallet: " + jObject["error"].ToString()); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - return; - } else - { - this.Close(); - } - } + InitializeComponent(); + this.seedPhrase = seedPhrase; + main = mainForm; + // Theme form + BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]); + ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]); + foreach (Control control in Controls) mainForm.ThemeControl(control); + textBoxSeed.Text = seedPhrase; } -} + + private async void Start_Click(object sender, EventArgs e) + { + if (textBoxPassword.Text.Length < 8) + { + var notifyForm = new NotifyForm("Please choose a longer password!"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + return; + } + + if (textBoxPassword.Text != textBoxPassword2.Text) + { + var notifyForm = new NotifyForm("Passwords do not match!"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + return; + } + + // Encrypt wallet + var content = "{\"method\":\"encryptwallet\",\"params\":[\"" + textBoxPassword.Text + "\"]}"; + var response = await main.APIPost("", true, content); + main.AddLog("Encrypt wallet: " + response); + var jObject = JObject.Parse(response); + if (jObject["error"].ToString() != "") + { + var notifyForm = new NotifyForm("Error encrypting wallet: " + jObject["error"]); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + return; + } + + Close(); + } +} \ No newline at end of file diff --git a/FireWalletLite/Loader.cs b/FireWalletLite/Loader.cs index 350c0f7..9532dc5 100644 --- a/FireWalletLite/Loader.cs +++ b/FireWalletLite/Loader.cs @@ -2,237 +2,243 @@ using System.Diagnostics; using System.Text.RegularExpressions; using FireWallet; -namespace FireWalletLite +namespace FireWalletLite; + +public partial class Loader : Form { - public partial class Loader : Form + public Loader() { - #region Constants - MainForm mainForm = new MainForm(); - bool hideScreen = true; - Process HSDProcess; - #endregion + InitializeComponent(); - public Loader() + var splashScreen = new SplashScreen(false); + splashScreen.Show(); + Application.DoEvents(); + var start = DateTime.Now; + // Install and load node + var dir = mainForm.dir; + HSDProcess = new Process(); + if (!Directory.Exists(dir)) Environment.Exit(1); + var hsdPath = dir + "hsd\\bin\\hsd.exe"; + if (!Directory.Exists(dir + "hsd")) { - InitializeComponent(); + var repositoryUrl = "https://github.com/handshake-org/hsd.git"; + var destinationPath = dir + "hsd"; + CloneRepository(repositoryUrl, destinationPath); + } - SplashScreen splashScreen = new SplashScreen(false); - splashScreen.Show(); + // Start HSD + HSDProcess.StartInfo.RedirectStandardInput = true; + HSDProcess.StartInfo.RedirectStandardOutput = false; + HSDProcess.StartInfo.UseShellExecute = false; + HSDProcess.StartInfo.FileName = "node.exe"; + HSDProcess.StartInfo.Arguments = dir + "hsd\\bin\\hsd --agent=FireWallet --spv --prefix " + dir + "\\hsd_data"; + HSDProcess.StartInfo.CreateNoWindow = hideScreen; + if (hideScreen) + { + HSDProcess.StartInfo.RedirectStandardError = true; + // Send errors to log + HSDProcess.ErrorDataReceived += (sender, e) => mainForm.AddLog("HSD Error: " + e.Data); + } + else + { + HSDProcess.StartInfo.RedirectStandardError = false; + } + + HSDProcess.Start(); + while ((DateTime.Now - start).TotalSeconds < 5) + { + Thread.Sleep(10); Application.DoEvents(); - DateTime start = DateTime.Now; - // Install and load node - string dir = mainForm.dir; - HSDProcess = new Process(); - if (!Directory.Exists(dir)) Environment.Exit(1); - string hsdPath = dir + "hsd\\bin\\hsd.exe"; - if (!Directory.Exists(dir + "hsd")) + } + + splashScreen.CloseSplash(); + while (!splashScreen.IsClosed) + { + Thread.Sleep(10); + Application.DoEvents(); + } + + splashScreen.Dispose(); + mainForm.Show(); + } + + #region Constants + + private readonly MainForm mainForm = new(); + private readonly bool hideScreen = true; + private readonly Process HSDProcess; + + #endregion + + #region Git + + public void CloneRepository(string repositoryUrl, string destinationPath) + { + try + { + // Check if git is installed + var testInstalled = new Process(); + testInstalled.StartInfo.FileName = "git"; + testInstalled.StartInfo.Arguments = "-v"; + testInstalled.StartInfo.RedirectStandardOutput = true; + testInstalled.StartInfo.UseShellExecute = false; + testInstalled.StartInfo.CreateNoWindow = true; + testInstalled.Start(); + var outputInstalled = testInstalled.StandardOutput.ReadToEnd(); + testInstalled.WaitForExit(); + + if (!outputInstalled.Contains("git version")) { - string repositoryUrl = "https://github.com/handshake-org/hsd.git"; - string destinationPath = dir + "hsd"; - CloneRepository(repositoryUrl, destinationPath); + mainForm.AddLog("Git is not installed"); + var notifyForm = new NotifyForm("Git is not installed\nPlease install it to install HSD dependencies", + "Install", "https://git-scm.com/download/win"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + Environment.Exit(21); + return; } - // Start HSD - HSDProcess.StartInfo.RedirectStandardInput = true; - HSDProcess.StartInfo.RedirectStandardOutput = false; - HSDProcess.StartInfo.UseShellExecute = false; - HSDProcess.StartInfo.FileName = "node.exe"; - HSDProcess.StartInfo.Arguments = dir + "hsd\\bin\\hsd --agent=FireWallet --spv --prefix " + dir + "\\hsd_data"; - HSDProcess.StartInfo.CreateNoWindow = hideScreen; - if (hideScreen) + + // Check if node installed + testInstalled = new Process(); + testInstalled.StartInfo.FileName = "node"; + testInstalled.StartInfo.Arguments = "-v"; + testInstalled.StartInfo.RedirectStandardOutput = true; + testInstalled.StartInfo.UseShellExecute = false; + testInstalled.StartInfo.CreateNoWindow = true; + testInstalled.Start(); + outputInstalled = testInstalled.StandardOutput.ReadToEnd(); + testInstalled.WaitForExit(); + + if (!outputInstalled.Contains("v")) { - HSDProcess.StartInfo.RedirectStandardError = true; - // Send errors to log - HSDProcess.ErrorDataReceived += (sender, e) => mainForm.AddLog("HSD Error: " + e.Data); + mainForm.AddLog("Node is not installed"); + var notifyForm = new NotifyForm("Node is not installed\nPlease install it to install HSD dependencies", + "Install", "https://nodejs.org/en/download"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + Environment.Exit(22); + return; + } + + + // Check if npm installed + testInstalled = new Process(); + testInstalled.StartInfo.FileName = "cmd.exe"; + testInstalled.StartInfo.Arguments = "npm -v"; + testInstalled.StartInfo.RedirectStandardOutput = true; + testInstalled.StartInfo.UseShellExecute = false; + testInstalled.StartInfo.CreateNoWindow = false; + testInstalled.Start(); + // Wait 3 seconds and then kill + Thread.Sleep(3000); + testInstalled.Kill(); + outputInstalled = testInstalled.StandardOutput.ReadToEnd(); + testInstalled.WaitForExit(); + if (Regex.IsMatch(outputInstalled, @"^\d+\.\d+\.\d+$")) + { + mainForm.AddLog("NPM is not installed"); + mainForm.AddLog(outputInstalled); + var notifyForm = new NotifyForm("NPM is not installed\nPlease install it to install HSD dependencies", + "Install", "https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + Environment.Exit(23); + return; + } + + mainForm.AddLog("Prerequisites installed"); + + var startInfo = new ProcessStartInfo(); + startInfo.FileName = "git"; + startInfo.Arguments = $"clone {repositoryUrl} {destinationPath}"; + + if (repositoryUrl == "https://github.com/handshake-org/hsd.git") + startInfo.Arguments = $"clone --depth 1 --branch latest {repositoryUrl} {destinationPath}"; + + startInfo.RedirectStandardOutput = true; + startInfo.UseShellExecute = false; + startInfo.CreateNoWindow = hideScreen; + + var process = new Process(); + process.StartInfo = startInfo; + process.Start(); + + var output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + while (!process.HasExited) output += process.StandardOutput.ReadToEnd(); + var psiNpmRunDist = new ProcessStartInfo + { + FileName = "cmd", + RedirectStandardInput = true, + WorkingDirectory = destinationPath, + CreateNoWindow = hideScreen + }; + var pNpmRunDist = Process.Start(psiNpmRunDist); + pNpmRunDist.StandardInput.WriteLine("npm install & exit"); + pNpmRunDist.WaitForExit(); + } + catch (Exception ex) + { + mainForm.AddLog("Git/NPM Install FAILED"); + mainForm.AddLog(ex.Message); + if (ex.Message.Contains("to start process 'git'")) + { + var notifyForm = new NotifyForm("Git needs to be installed\nCheck logs for more details"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + } + else if (ex.Message.Contains("to start process 'node'")) + { + var notifyForm = new NotifyForm("Node needs to be installed\nCheck logs for more details"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + } + else if (ex.Message.Contains("to start process 'npm'")) + { + var notifyForm = new NotifyForm("NPM needs to be installed\nCheck logs for more details"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); } else { - HSDProcess.StartInfo.RedirectStandardError = false; + var notifyForm = new NotifyForm("Git/NPM Install FAILED\nCheck logs for more details"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); } - HSDProcess.Start(); - while ((DateTime.Now - start).TotalSeconds < 5) - { - Thread.Sleep(10); - Application.DoEvents(); - } - splashScreen.CloseSplash(); - while (!splashScreen.IsClosed) - { - Thread.Sleep(10); - Application.DoEvents(); - } - splashScreen.Dispose(); - mainForm.Show(); + + Environment.Exit(24); } - #region Git - public void CloneRepository(string repositoryUrl, string destinationPath) - { - try - { - // Check if git is installed - Process testInstalled = new Process(); - testInstalled.StartInfo.FileName = "git"; - testInstalled.StartInfo.Arguments = "-v"; - testInstalled.StartInfo.RedirectStandardOutput = true; - testInstalled.StartInfo.UseShellExecute = false; - testInstalled.StartInfo.CreateNoWindow = true; - testInstalled.Start(); - string outputInstalled = testInstalled.StandardOutput.ReadToEnd(); - testInstalled.WaitForExit(); - - if (!outputInstalled.Contains("git version")) - { - mainForm.AddLog("Git is not installed"); - NotifyForm notifyForm = new NotifyForm("Git is not installed\nPlease install it to install HSD dependencies", "Install", "https://git-scm.com/download/win"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - Environment.Exit(21); - return; - } - - // Check if node installed - testInstalled = new Process(); - testInstalled.StartInfo.FileName = "node"; - testInstalled.StartInfo.Arguments = "-v"; - testInstalled.StartInfo.RedirectStandardOutput = true; - testInstalled.StartInfo.UseShellExecute = false; - testInstalled.StartInfo.CreateNoWindow = true; - testInstalled.Start(); - outputInstalled = testInstalled.StandardOutput.ReadToEnd(); - testInstalled.WaitForExit(); - - if (!outputInstalled.Contains("v")) - { - mainForm.AddLog("Node is not installed"); - NotifyForm notifyForm = new NotifyForm("Node is not installed\nPlease install it to install HSD dependencies", "Install", "https://nodejs.org/en/download"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - Environment.Exit(22); - return; - } - - - // Check if npm installed - testInstalled = new Process(); - testInstalled.StartInfo.FileName = "cmd.exe"; - testInstalled.StartInfo.Arguments = "npm -v"; - testInstalled.StartInfo.RedirectStandardOutput = true; - testInstalled.StartInfo.UseShellExecute = false; - testInstalled.StartInfo.CreateNoWindow = false; - testInstalled.Start(); - // Wait 3 seconds and then kill - Thread.Sleep(3000); - testInstalled.Kill(); - outputInstalled = testInstalled.StandardOutput.ReadToEnd(); - testInstalled.WaitForExit(); - if (Regex.IsMatch(outputInstalled, @"^\d+\.\d+\.\d+$")) - { - mainForm.AddLog("NPM is not installed"); - mainForm.AddLog(outputInstalled); - NotifyForm notifyForm = new NotifyForm("NPM is not installed\nPlease install it to install HSD dependencies", "Install", "https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - Environment.Exit(23); - return; - } - - mainForm.AddLog("Prerequisites installed"); - - ProcessStartInfo startInfo = new ProcessStartInfo(); - startInfo.FileName = "git"; - startInfo.Arguments = $"clone {repositoryUrl} {destinationPath}"; - - if (repositoryUrl == "https://github.com/handshake-org/hsd.git") - { - startInfo.Arguments = $"clone --depth 1 --branch latest {repositoryUrl} {destinationPath}"; - } - - startInfo.RedirectStandardOutput = true; - startInfo.UseShellExecute = false; - startInfo.CreateNoWindow = hideScreen; - - Process process = new Process(); - process.StartInfo = startInfo; - process.Start(); - - string output = process.StandardOutput.ReadToEnd(); - process.WaitForExit(); - - while (!process.HasExited) - { - output += process.StandardOutput.ReadToEnd(); - } - var psiNpmRunDist = new ProcessStartInfo - { - FileName = "cmd", - RedirectStandardInput = true, - WorkingDirectory = destinationPath, - CreateNoWindow = hideScreen - }; - var pNpmRunDist = Process.Start(psiNpmRunDist); - pNpmRunDist.StandardInput.WriteLine("npm install & exit"); - pNpmRunDist.WaitForExit(); - } - catch (Exception ex) - { - mainForm.AddLog("Git/NPM Install FAILED"); - mainForm.AddLog(ex.Message); - if (ex.Message.Contains("to start process 'git'")) - { - NotifyForm notifyForm = new NotifyForm("Git needs to be installed\nCheck logs for more details"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - } - else if (ex.Message.Contains("to start process 'node'")) - { - NotifyForm notifyForm = new NotifyForm("Node needs to be installed\nCheck logs for more details"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - } - else if (ex.Message.Contains("to start process 'npm'")) - { - NotifyForm notifyForm = new NotifyForm("NPM needs to be installed\nCheck logs for more details"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - } - else - { - - NotifyForm notifyForm = new NotifyForm("Git/NPM Install FAILED\nCheck logs for more details"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - } - Environment.Exit(24); - } - } - public bool CheckNodeInstalled() - { - try - { - // Create a new process to execute the 'node' command - Process process = new Process(); - process.StartInfo.FileName = "node"; - process.StartInfo.Arguments = "--version"; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = true; - - // Start the process and read the output - process.Start(); - string output = process.StandardOutput.ReadToEnd(); - - // Wait for the process to exit - process.WaitForExit(); - - // Check if the output contains a version number - return !string.IsNullOrEmpty(output); - } - catch (Exception) - { - // An exception occurred, indicating that 'node' is not installed or accessible - return false; - } - } - #endregion - } + + public bool CheckNodeInstalled() + { + try + { + // Create a new process to execute the 'node' command + var process = new Process(); + process.StartInfo.FileName = "node"; + process.StartInfo.Arguments = "--version"; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + + // Start the process and read the output + process.Start(); + var output = process.StandardOutput.ReadToEnd(); + + // Wait for the process to exit + process.WaitForExit(); + + // Check if the output contains a version number + return !string.IsNullOrEmpty(output); + } + catch (Exception) + { + // An exception occurred, indicating that 'node' is not installed or accessible + return false; + } + } + + #endregion } \ No newline at end of file diff --git a/FireWalletLite/MainForm.cs b/FireWalletLite/MainForm.cs index ce8b14d..591f3a8 100644 --- a/FireWalletLite/MainForm.cs +++ b/FireWalletLite/MainForm.cs @@ -1,837 +1,804 @@ using System.Diagnostics; -using System.DirectoryServices.ActiveDirectory; using FireWallet; using Newtonsoft.Json.Linq; -using static QRCoder.PayloadGenerator; -namespace FireWalletLite +namespace FireWalletLite; + +public partial class MainForm : Form { - public partial class MainForm : Form + private bool testedLogin; + + public MainForm() { - #region Constants and Config - - // Directory to store files including logs, theme and hsd node - public string dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" - + Application.ProductName.Trim().Replace(" ", "") + "\\"; - - // How many days to check for domain exiries. If domain will expire in less than this, prompt user to renew. - public int daysToExpire = 90; - - // Explorer URLs for transactions and domains - public string TXExplorer = "https://niami.io/tx/"; - public string DomainExplorer = "https://niami.io/domain/"; - - // Links to show in help dropdown menu - public Dictionary HelpLinks = new Dictionary() + InitializeComponent(); + UpdateTheme(); + Text = Application.ProductName; + foreach (var link in HelpLinks) { - { "Discord", "https://l.woodburn.au/discord" }, - { "Separator", "" }, - { "Github", "https://github.com/nathanwoodburn/FireWalletLite" } - }; - - // Min Confirmations for transactions to be considered valid - public int MinConfirmations = 1; - - #endregion - - #region Variables - - public Dictionary Theme { get; set; } - HttpClient httpClient = new HttpClient(); - Decimal Balance { get; set; } - public String Account = "primary"; - public String Password { get; set; } - - #endregion - - public MainForm() - { - InitializeComponent(); - UpdateTheme(); - this.Text = Application.ProductName; - foreach (KeyValuePair link in HelpLinks) + if (link.Key == "Separator") { - if (link.Key == "Separator") - { - DropDownHelp.DropDownItems.Add(new ToolStripSeparator()); - continue; - } + DropDownHelp.DropDownItems.Add(new ToolStripSeparator()); + continue; + } - ToolStripMenuItem tsmi = new ToolStripMenuItem(link.Key); - tsmi.Click += (s, e) => + var tsmi = new ToolStripMenuItem(link.Key); + tsmi.Click += (s, e) => + { + var psi = new ProcessStartInfo { - ProcessStartInfo psi = new ProcessStartInfo - { - FileName = link.Value, - UseShellExecute = true - }; - Process.Start(psi); + FileName = link.Value, + UseShellExecute = true }; - DropDownHelp.DropDownItems.Add(tsmi); - } - - DropDownHelp.Margin = - new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - 20, 0, 0, 0); + Process.Start(psi); + }; + DropDownHelp.DropDownItems.Add(tsmi); } - #region Theming + DropDownHelp.Margin = + new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - 20, 0, 0, 0); + } - private void UpdateTheme() + #region Logging + + public void AddLog(string message) + { + if (message.Contains( + "Get Error: No connection could be made because the target machine actively refused it")) return; + + // If file size is over 1MB, rename it to old.log.txt + if (File.Exists(dir + "log.txt")) { - // Check if file exists - if (!Directory.Exists(dir)) + var fi = new FileInfo(dir + "log.txt"); + if (fi.Length > 1000000) { - CreateConfig(dir); + if (File.Exists(dir + "old.log.txt")) + File.Delete(dir + "old.log.txt"); // Delete old log file as it is super old + File.Move(dir + "log.txt", dir + "old.log.txt"); } - - if (!File.Exists(dir + "theme.txt")) - { - CreateConfig(dir); - } - - // Read file - StreamReader sr = new StreamReader(dir + "theme.txt"); - Theme = new Dictionary(); - while (!sr.EndOfStream) - { - string line = sr.ReadLine(); - string[] split = line.Split(':'); - Theme.Add(split[0].Trim(), split[1].Trim()); - } - - sr.Dispose(); - - if (!Theme.ContainsKey("background") || !Theme.ContainsKey("background-alt") || - !Theme.ContainsKey("foreground") || !Theme.ContainsKey("foreground-alt")) - { - AddLog("Theme file is missing key"); - return; - } - - // Apply theme - this.BackColor = ColorTranslator.FromHtml(Theme["background"]); - - // Foreground - this.ForeColor = ColorTranslator.FromHtml(Theme["foreground"]); - - - // Need to specify this for each groupbox to override the black text - foreach (Control c in Controls) - { - ThemeControl(c); - } - - this.Width = Screen.PrimaryScreen.Bounds.Width / 5 * 3; - this.Height = Screen.PrimaryScreen.Bounds.Height / 5 * 3; } - public void ThemeControl(Control c) + var sw = new StreamWriter(dir + "log.txt", true); + sw.WriteLine(DateTime.Now + ": " + message); + sw.Dispose(); + } + + #endregion + + private void timerUpdate_Tick(object sender, EventArgs e) + { + if (SyncLabel.Text != "Status: Node Not Connected") + if (!testedLogin) + { + testedLogin = true; + Hide(); + TestForLogin(); + Show(); + } + + NodeStatus(); + } + + private void MainForm_Load(object sender, EventArgs e) + { + groupBoxLogin.Left = (ClientSize.Width - groupBoxLogin.Width) / 2; + groupBoxLogin.Top = (ClientSize.Height - groupBoxLogin.Height) / 2; + pictureBoxLogo.Height = groupBoxLogin.Top - 20; + pictureBoxLogo.Width = pictureBoxLogo.Height; + pictureBoxLogo.Top = 10; + pictureBoxLogo.Left = (ClientSize.Width - pictureBoxLogo.Width) / 2; + TopMost = true; + textBoxPassword.Focus(); + TopMost = false; + } + + private async void TestForLogin() + { + var path = "wallet/" + Account + "/master"; + var response = await APIGet(path, true); + var resp = JObject.Parse(response); + if (resp["encrypted"].ToString() == "False") { - if (c.GetType() == typeof(GroupBox) || c.GetType() == typeof(Panel)) - { - c.ForeColor = ColorTranslator.FromHtml(Theme["foreground"]); - foreach (Control sub in c.Controls) - { - ThemeControl(sub); - } - } + var mnemonic = JObject.Parse(resp["mnemonic"].ToString()); + var phrase = mnemonic["phrase"].ToString(); - if (c.GetType() == typeof(TextBox) || c.GetType() == typeof(Button) - || c.GetType() == typeof(ComboBox) || - c.GetType() == typeof(StatusStrip) || c.GetType() == typeof(ToolStrip) - || c.GetType() == typeof(NumericUpDown)) - { - c.ForeColor = ColorTranslator.FromHtml(Theme["foreground-alt"]); - c.BackColor = ColorTranslator.FromHtml(Theme["background-alt"]); - } + // Show form to save mnemonic and encrypt wallet + var firstLoginForm = new FirstLoginForm(phrase, this); + firstLoginForm.ShowDialog(); + firstLoginForm.Dispose(); + } + } - if (c.GetType() == typeof(Panel)) c.Dock = DockStyle.Fill; + private async void Login_Click(object sender, EventArgs e) + { + LoginButton.Enabled = false; // To prevent double clicking + Password = textBoxPassword.Text; + + var path = "wallet/" + Account + "/unlock"; + var content = "{\"passphrase\": \"" + Password + "\",\"timeout\": 60}"; + + var response = await APIPost(path, true, content); + if (response == "Error") + { + Password = ""; + var notifyForm = new NotifyForm("Incorrect Password"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + LoginButton.Enabled = true; + return; } - private void CreateConfig(string dir) - { - if (!Directory.Exists(dir)) - { - Directory.CreateDirectory(dir); - } + groupBoxDomains.Width = Width - groupBoxDomains.Left - 20; + await UpdateBalance(); + await GetTXHistory(); + panelLogin.Hide(); + panelNav.Dock = DockStyle.Left; + panelPortfolio.Show(); - StreamWriter sw = new StreamWriter(dir + "theme.txt"); - sw.WriteLine("background: #000000"); - sw.WriteLine("foreground: #8e05c2"); - sw.WriteLine("background-alt: #3e065f"); - sw.WriteLine("foreground-alt: #ffffff"); - sw.WriteLine("error: #ff0000"); - sw.Dispose(); - AddLog("Created theme file"); + // Some UI stuff + groupBoxAccount.Top = statusStripMain.Height + 10; + groupBoxDomains.Top = statusStripMain.Height + 10; + groupBoxDomains.Height = Height - groupBoxDomains.Top - 40; + buttonReceive.Top = statusStripMain.Height + 10; + buttonSend.Top = buttonReceive.Top + buttonReceive.Height + 10; + buttonRenew.Top = groupBoxAccount.Top + groupBoxAccount.Height + 10; + groupBoxHistory.Top = buttonRenew.Top + buttonRenew.Height + 10; + groupBoxHistory.Height = Height - groupBoxHistory.Top - 40; + } + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + // Run taskkill /im "node.exe" /f /t + var startInfo = new ProcessStartInfo(); + startInfo.FileName = "taskkill.exe"; + startInfo.Arguments = "/im \"node.exe\" /f /t"; + startInfo.CreateNoWindow = true; + Process.Start(startInfo); + Environment.Exit(0); + } + + private void textBoxPassword_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyValue == 13) + { + Login_Click(sender, e); + e.SuppressKeyPress = true; + } + } + + private async void buttonReceive_Click(object sender, EventArgs e) + { + var path = "wallet/" + Account + "/address"; + var content = "{\"account\": \"default\"}"; + var response = await APIPost(path, true, content); + if (response == "Error") + { + var notifyForm = new NotifyForm("Error getting address"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + return; } - #endregion + var resp = JObject.Parse(response); + var address = resp["address"].ToString(); - #region Logging + var receiveForm = new ReceiveForm(address, this); + receiveForm.ShowDialog(); + receiveForm.Dispose(); + } - public void AddLog(string message) + private void buttonSend_Click(object sender, EventArgs e) + { + var sendForm = new SendForm(Balance, this); + sendForm.ShowDialog(); + sendForm.Dispose(); + } + + private async void buttonRenew_Click(object sender, EventArgs e) + { + var batches = new Batch[DomainsRenewable.Length]; + for (var i = 0; i < DomainsRenewable.Length; i++) batches[i] = new Batch(DomainsRenewable[i], "RENEW"); + + var batchTX = "[" + string.Join(", ", batches.Select(batch => batch.ToString())) + "]"; + var content = "{\"method\": \"sendbatch\",\"params\":[ " + batchTX + "]}"; + var response = await APIPost("", true, content); + + if (response == "Error") { - if (message.Contains( - "Get Error: No connection could be made because the target machine actively refused it")) return; - - // If file size is over 1MB, rename it to old.log.txt - if (File.Exists(dir + "log.txt")) - { - FileInfo fi = new FileInfo(dir + "log.txt"); - if (fi.Length > 1000000) - { - if (File.Exists(dir + "old.log.txt")) - File.Delete(dir + "old.log.txt"); // Delete old log file as it is super old - File.Move(dir + "log.txt", dir + "old.log.txt"); - } - } - - StreamWriter sw = new StreamWriter(dir + "log.txt", true); - sw.WriteLine(DateTime.Now.ToString() + ": " + message); - sw.Dispose(); + AddLog("Error sending renewals"); + var notifyForm = new NotifyForm("Error sending renewals"); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + return; } - #endregion - - bool testedLogin = false; - - private void timerUpdate_Tick(object sender, EventArgs e) + var jObject = JObject.Parse(response); + if (jObject["error"].ToString() != "") { - if (SyncLabel.Text != "Status: Node Not Connected") + AddLog("Error: "); + AddLog(jObject["error"].ToString()); + if (jObject["error"].ToString().Contains("Batch output addresses would exceed lookahead")) { - if (!testedLogin) - { - testedLogin = true; - this.Hide(); - TestForLogin(); - this.Show(); - } - } - - NodeStatus(); - } - - #region API - - private async void NodeStatus() - { - if (await APIGet("", false) == "Error") - { - SyncLabel.Text = "Status: Node Not Connected"; - return; + var notifyForm = + new NotifyForm( + "Error: \nBatch output addresses would exceed lookahead\nYour batch might have too many TXs."); + notifyForm.ShowDialog(); + notifyForm.Dispose(); } else { - // Get sync status - String APIresponse = await APIGet("", false); - JObject resp = JObject.Parse(APIresponse); - JObject chain = JObject.Parse(resp["chain"].ToString()); - decimal progress = Convert.ToDecimal(chain["progress"].ToString()); - SyncLabel.Text = "Sync: " + decimal.Round(progress * 100, 2) + "%"; - if (progress < 1) + var notifyForm = new NotifyForm("Error: \n" + jObject["error"]); + notifyForm.ShowDialog(); + notifyForm.Dispose(); + } + + return; + } + + var result = JObject.Parse(jObject["result"].ToString()); + var hash = result["hash"].ToString(); + AddLog("Batch sent with hash: " + hash); + var notifyForm2 = + new NotifyForm("Renewals sent\nThis might take a while to mine.", "Explorer", TXExplorer + hash); + notifyForm2.ShowDialog(); + notifyForm2.Dispose(); + } + + #region Constants and Config + + // Directory to store files including logs, theme and hsd node + public string dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + + Application.ProductName.Trim().Replace(" ", "") + "\\"; + + // How many days to check for domain exiries. If domain will expire in less than this, prompt user to renew. + public int daysToExpire = 90; + + // Explorer URLs for transactions and domains + public string TXExplorer = "https://niami.io/tx/"; + public string DomainExplorer = "https://niami.io/domain/"; + + // Links to show in help dropdown menu + public Dictionary HelpLinks = new() + { + { "Discord", "https://l.woodburn.au/discord" }, + { "Separator", "" }, + { "Github", "https://github.com/nathanwoodburn/FireWalletLite" } + }; + + // Min Confirmations for transactions to be considered valid + public int MinConfirmations = 1; + + #endregion + + #region Variables + + public Dictionary Theme { get; set; } + private readonly HttpClient httpClient = new(); + private decimal Balance { get; set; } + public string Account = "primary"; + public string Password { get; set; } + + #endregion + + #region Theming + + private void UpdateTheme() + { + // Check if file exists + if (!Directory.Exists(dir)) CreateConfig(dir); + + if (!File.Exists(dir + "theme.txt")) CreateConfig(dir); + + // Read file + var sr = new StreamReader(dir + "theme.txt"); + Theme = new Dictionary(); + while (!sr.EndOfStream) + { + var line = sr.ReadLine(); + var split = line.Split(':'); + Theme.Add(split[0].Trim(), split[1].Trim()); + } + + sr.Dispose(); + + if (!Theme.ContainsKey("background") || !Theme.ContainsKey("background-alt") || + !Theme.ContainsKey("foreground") || !Theme.ContainsKey("foreground-alt")) + { + AddLog("Theme file is missing key"); + return; + } + + // Apply theme + BackColor = ColorTranslator.FromHtml(Theme["background"]); + + // Foreground + ForeColor = ColorTranslator.FromHtml(Theme["foreground"]); + + + // Need to specify this for each groupbox to override the black text + foreach (Control c in Controls) ThemeControl(c); + + Width = Screen.PrimaryScreen.Bounds.Width / 5 * 3; + Height = Screen.PrimaryScreen.Bounds.Height / 5 * 3; + } + + public void ThemeControl(Control c) + { + if (c.GetType() == typeof(GroupBox) || c.GetType() == typeof(Panel)) + { + c.ForeColor = ColorTranslator.FromHtml(Theme["foreground"]); + foreach (Control sub in c.Controls) ThemeControl(sub); + } + + if (c.GetType() == typeof(TextBox) || c.GetType() == typeof(Button) + || c.GetType() == typeof(ComboBox) || + c.GetType() == typeof(StatusStrip) || c.GetType() == typeof(ToolStrip) + || c.GetType() == typeof(NumericUpDown)) + { + c.ForeColor = ColorTranslator.FromHtml(Theme["foreground-alt"]); + c.BackColor = ColorTranslator.FromHtml(Theme["background-alt"]); + } + + if (c.GetType() == typeof(Panel)) c.Dock = DockStyle.Fill; + } + + private void CreateConfig(string dir) + { + if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); + + var streamWriter = new StreamWriter(dir + "theme.txt"); + streamWriter.WriteLine("background: #000000"); + streamWriter.WriteLine("foreground: #8e05c2"); + streamWriter.WriteLine("background-alt: #3e065f"); + streamWriter.WriteLine("foreground-alt: #ffffff"); + streamWriter.WriteLine("error: #ff0000"); + streamWriter.Dispose(); + AddLog("Created theme file"); + } + + #endregion + + #region API + + private async void NodeStatus() + { + if (await APIGet("", false) == "Error") + { + SyncLabel.Text = "Status: Node Not Connected"; + return; + } + + // Get sync status + var APIresponse = await APIGet("", false); + var resp = JObject.Parse(APIresponse); + var chain = JObject.Parse(resp["chain"].ToString()); + var progress = Convert.ToDecimal(chain["progress"].ToString()); + SyncLabel.Text = "Sync: " + decimal.Round(progress * 100, 2) + "%"; + if (progress < 1) + { + LabelSyncWarning.Visible = true; + DropDownHelp.Margin = + new Padding( + statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - LabelSyncWarning.Width - 20, + 0, 0, 0); + } + else + { + LabelSyncWarning.Visible = false; + DropDownHelp.Margin = new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - 20, + 0, 0, 0); + } + + // Try to keep wallet unlocked + var path = "wallet/" + Account + "/unlock"; + var content = "{\"passphrase\": \"" + Password + "\",\"timeout\": 60}"; + await APIPost(path, true, content); + path = ""; + content = "{\"method\": \"selectwallet\",\"params\":[ \"" + Account + "\"]}"; + + await APIPost(path, true, content); + } + + private async Task UpdateBalance() + { + var response = await APIGet("wallet/" + Account + "/balance?account=default", true); + if (response == "Error") return; + + var resp = JObject.Parse(response); + + var available = (Convert.ToDecimal(resp["unconfirmed"].ToString()) - + Convert.ToDecimal(resp["lockedUnconfirmed"].ToString())) / 1000000; + var locked = Convert.ToDecimal(resp["lockedUnconfirmed"].ToString()) / 1000000; + available = decimal.Round(available, 2); + locked = decimal.Round(locked, 2); + Balance = available; + labelBalance.Text = "Balance: " + available + " HNS"; + + // Get domain count + UpdateDomains(); + } + + public async Task APIPost(string path, bool wallet, string content) + { + if (content == "{\"passphrase\": \"\",\"timeout\": 60}") return ""; + + var ip = "127.0.0.1"; + var port = "1203"; + if (wallet) port = port + "9"; + else port = port + "7"; + var req = new HttpRequestMessage(HttpMethod.Post, "http://" + ip + ":" + port + "/" + path); + //req.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes("x:" + key))); + req.Content = new StringContent(content); + // Send request + try + { + var resp = await httpClient.SendAsync(req); + if (!resp.IsSuccessStatusCode) + { + AddLog("Post Error: " + resp.StatusCode); + AddLog(await resp.Content.ReadAsStringAsync()); + return "Error"; + } + + return await resp.Content.ReadAsStringAsync(); + } + catch (Exception ex) + { + AddLog("Post Error: " + ex.Message); + if (ex.Message.Contains("The request was canceled due to the configured HttpClient.Timeout")) + Environment.Exit(91); + + return "Error"; + } + } + + public async Task APIGet(string path, bool wallet) + { + var ip = "127.0.0.1"; + + var port = "1203"; + if (wallet) port = port + "9"; + else port = port + "7"; + try + { + var request = + new HttpRequestMessage(HttpMethod.Get, "http://" + ip + ":" + port + "/" + path); + // Add API key to header + //request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes("x:" + key))); + // Send request and log response + var response = await httpClient.SendAsync(request); + if (!response.IsSuccessStatusCode) + { + AddLog("Get Error: " + response.StatusCode); + AddLog(await response.Content.ReadAsStringAsync()); + return "Error"; + } + + return await response.Content.ReadAsStringAsync(); + } + // Log errors to log textbox + catch (Exception ex) + { + AddLog("Get Error: " + ex.Message); + if (ex.Message.Contains("The request was canceled due to the configured HttpClient.Timeout")) + Environment.Exit(91); + + return "Error"; + } + } + + public async Task ValidAddress(string address) + { + var output = await APIPost("", false, + "{\"method\": \"validateaddress\",\"params\": [ \"" + address + "\" ]}"); + var APIresp = JObject.Parse(output); + var result = JObject.Parse(APIresp["result"].ToString()); + if (result["isvalid"].ToString() == "True") return true; + return false; + } + + public string[] Domains { get; set; } + public string[] DomainsRenewable { get; set; } + + private async void UpdateDomains() + { + var response = await APIGet("wallet/" + Account + "/name?own=true", true); + + try + { + var names = JArray.Parse(response); + Domains = new string[names.Count]; + DomainsRenewable = new string[names.Count]; + var i = 0; + var renewable = 0; + // Sort by Alphabetic order + names = new JArray(names.OrderBy(obj => (string)obj["name"])); + panelDomainList.Controls.Clear(); + + // If no domains, add label and return + if (names.Count == 0) + { + var noDomainsLabel = new Label(); + noDomainsLabel.Text = "No domains yet.\nPlease note domain transfers take at least 2 days"; + noDomainsLabel.TextAlign = ContentAlignment.MiddleCenter; + noDomainsLabel.AutoSize = true; + panelDomainList.Controls.Add(noDomainsLabel); + noDomainsLabel.Left = panelDomainList.Width / 2 - noDomainsLabel.Width / 2; + noDomainsLabel.Top = 10; + } + + foreach (JObject name in names) + { + Domains[i] = name["name"].ToString(); + var domainTMP = new Panel(); + domainTMP.Width = panelDomainList.Width - 20 - SystemInformation.VerticalScrollBarWidth; + domainTMP.Height = 30; + domainTMP.Top = 30 * i; + domainTMP.Left = 10; + domainTMP.BorderStyle = BorderStyle.FixedSingle; + + var domainName = new Label(); + domainName.Text = Domains[i]; + domainName.Top = 5; + domainName.Left = 5; + domainName.AutoSize = true; + domainTMP.Controls.Add(domainName); + + if (!name.ContainsKey("stats")) { - LabelSyncWarning.Visible = true; - DropDownHelp.Margin = - new Padding( - statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - LabelSyncWarning.Width - 20, - 0, 0, 0); + AddLog("Domain " + Domains[i] + " does not have stats"); + continue; + } + + var expiry = new Label(); + var stats = JObject.Parse(name["stats"].ToString()); + if (stats.ContainsKey("daysUntilExpire")) + { + expiry.Text = "Expires: " + stats["daysUntilExpire"] + " days"; + expiry.Top = 5; + expiry.AutoSize = true; + expiry.Left = domainTMP.Width - expiry.Width - 100; + domainTMP.Controls.Add(expiry); + + // Add to domains renewable if less than set days + var days = decimal.Parse(stats["daysUntilExpire"].ToString()); + if (days <= daysToExpire) + { + DomainsRenewable[renewable] = Domains[i]; + renewable++; + } } else { - LabelSyncWarning.Visible = false; - DropDownHelp.Margin = new Padding(statusStripMain.Width - DropDownHelp.Width - SyncLabel.Width - 20, - 0, 0, 0); + expiry.Text = "Expires: Not Registered yet"; + expiry.Top = 5; + expiry.AutoSize = true; + expiry.Left = domainTMP.Width - expiry.Width - 100; + domainTMP.Controls.Add(expiry); } + // On Click open domain - } - - // Try to keep wallet unlocked - string path = "wallet/" + Account + "/unlock"; - string content = "{\"passphrase\": \"" + Password + "\",\"timeout\": 60}"; - await APIPost(path, true, content); - path = ""; - content = "{\"method\": \"selectwallet\",\"params\":[ \"" + Account + "\"]}"; - - await APIPost(path, true, content); - - } - - private async Task UpdateBalance() - { - string response = await APIGet("wallet/" + Account + "/balance?account=default", true); - if (response == "Error") return; - - JObject resp = JObject.Parse(response); - - decimal available = (Convert.ToDecimal(resp["unconfirmed"].ToString()) - - Convert.ToDecimal(resp["lockedUnconfirmed"].ToString())) / 1000000; - decimal locked = Convert.ToDecimal(resp["lockedUnconfirmed"].ToString()) / 1000000; - available = decimal.Round(available, 2); - locked = decimal.Round(locked, 2); - Balance = available; - labelBalance.Text = "Balance: " + available + " HNS"; - - // Get domain count - UpdateDomains(); - - } - - public async Task APIPost(string path, bool wallet, string content) - { - if (content == "{\"passphrase\": \"\",\"timeout\": 60}") - { - return ""; - } - - string ip = "127.0.0.1"; - string port = "1203"; - if (wallet) port = port + "9"; - else port = port + "7"; - HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, "http://" + ip + ":" + port + "/" + path); - //req.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes("x:" + key))); - req.Content = new StringContent(content); - // Send request - try - { - HttpResponseMessage resp = await httpClient.SendAsync(req); - if (!resp.IsSuccessStatusCode) + domainTMP.Click += (sender, e) => { - AddLog("Post Error: " + resp.StatusCode); - AddLog(await resp.Content.ReadAsStringAsync()); - return "Error"; - } - - return await resp.Content.ReadAsStringAsync(); - - } - catch (Exception ex) - { - AddLog("Post Error: " + ex.Message); - if (ex.Message.Contains("The request was canceled due to the configured HttpClient.Timeout")) - { - Environment.Exit(91); - } - - return "Error"; - } - } - - public async Task APIGet(string path, bool wallet) - { - string ip = "127.0.0.1"; - - string port = "1203"; - if (wallet) port = port + "9"; - else port = port + "7"; - try - { - HttpRequestMessage request = - new HttpRequestMessage(HttpMethod.Get, "http://" + ip + ":" + port + "/" + path); - // Add API key to header - //request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes("x:" + key))); - // Send request and log response - HttpResponseMessage response = await httpClient.SendAsync(request); - if (!response.IsSuccessStatusCode) - { - AddLog("Get Error: " + response.StatusCode); - AddLog(await response.Content.ReadAsStringAsync()); - return "Error"; - } - - return await response.Content.ReadAsStringAsync(); - - } - // Log errors to log textbox - catch (Exception ex) - { - AddLog("Get Error: " + ex.Message); - if (ex.Message.Contains("The request was canceled due to the configured HttpClient.Timeout")) - { - Environment.Exit(91); - } - - return "Error"; - } - } - - public async Task ValidAddress(string address) - { - string output = await APIPost("", false, - "{\"method\": \"validateaddress\",\"params\": [ \"" + address + "\" ]}"); - JObject APIresp = JObject.Parse(output); - JObject result = JObject.Parse(APIresp["result"].ToString()); - if (result["isvalid"].ToString() == "True") return true; - else return false; - } - - public string[] Domains { get; set; } - public string[] DomainsRenewable { get; set; } - - private async void UpdateDomains() - { - string response = await APIGet("wallet/" + Account + "/name?own=true", true); - - try - { - JArray names = JArray.Parse(response); - Domains = new string[names.Count]; - DomainsRenewable = new string[names.Count]; - int i = 0; - int renewable = 0; - // Sort by Alphabetic order - names = new JArray(names.OrderBy(obj => (string)obj["name"])); - panelDomainList.Controls.Clear(); - - // If no domains, add label and return - if (names.Count == 0) - { - Label noDomainsLabel = new Label(); - noDomainsLabel.Text = "No domains yet.\nPlease note domain transfers take at least 2 days"; - noDomainsLabel.TextAlign = ContentAlignment.MiddleCenter; - noDomainsLabel.AutoSize = true; - panelDomainList.Controls.Add(noDomainsLabel); - noDomainsLabel.Left = panelDomainList.Width / 2 - noDomainsLabel.Width / 2; - noDomainsLabel.Top = 10; - } - - foreach (JObject name in names) - { - Domains[i] = name["name"].ToString(); - Panel domainTMP = new Panel(); - domainTMP.Width = panelDomainList.Width - 20 - SystemInformation.VerticalScrollBarWidth; - domainTMP.Height = 30; - domainTMP.Top = 30 * (i); - domainTMP.Left = 10; - domainTMP.BorderStyle = BorderStyle.FixedSingle; - - Label domainName = new Label(); - domainName.Text = Domains[i]; - domainName.Top = 5; - domainName.Left = 5; - domainName.AutoSize = true; - domainTMP.Controls.Add(domainName); - - if (!name.ContainsKey("stats")) - { - AddLog("Domain " + Domains[i] + " does not have stats"); - continue; - } - - Label expiry = new Label(); - JObject stats = JObject.Parse(name["stats"].ToString()); - if (stats.ContainsKey("daysUntilExpire")) - { - expiry.Text = "Expires: " + stats["daysUntilExpire"].ToString() + " days"; - expiry.Top = 5; - expiry.AutoSize = true; - expiry.Left = domainTMP.Width - expiry.Width - 100; - domainTMP.Controls.Add(expiry); - - // Add to domains renewable if less than set days - decimal days = decimal.Parse(stats["daysUntilExpire"].ToString()); - if (days <= daysToExpire) - { - DomainsRenewable[renewable] = Domains[i]; - renewable++; - } - } - else - { - expiry.Text = "Expires: Not Registered yet"; - expiry.Top = 5; - expiry.AutoSize = true; - expiry.Left = domainTMP.Width - expiry.Width - 100; - domainTMP.Controls.Add(expiry); - } - // On Click open domain - - domainTMP.Click += new EventHandler((sender, e) => - { - DomainForm domainForm = new DomainForm(this, name["name"].ToString()); - domainForm.Show(); - }); - foreach (Control c in domainTMP.Controls) - { - c.Click += new EventHandler((sender, e) => - { - DomainForm domainForm = new DomainForm(this, name["name"].ToString()); - domainForm.Show(); - }); - } - - panelDomainList.Controls.Add(domainTMP); - i++; - } - - labelDomains.Text = "Domains: " + names.Count; - - if (renewable > 0) - { - buttonRenew.Text = "Renew " + renewable + " domains"; - buttonRenew.Enabled = true; - } - } - catch (Exception ex) - { - AddLog("Error getting domains"); - AddLog(ex.Message); - } - } - - private async Task GetTXHistory() - { - // Check how many TX there are - string APIresponse = await APIGet("wallet/" + Account, true); - JObject wallet = JObject.Parse(APIresponse); - if (!wallet.ContainsKey("balance")) - { - AddLog("GetInfo Error"); - AddLog(APIresponse); - return; - } - - JObject balance = JObject.Parse(wallet["balance"].ToString()); - int TotalTX = Convert.ToInt32(balance["tx"].ToString()); - int toGet = 10; - - if (toGet > TotalTX) toGet = TotalTX; - int toSkip = TotalTX - toGet; - - // GET TXs - APIresponse = await APIPost("", true, - "{\"method\": \"listtransactions\",\"params\": [\"default\"," + toGet + "," + toSkip + "]}"); - - if (APIresponse == "Error") - { - AddLog("GetInfo Error"); - return; - } - - JObject TXGET = JObject.Parse(APIresponse); - - // Check for error - if (TXGET["error"].ToString() != "") - { - AddLog("GetInfo Error"); - AddLog(APIresponse); - return; - } - - JArray txs = JArray.Parse(TXGET["result"].ToString()); - if (toGet > txs.Count) - toGet = txs.Count; // In case there are less TXs than expected (usually happens when the get TX's fails) - Control[] tmpControls = new Control[toGet]; - for (int i = 0; i < toGet; i++) - { - - // Get last tx - JObject tx = - JObject.Parse(await APIGet("wallet/" + Account + "/tx/" + txs[toGet - i - 1]["txid"].ToString(), - true)); - - string hash = tx["hash"].ToString(); - string date = tx["mdate"].ToString(); - - date = DateTime.Parse(date).ToShortDateString(); - - - - - Panel tmpPanel = new Panel(); - tmpPanel.Width = groupBoxHistory.Width - SystemInformation.VerticalScrollBarWidth - 20; - tmpPanel.Height = 50; - tmpPanel.Location = new Point(5, (i * 55)); - tmpPanel.BorderStyle = BorderStyle.FixedSingle; - tmpPanel.BackColor = ColorTranslator.FromHtml(Theme["background-alt"]); - tmpPanel.ForeColor = ColorTranslator.FromHtml(Theme["foreground-alt"]); - tmpPanel.Controls.Add( - new Label() - { - Text = "Date: " + date, - Location = new Point(10, 5) - } - ); - int confirmations = Convert.ToInt32(tx["confirmations"].ToString()); - if (confirmations < MinConfirmations) - { - Label txPending = new Label() - { - Text = "Pending", - Location = new Point(100, 5) - }; - tmpPanel.Controls.Add(txPending); - txPending.BringToFront(); - } - - - Label labelHash = new Label() - { - Text = "Hash: " + hash.Substring(0, 10) + "..." + hash.Substring(hash.Length - 10), - AutoSize = true, - Location = new Point(10, 25) + var domainForm = new DomainForm(this, name["name"].ToString()); + domainForm.Show(); }; + foreach (Control c in domainTMP.Controls) + c.Click += (sender, e) => + { + var domainForm = new DomainForm(this, name["name"].ToString()); + domainForm.Show(); + }; - tmpPanel.Controls.Add(labelHash); - tmpPanel.Click += (sender, e) => + panelDomainList.Controls.Add(domainTMP); + i++; + } + + labelDomains.Text = "Domains: " + names.Count; + + if (renewable > 0) + { + buttonRenew.Text = "Renew " + renewable + " domains"; + buttonRenew.Enabled = true; + } + } + catch (Exception ex) + { + AddLog("Error getting domains"); + AddLog(ex.Message); + } + } + + private async Task GetTXHistory() + { + // Check how many TX there are + var APIresponse = await APIGet("wallet/" + Account, true); + var wallet = JObject.Parse(APIresponse); + if (!wallet.ContainsKey("balance")) + { + AddLog("GetInfo Error"); + AddLog(APIresponse); + return; + } + + var balance = JObject.Parse(wallet["balance"].ToString()); + var TotalTX = Convert.ToInt32(balance["tx"].ToString()); + var toGet = 10; + + if (toGet > TotalTX) toGet = TotalTX; + var toSkip = TotalTX - toGet; + + // GET TXs + APIresponse = await APIPost("", true, + "{\"method\": \"listtransactions\",\"params\": [\"default\"," + toGet + "," + toSkip + "]}"); + + if (APIresponse == "Error") + { + AddLog("GetInfo Error"); + return; + } + + var TXGET = JObject.Parse(APIresponse); + + // Check for error + if (TXGET["error"].ToString() != "") + { + AddLog("GetInfo Error"); + AddLog(APIresponse); + return; + } + + var txs = JArray.Parse(TXGET["result"].ToString()); + if (toGet > txs.Count) + toGet = txs.Count; // In case there are less TXs than expected (usually happens when the get TX's fails) + var tmpControls = new Control[toGet]; + for (var i = 0; i < toGet; i++) + { + // Get last tx + var tx = + JObject.Parse(await APIGet("wallet/" + Account + "/tx/" + txs[toGet - i - 1]["txid"], + true)); + + var hash = tx["hash"].ToString(); + var date = tx["mdate"].ToString(); + + date = DateTime.Parse(date).ToShortDateString(); + + + var tmpPanel = new Panel(); + tmpPanel.Width = groupBoxHistory.Width - SystemInformation.VerticalScrollBarWidth - 20; + tmpPanel.Height = 50; + tmpPanel.Location = new Point(5, i * 55); + tmpPanel.BorderStyle = BorderStyle.FixedSingle; + tmpPanel.BackColor = ColorTranslator.FromHtml(Theme["background-alt"]); + tmpPanel.ForeColor = ColorTranslator.FromHtml(Theme["foreground-alt"]); + tmpPanel.Controls.Add( + new Label { - ProcessStartInfo psi = new ProcessStartInfo + Text = "Date: " + date, + Location = new Point(10, 5) + } + ); + var confirmations = Convert.ToInt32(tx["confirmations"].ToString()); + if (confirmations < MinConfirmations) + { + var txPending = new Label + { + Text = "Pending", + Location = new Point(100, 5) + }; + tmpPanel.Controls.Add(txPending); + txPending.BringToFront(); + } + + + var labelHash = new Label + { + Text = "Hash: " + hash.Substring(0, 10) + "..." + hash.Substring(hash.Length - 10), + AutoSize = true, + Location = new Point(10, 25) + }; + + tmpPanel.Controls.Add(labelHash); + tmpPanel.Click += (sender, e) => + { + var psi = new ProcessStartInfo + { + FileName = TXExplorer + hash, + UseShellExecute = true + }; + Process.Start(psi); + }; + foreach (Control c in tmpPanel.Controls) + c.Click += (sender, e) => + { + var psi = new ProcessStartInfo { FileName = TXExplorer + hash, UseShellExecute = true }; Process.Start(psi); }; - foreach (Control c in tmpPanel.Controls) - { - c.Click += (sender, e) => - { - ProcessStartInfo psi = new ProcessStartInfo - { - FileName = TXExplorer + hash, - UseShellExecute = true - }; - Process.Start(psi); - }; - } - tmpControls[i] = tmpPanel; - - - } - groupBoxHistory.Controls.Clear(); - Panel txPanel = new Panel(); - txPanel.Width = groupBoxHistory.Width - SystemInformation.VerticalScrollBarWidth; - txPanel.Controls.AddRange(tmpControls); - txPanel.AutoScroll = true; - txPanel.Dock = DockStyle.Fill; - groupBoxHistory.Controls.Add(txPanel); + tmpControls[i] = tmpPanel; } - #endregion - private void MainForm_Load(object sender, EventArgs e) - { - groupBoxLogin.Left = (this.ClientSize.Width - groupBoxLogin.Width) / 2; - groupBoxLogin.Top = (this.ClientSize.Height - groupBoxLogin.Height) / 2; - pictureBoxLogo.Height = groupBoxLogin.Top - 20; - pictureBoxLogo.Width = pictureBoxLogo.Height; - pictureBoxLogo.Top = 10; - pictureBoxLogo.Left = (this.ClientSize.Width - pictureBoxLogo.Width) / 2; - this.TopMost = true; - textBoxPassword.Focus(); - this.TopMost = false; - } - private async void TestForLogin() - { - string path = "wallet/" + Account + "/master"; - string response = await APIGet(path, true); - JObject resp = JObject.Parse(response); - if (resp["encrypted"].ToString() == "False") - { - JObject mnemonic = JObject.Parse(resp["mnemonic"].ToString()); - string phrase = mnemonic["phrase"].ToString(); - - // Show form to save mnemonic and encrypt wallet - FirstLoginForm firstLoginForm = new FirstLoginForm(phrase, this); - firstLoginForm.ShowDialog(); - firstLoginForm.Dispose(); - } - } - private async void Login_Click(object sender, EventArgs e) - { - LoginButton.Enabled = false; // To prevent double clicking - Password = textBoxPassword.Text; - - string path = "wallet/" + Account + "/unlock"; - string content = "{\"passphrase\": \"" + Password + "\",\"timeout\": 60}"; - - string response = await APIPost(path, true, content); - if (response == "Error") - { - Password = ""; - NotifyForm notifyForm = new NotifyForm("Incorrect Password"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - LoginButton.Enabled = true; - return; - } - groupBoxDomains.Width = this.Width - groupBoxDomains.Left - 20; - await UpdateBalance(); - await GetTXHistory(); - panelLogin.Hide(); - panelNav.Dock = DockStyle.Left; - panelPortfolio.Show(); - - // Some UI stuff - groupBoxAccount.Top = statusStripMain.Height + 10; - groupBoxDomains.Top = statusStripMain.Height + 10; - groupBoxDomains.Height = this.Height - groupBoxDomains.Top - 40; - buttonReceive.Top = statusStripMain.Height + 10; - buttonSend.Top = buttonReceive.Top + buttonReceive.Height + 10; - buttonRenew.Top = groupBoxAccount.Top + groupBoxAccount.Height + 10; - groupBoxHistory.Top = buttonRenew.Top + buttonRenew.Height + 10; - groupBoxHistory.Height = this.Height - groupBoxHistory.Top - 40; - } - private void MainForm_FormClosing(object sender, FormClosingEventArgs e) - { - // Run taskkill /im "node.exe" /f /t - ProcessStartInfo startInfo = new ProcessStartInfo(); - startInfo.FileName = "taskkill.exe"; - startInfo.Arguments = "/im \"node.exe\" /f /t"; - startInfo.CreateNoWindow = true; - Process.Start(startInfo); - Environment.Exit(0); - } - - private void textBoxPassword_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyValue == 13) - { - Login_Click(sender, e); - e.SuppressKeyPress = true; - } - } - - private async void buttonReceive_Click(object sender, EventArgs e) - { - string path = "wallet/" + Account + "/address"; - string content = "{\"account\": \"default\"}"; - string response = await APIPost(path, true, content); - if (response == "Error") - { - NotifyForm notifyForm = new NotifyForm("Error getting address"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - return; - } - JObject resp = JObject.Parse(response); - string address = resp["address"].ToString(); - - ReceiveForm receiveForm = new ReceiveForm(address, this); - receiveForm.ShowDialog(); - receiveForm.Dispose(); - } - - private void buttonSend_Click(object sender, EventArgs e) - { - SendForm sendForm = new SendForm(Balance, this); - sendForm.ShowDialog(); - sendForm.Dispose(); - } - - private async void buttonRenew_Click(object sender, EventArgs e) - { - Batch[] batches = new Batch[DomainsRenewable.Length]; - for (int i = 0; i < DomainsRenewable.Length; i++) - { - batches[i] = new Batch(DomainsRenewable[i], "RENEW"); - } - - string batchTX = "[" + string.Join(", ", batches.Select(batch => batch.ToString())) + "]"; - string content = "{\"method\": \"sendbatch\",\"params\":[ " + batchTX + "]}"; - string response = await APIPost("", true, content); - - if (response == "Error") - { - AddLog("Error sending renewals"); - NotifyForm notifyForm = new NotifyForm("Error sending renewals"); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - return; - } - - JObject jObject = JObject.Parse(response); - if (jObject["error"].ToString() != "") - { - AddLog("Error: "); - AddLog(jObject["error"].ToString()); - if (jObject["error"].ToString().Contains("Batch output addresses would exceed lookahead")) - { - NotifyForm notifyForm = new NotifyForm("Error: \nBatch output addresses would exceed lookahead\nYour batch might have too many TXs."); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - } - else - { - NotifyForm notifyForm = new NotifyForm("Error: \n" + jObject["error"].ToString()); - notifyForm.ShowDialog(); - notifyForm.Dispose(); - } - return; - } - JObject result = JObject.Parse(jObject["result"].ToString()); - string hash = result["hash"].ToString(); - AddLog("Batch sent with hash: " + hash); - NotifyForm notifyForm2 = new NotifyForm("Renewals sent\nThis might take a while to mine.", "Explorer", TXExplorer + hash); - notifyForm2.ShowDialog(); - notifyForm2.Dispose(); - } + groupBoxHistory.Controls.Clear(); + var txPanel = new Panel(); + txPanel.Width = groupBoxHistory.Width - SystemInformation.VerticalScrollBarWidth; + txPanel.Controls.AddRange(tmpControls); + txPanel.AutoScroll = true; + txPanel.Dock = DockStyle.Fill; + groupBoxHistory.Controls.Add(txPanel); } - public class Batch - { - public string domain { get; } - public string method { get; } - public decimal bid { get; } - public decimal lockup { get; } - public string toAddress { get; } - //public DNS[]? update { get; } - public Batch(string domain, string method) // Normal TXs - { - this.domain = domain; - this.method = method; - bid = 0; - lockup = 0; - toAddress = ""; - //update = null; - } - public Batch(string domain, string method, string toAddress) // Transfers - { - this.domain = domain; - this.method = method; - this.toAddress = toAddress; - bid = 0; - lockup = 0; - //update = null; - } - public Batch(string domain, string method, decimal bid, decimal lockup) // Bids - { - this.domain = domain; - this.method = method; - this.bid = bid; - this.lockup = lockup; - toAddress = ""; - //update = null; - } - // DNS Update not implemented yet - /* - public Batch(string domain, string method, DNS[] update) // DNS Update - { - this.domain = domain; - this.method = method; - this.update = update; - }*/ - public override string ToString() - { - if (method == "BID") - { - return "[\"BID\", \"" + domain + "\", " + bid + ", " + lockup + "]"; - } - else if (method == "TRANSFER") - { - return "[\"TRANSFER\", \"" + domain + "\", \"" + toAddress + "\"]"; - } - /*else if (method == "UPDATE" && update != null) - { - - string records = "{\"records\":[" + string.Join(", ", update.Select(record => record.ToString())) + "]}"; - return "[\"UPDATE\", \"" + domain + "\", " + records + "]"; - - } - else if (method == "UPDATE") - { - return "[\"UPDATE\", \"" + domain + "\", {\"records\":[]}]"; - }*/ - return "[\"" + method + "\", \"" + domain + "\"]"; - } - } + #endregion } + +public class Batch +{ + //public DNS[]? update { get; } + public Batch(string domain, string method) // Normal TXs + { + this.domain = domain; + this.method = method; + bid = 0; + lockup = 0; + toAddress = ""; + //update = null; + } + + public Batch(string domain, string method, string toAddress) // Transfers + { + this.domain = domain; + this.method = method; + this.toAddress = toAddress; + bid = 0; + lockup = 0; + //update = null; + } + + public Batch(string domain, string method, decimal bid, decimal lockup) // Bids + { + this.domain = domain; + this.method = method; + this.bid = bid; + this.lockup = lockup; + toAddress = ""; + //update = null; + } + + public string domain { get; } + public string method { get; } + public decimal bid { get; } + public decimal lockup { get; } + + public string toAddress { get; } + + // DNS Update not implemented yet + /* + public Batch(string domain, string method, DNS[] update) // DNS Update + { + this.domain = domain; + this.method = method; + this.update = update; + + }*/ + public override string ToString() + { + if (method == "BID") + return "[\"BID\", \"" + domain + "\", " + bid + ", " + lockup + "]"; + if (method == "TRANSFER") return "[\"TRANSFER\", \"" + domain + "\", \"" + toAddress + "\"]"; + /*else if (method == "UPDATE" && update != null) + { + + string records = "{\"records\":[" + string.Join(", ", update.Select(record => record.ToString())) + "]}"; + return "[\"UPDATE\", \"" + domain + "\", " + records + "]"; + + } + else if (method == "UPDATE") + { + return "[\"UPDATE\", \"" + domain + "\", {\"records\":[]}]"; + }*/ + return "[\"" + method + "\", \"" + domain + "\"]"; + } +} \ No newline at end of file diff --git a/FireWalletLite/NotifyForm.cs b/FireWalletLite/NotifyForm.cs index 48387d6..eb96e85 100644 --- a/FireWalletLite/NotifyForm.cs +++ b/FireWalletLite/NotifyForm.cs @@ -1,266 +1,249 @@ using System.Diagnostics; using System.Runtime.InteropServices; -namespace FireWallet +namespace FireWallet; + +public partial class NotifyForm : Form { - public partial class NotifyForm : Form + private bool allowClose = true; + private readonly string altLink; + + private readonly string dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + + "\\FireWallet\\"; + + private readonly bool Linkcopy; + private Dictionary theme; + + public NotifyForm(string Message) { - string dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\FireWallet\\"; - Dictionary theme; - string altLink; - bool Linkcopy; - bool allowClose = true; - public NotifyForm(string Message) + InitializeComponent(); + labelmessage.Text = Message; + altLink = ""; + } + + public NotifyForm(string Message, string altText, string altLink) + { + InitializeComponent(); + labelmessage.Text = Message; + buttonALT.Text = altText; + buttonALT.Visible = true; + this.altLink = altLink; + buttonOK.Focus(); + Linkcopy = false; + } + + public NotifyForm(string Message, bool allowClose) + { + InitializeComponent(); + labelmessage.Text = Message; + buttonOK.Focus(); + Linkcopy = false; + buttonOK.Visible = allowClose; + allowClose = allowClose; + } + + public NotifyForm(string Message, string altText, string altLink, bool Linkcopy) + { + InitializeComponent(); + labelmessage.Text = Message; + buttonALT.Text = altText; + buttonALT.Visible = true; + this.altLink = altLink; + buttonOK.Focus(); + this.Linkcopy = Linkcopy; + + if (Linkcopy) + // Small font to fix more data + labelmessage.Font = new Font(labelmessage.Font.FontFamily, 10); + } + + public void CloseNotification() + { + Close(); + } + + private void NotifyForm_Load(object sender, EventArgs e) + { + UpdateTheme(); + } + + private void OK_Click(object sender, EventArgs e) + { + allowClose = true; + Close(); + } + + private void buttonALT_Click(object sender, EventArgs e) + { + if (Linkcopy) { - InitializeComponent(); - labelmessage.Text = Message; - altLink = ""; - } - public void CloseNotification() - { - this.Close(); - } - public NotifyForm(string Message, string altText, string altLink) - { - InitializeComponent(); - labelmessage.Text = Message; - buttonALT.Text = altText; - buttonALT.Visible = true; - this.altLink = altLink; - buttonOK.Focus(); - Linkcopy = false; - } - public NotifyForm(string Message, bool allowClose) - { - InitializeComponent(); - labelmessage.Text = Message; - buttonOK.Focus(); - Linkcopy = false; - buttonOK.Visible = allowClose; - allowClose = allowClose; + // Copy link to clipboard + Clipboard.SetText(altLink); + return; } - public NotifyForm(string Message, string altText, string altLink, bool Linkcopy) + // Open link + var psi = new ProcessStartInfo { - InitializeComponent(); - labelmessage.Text = Message; - buttonALT.Text = altText; - buttonALT.Visible = true; - this.altLink = altLink; - buttonOK.Focus(); - this.Linkcopy = Linkcopy; + FileName = altLink, + UseShellExecute = true + }; + Process.Start(psi); + } - if (Linkcopy) - { - // Small font to fix more data - labelmessage.Font = new Font(labelmessage.Font.FontFamily, 10); - } + private void NotifyForm_FormClosing(object sender, FormClosingEventArgs e) + { + if (!allowClose) e.Cancel = true; + } + + #region Theming + + private void UpdateTheme() + { + // Check if file exists + if (!Directory.Exists(dir)) CreateConfig(dir); + if (!File.Exists(dir + "theme.txt")) CreateConfig(dir); + + // Read file + var sr = new StreamReader(dir + "theme.txt"); + theme = new Dictionary(); + while (!sr.EndOfStream) + { + var line = sr.ReadLine(); + var split = line.Split(':'); + theme.Add(split[0].Trim(), split[1].Trim()); } - #region Theming - private void UpdateTheme() + sr.Dispose(); + + if (!theme.ContainsKey("background") || !theme.ContainsKey("background-alt") || + !theme.ContainsKey("foreground") || !theme.ContainsKey("foreground-alt")) return; + + // Apply theme + BackColor = ColorTranslator.FromHtml(theme["background"]); + + // Foreground + ForeColor = ColorTranslator.FromHtml(theme["foreground"]); + + + // Need to specify this for each groupbox to override the black text + foreach (Control c in Controls) ThemeControl(c); + + + // Transparancy + applyTransparency(theme); + } + + private void ThemeControl(Control c) + { + if (c.GetType() == typeof(GroupBox) || c.GetType() == typeof(Panel)) { - // Check if file exists - if (!Directory.Exists(dir)) - { - CreateConfig(dir); - } - if (!File.Exists(dir + "theme.txt")) - { - CreateConfig(dir); - } - - // Read file - StreamReader sr = new StreamReader(dir + "theme.txt"); - theme = new Dictionary(); - while (!sr.EndOfStream) - { - string line = sr.ReadLine(); - string[] split = line.Split(':'); - theme.Add(split[0].Trim(), split[1].Trim()); - } - sr.Dispose(); - - if (!theme.ContainsKey("background") || !theme.ContainsKey("background-alt") || !theme.ContainsKey("foreground") || !theme.ContainsKey("foreground-alt")) - { - return; - } - - // Apply theme - this.BackColor = ColorTranslator.FromHtml(theme["background"]); - - // Foreground - this.ForeColor = ColorTranslator.FromHtml(theme["foreground"]); - - - // Need to specify this for each groupbox to override the black text - foreach (Control c in Controls) - { - ThemeControl(c); - } - - - - - // Transparancy - applyTransparency(theme); - - - } - private void ThemeControl(Control c) - { - if (c.GetType() == typeof(GroupBox) || c.GetType() == typeof(Panel)) - { - c.ForeColor = ColorTranslator.FromHtml(theme["foreground"]); - foreach (Control sub in c.Controls) - { - ThemeControl(sub); - } - } - if (c.GetType() == typeof(TextBox) || c.GetType() == typeof(Button) - || c.GetType() == typeof(ComboBox) || c.GetType() == typeof(StatusStrip)) - { - c.ForeColor = ColorTranslator.FromHtml(theme["foreground-alt"]); - c.BackColor = ColorTranslator.FromHtml(theme["background-alt"]); - } + c.ForeColor = ColorTranslator.FromHtml(theme["foreground"]); + foreach (Control sub in c.Controls) ThemeControl(sub); } - private void applyTransparency(Dictionary theme) + if (c.GetType() == typeof(TextBox) || c.GetType() == typeof(Button) + || c.GetType() == typeof(ComboBox) || c.GetType() == typeof(StatusStrip)) { - if (theme.ContainsKey("transparent-mode")) - { - switch (theme["transparent-mode"]) - { - case "mica": - var accent = new AccentPolicy { AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND }; - var accentStructSize = Marshal.SizeOf(accent); - var accentPtr = Marshal.AllocHGlobal(accentStructSize); - Marshal.StructureToPtr(accent, accentPtr, false); - var data = new WindowCompositionAttributeData - { - Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY, - SizeOfData = accentStructSize, - Data = accentPtr - }; - User32.SetWindowCompositionAttribute(Handle, ref data); - Marshal.FreeHGlobal(accentPtr); - break; - case "key": - if (theme.ContainsKey("transparency-key")) - { - switch (theme["transparency-key"]) - { - case "alt": - this.TransparencyKey = ColorTranslator.FromHtml(theme["background-alt"]); - break; - case "main": - this.TransparencyKey = ColorTranslator.FromHtml(theme["background"]); - break; - default: - this.TransparencyKey = ColorTranslator.FromHtml(theme["transparency-key"]); - break; - } - } - break; - case "percent": - if (theme.ContainsKey("transparency-percent")) - { - Opacity = Convert.ToDouble(theme["transparency-percent"]) / 100; - } - break; - } - } - } - - private void CreateConfig(string dir) - { - if (!Directory.Exists(dir)) - { - Directory.CreateDirectory(dir); - } - StreamWriter sw = new StreamWriter(dir + "theme.txt"); - sw.WriteLine("background: #000000"); - sw.WriteLine("foreground: #8e05c2"); - sw.WriteLine("background-alt: #3e065f"); - sw.WriteLine("foreground-alt: #ffffff"); - sw.WriteLine("transparent-mode: off"); - sw.WriteLine("transparency-key: main"); - sw.WriteLine("transparency-percent: 90"); - - sw.Dispose(); - - } - - // Required for mica effect - internal enum AccentState - { - ACCENT_DISABLED = 0, - ACCENT_ENABLE_GRADIENT = 1, - ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, - ACCENT_ENABLE_BLURBEHIND = 3, - ACCENT_INVALID_STATE = 4 - } - - internal enum WindowCompositionAttribute - { - WCA_ACCENT_POLICY = 19 - } - - [StructLayout(LayoutKind.Sequential)] - internal struct AccentPolicy - { - public AccentState AccentState; - public int AccentFlags; - public int GradientColor; - public int AnimationId; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct WindowCompositionAttributeData - { - public WindowCompositionAttribute Attribute; - public IntPtr Data; - public int SizeOfData; - } - - internal static class User32 - { - [DllImport("user32.dll")] - internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data); - } - #endregion - - private void NotifyForm_Load(object sender, EventArgs e) - { - UpdateTheme(); - } - - private void OK_Click(object sender, EventArgs e) - { - allowClose = true; - this.Close(); - } - - private void buttonALT_Click(object sender, EventArgs e) - { - if (Linkcopy) - { - // Copy link to clipboard - Clipboard.SetText(altLink); - return; - } - // Open link - ProcessStartInfo psi = new ProcessStartInfo - { - FileName = altLink, - UseShellExecute = true - }; - Process.Start(psi); - } - - private void NotifyForm_FormClosing(object sender, FormClosingEventArgs e) - { - if (!allowClose) e.Cancel = true; + c.ForeColor = ColorTranslator.FromHtml(theme["foreground-alt"]); + c.BackColor = ColorTranslator.FromHtml(theme["background-alt"]); } } -} + + private void applyTransparency(Dictionary theme) + { + if (theme.ContainsKey("transparent-mode")) + switch (theme["transparent-mode"]) + { + case "mica": + var accent = new AccentPolicy { AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND }; + var accentStructSize = Marshal.SizeOf(accent); + var accentPtr = Marshal.AllocHGlobal(accentStructSize); + Marshal.StructureToPtr(accent, accentPtr, false); + var data = new WindowCompositionAttributeData + { + Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY, + SizeOfData = accentStructSize, + Data = accentPtr + }; + User32.SetWindowCompositionAttribute(Handle, ref data); + Marshal.FreeHGlobal(accentPtr); + break; + case "key": + if (theme.ContainsKey("transparency-key")) + switch (theme["transparency-key"]) + { + case "alt": + TransparencyKey = ColorTranslator.FromHtml(theme["background-alt"]); + break; + case "main": + TransparencyKey = ColorTranslator.FromHtml(theme["background"]); + break; + default: + TransparencyKey = ColorTranslator.FromHtml(theme["transparency-key"]); + break; + } + + break; + case "percent": + if (theme.ContainsKey("transparency-percent")) + Opacity = Convert.ToDouble(theme["transparency-percent"]) / 100; + break; + } + } + + private void CreateConfig(string dir) + { + if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); + var sw = new StreamWriter(dir + "theme.txt"); + sw.WriteLine("background: #000000"); + sw.WriteLine("foreground: #8e05c2"); + sw.WriteLine("background-alt: #3e065f"); + sw.WriteLine("foreground-alt: #ffffff"); + sw.WriteLine("transparent-mode: off"); + sw.WriteLine("transparency-key: main"); + sw.WriteLine("transparency-percent: 90"); + + sw.Dispose(); + } + + // Required for mica effect + internal enum AccentState + { + ACCENT_DISABLED = 0, + ACCENT_ENABLE_GRADIENT = 1, + ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, + ACCENT_ENABLE_BLURBEHIND = 3, + ACCENT_INVALID_STATE = 4 + } + + internal enum WindowCompositionAttribute + { + WCA_ACCENT_POLICY = 19 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct AccentPolicy + { + public AccentState AccentState; + public int AccentFlags; + public int GradientColor; + public int AnimationId; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct WindowCompositionAttributeData + { + public WindowCompositionAttribute Attribute; + public IntPtr Data; + public int SizeOfData; + } + + internal static class User32 + { + [DllImport("user32.dll")] + internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data); + } + + #endregion +} \ No newline at end of file diff --git a/FireWalletLite/Program.cs b/FireWalletLite/Program.cs index 499ca71..f18eba4 100644 --- a/FireWalletLite/Program.cs +++ b/FireWalletLite/Program.cs @@ -1,17 +1,16 @@ -namespace FireWalletLite +namespace FireWalletLite; + +internal static class Program { - internal static class Program + /// + /// The main entry point for the application. + /// + [STAThread] + private static void Main() { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - // To customize application configuration such as set high DPI settings or default font, - // see https://aka.ms/applicationconfiguration. - ApplicationConfiguration.Initialize(); - Application.Run(new Loader()); - } + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new Loader()); } } \ No newline at end of file diff --git a/FireWalletLite/ReceiveForm.cs b/FireWalletLite/ReceiveForm.cs index 4631bd0..4367df3 100644 --- a/FireWalletLite/ReceiveForm.cs +++ b/FireWalletLite/ReceiveForm.cs @@ -1,42 +1,39 @@ using QRCoder; -namespace FireWalletLite +namespace FireWalletLite; + +public partial class ReceiveForm : Form { - public partial class ReceiveForm : Form + private readonly string address; + private MainForm main; + + public ReceiveForm(string address, MainForm main) { - string address; - MainForm main; - public ReceiveForm(string address, MainForm main) - { - InitializeComponent(); - this.address = address; - this.main = main; - // Theme form - this.BackColor = ColorTranslator.FromHtml(main.Theme["background"]); - this.ForeColor = ColorTranslator.FromHtml(main.Theme["foreground"]); - foreach (Control control in Controls) - { - main.ThemeControl(control); - } - textBoxReceive.Text = address; - textBoxReceive.Left = (this.ClientSize.Width - textBoxReceive.Width) / 2; - label1.Left = (this.ClientSize.Width - label1.Width) / 2; - buttonCopy.Left = (this.ClientSize.Width - buttonCopy.Width) / 2; + InitializeComponent(); + this.address = address; + this.main = main; + // Theme form + BackColor = ColorTranslator.FromHtml(main.Theme["background"]); + ForeColor = ColorTranslator.FromHtml(main.Theme["foreground"]); + foreach (Control control in Controls) main.ThemeControl(control); + textBoxReceive.Text = address; + textBoxReceive.Left = (ClientSize.Width - textBoxReceive.Width) / 2; + label1.Left = (ClientSize.Width - label1.Width) / 2; + buttonCopy.Left = (ClientSize.Width - buttonCopy.Width) / 2; - - QRCodeGenerator qrcode = new QRCodeGenerator(); - QRCodeData qrData = qrcode.CreateQrCode(address, QRCodeGenerator.ECCLevel.Q); - QRCode qrCode = new QRCode(qrData); - pictureBoxReceiveQR.Image = qrCode.GetGraphic(20, main.Theme["foreground"], main.Theme["background"]); - pictureBoxReceiveQR.SizeMode = PictureBoxSizeMode.Zoom; - pictureBoxReceiveQR.Width = this.ClientSize.Width / 2; - pictureBoxReceiveQR.Height = this.ClientSize.Width / 2; - pictureBoxReceiveQR.Left = (this.ClientSize.Width - pictureBoxReceiveQR.Width) / 2; - } - private void buttonCopy_Click(object sender, EventArgs e) - { - Clipboard.SetText(address); - } + var qrcode = new QRCodeGenerator(); + var qrData = qrcode.CreateQrCode(address, QRCodeGenerator.ECCLevel.Q); + var qrCode = new QRCode(qrData); + pictureBoxReceiveQR.Image = qrCode.GetGraphic(20, main.Theme["foreground"], main.Theme["background"]); + pictureBoxReceiveQR.SizeMode = PictureBoxSizeMode.Zoom; + pictureBoxReceiveQR.Width = ClientSize.Width / 2; + pictureBoxReceiveQR.Height = ClientSize.Width / 2; + pictureBoxReceiveQR.Left = (ClientSize.Width - pictureBoxReceiveQR.Width) / 2; } -} + + private void buttonCopy_Click(object sender, EventArgs e) + { + Clipboard.SetText(address); + } +} \ No newline at end of file diff --git a/FireWalletLite/SendForm.cs b/FireWalletLite/SendForm.cs index 7cf33f4..66ff7a7 100644 --- a/FireWalletLite/SendForm.cs +++ b/FireWalletLite/SendForm.cs @@ -1,106 +1,102 @@ using FireWallet; using Newtonsoft.Json.Linq; -namespace FireWalletLite +namespace FireWalletLite; + +public partial class SendForm : Form { - public partial class SendForm : Form + private readonly int fee = 1; + private readonly MainForm main; + private readonly decimal unlockedbalance; + + public SendForm(decimal Unlockedbalance, MainForm main) { - int fee = 1; - decimal unlockedbalance; - MainForm main; - public SendForm(decimal Unlockedbalance, MainForm main) - { - InitializeComponent(); - this.main = main; - this.unlockedbalance = Unlockedbalance; + InitializeComponent(); + this.main = main; + unlockedbalance = Unlockedbalance; - // Theme form - this.BackColor = ColorTranslator.FromHtml(main.Theme["background"]); - this.ForeColor = ColorTranslator.FromHtml(main.Theme["foreground"]); - foreach (Control control in Controls) - { - main.ThemeControl(control); - } + // Theme form + BackColor = ColorTranslator.FromHtml(main.Theme["background"]); + ForeColor = ColorTranslator.FromHtml(main.Theme["foreground"]); + foreach (Control control in Controls) main.ThemeControl(control); - labelMax.Text = "Max: " + (unlockedbalance - fee).ToString() + " HNS"; - if (unlockedbalance < fee) - { - labelMax.Text = "Max: 0 HNS"; - //buttonSend.Enabled = false; - } - - // Allign controls - labelAddress.Left = (this.ClientSize.Width - labelAddress.Width) / 2; - labelAmount.Left = (this.ClientSize.Width - labelAmount.Width) / 2; - textBoxAddress.Left = (this.ClientSize.Width - textBoxAddress.Width) / 2; - labelMax.Left = (this.ClientSize.Width - labelMax.Width) / 2; - textBoxAmount.Left = (this.ClientSize.Width - textBoxAmount.Width - labelHNSToken.Width - 10) / 2; - labelHNSToken.Left = textBoxAmount.Left + textBoxAmount.Width + 10; - buttonSend.Left = (this.ClientSize.Width - buttonSend.Width) / 2; - } - - private async void buttonSend_Click(object sender, EventArgs e) - { - buttonSend.Enabled = false; - string address = textBoxAddress.Text; - if (textBoxAddress.Text.Substring(0,1) == "@") - { - // HIP-02 not supported yet - NotifyForm notify = new NotifyForm("HIP-02 not supported yet"); - notify.ShowDialog(); - notify.Dispose(); - buttonSend.Enabled = true; - return; - } - bool valid = await main.ValidAddress(address); - if (!valid) - { - NotifyForm notify = new NotifyForm("Invalid address"); - notify.ShowDialog(); - notify.Dispose(); - buttonSend.Enabled = true; - return; - } - - decimal amount = 0; - if (!decimal.TryParse(textBoxAmount.Text, out amount)) - { - NotifyForm notify = new NotifyForm("Invalid amount"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - if (amount > unlockedbalance - fee) - { - NotifyForm notify = new NotifyForm("Insufficient balance"); - notify.ShowDialog(); - notify.Dispose(); - return; - } - - string content = "{\"method\": \"sendtoaddress\",\"params\": [ \"" + address + "\", " + - amount.ToString() + "]}"; - string output = await main.APIPost("", true, content); - JObject APIresp = JObject.Parse(output); - if (APIresp["error"].ToString() != "") - { - main.AddLog("Failed:"); - main.AddLog(APIresp.ToString()); - JObject error = JObject.Parse(APIresp["error"].ToString()); - string ErrorMessage = error["message"].ToString(); - - NotifyForm notify = new NotifyForm("Error Transaction Failed\n" + ErrorMessage); - notify.ShowDialog(); - notify.Dispose(); - return; - } - string hash = APIresp["result"].ToString(); - string link = main.TXExplorer + hash; - NotifyForm notifySuccess = new NotifyForm("Transaction Sent\nThis transaction could take up to 20 minutes to mine", - "Explorer", link); - notifySuccess.ShowDialog(); - notifySuccess.Dispose(); - this.Close(); - } + labelMax.Text = "Max: " + (unlockedbalance - fee) + " HNS"; + if (unlockedbalance < fee) labelMax.Text = "Max: 0 HNS"; + //buttonSend.Enabled = false; + // Allign controls + labelAddress.Left = (ClientSize.Width - labelAddress.Width) / 2; + labelAmount.Left = (ClientSize.Width - labelAmount.Width) / 2; + textBoxAddress.Left = (ClientSize.Width - textBoxAddress.Width) / 2; + labelMax.Left = (ClientSize.Width - labelMax.Width) / 2; + textBoxAmount.Left = (ClientSize.Width - textBoxAmount.Width - labelHNSToken.Width - 10) / 2; + labelHNSToken.Left = textBoxAmount.Left + textBoxAmount.Width + 10; + buttonSend.Left = (ClientSize.Width - buttonSend.Width) / 2; } -} + + private async void buttonSend_Click(object sender, EventArgs e) + { + buttonSend.Enabled = false; + var address = textBoxAddress.Text; + if (textBoxAddress.Text.Substring(0, 1) == "@") + { + // HIP-02 not supported yet + var notify = new NotifyForm("HIP-02 not supported yet"); + notify.ShowDialog(); + notify.Dispose(); + buttonSend.Enabled = true; + return; + } + + var valid = await main.ValidAddress(address); + if (!valid) + { + var notify = new NotifyForm("Invalid address"); + notify.ShowDialog(); + notify.Dispose(); + buttonSend.Enabled = true; + return; + } + + decimal amount = 0; + if (!decimal.TryParse(textBoxAmount.Text, out amount)) + { + var notify = new NotifyForm("Invalid amount"); + notify.ShowDialog(); + notify.Dispose(); + return; + } + + if (amount > unlockedbalance - fee) + { + var notify = new NotifyForm("Insufficient balance"); + notify.ShowDialog(); + notify.Dispose(); + return; + } + + var content = "{\"method\": \"sendtoaddress\",\"params\": [ \"" + address + "\", " + + amount + "]}"; + var output = await main.APIPost("", true, content); + var APIresp = JObject.Parse(output); + if (APIresp["error"].ToString() != "") + { + main.AddLog("Failed:"); + main.AddLog(APIresp.ToString()); + var error = JObject.Parse(APIresp["error"].ToString()); + var ErrorMessage = error["message"].ToString(); + + var notify = new NotifyForm("Error Transaction Failed\n" + ErrorMessage); + notify.ShowDialog(); + notify.Dispose(); + return; + } + + var hash = APIresp["result"].ToString(); + var link = main.TXExplorer + hash; + var notifySuccess = new NotifyForm("Transaction Sent\nThis transaction could take up to 20 minutes to mine", + "Explorer", link); + notifySuccess.ShowDialog(); + notifySuccess.Dispose(); + Close(); + } +} \ No newline at end of file diff --git a/FireWalletLite/SplashScreen.cs b/FireWalletLite/SplashScreen.cs index f49859b..022aac3 100644 --- a/FireWalletLite/SplashScreen.cs +++ b/FireWalletLite/SplashScreen.cs @@ -1,96 +1,104 @@ using System.Diagnostics; using System.Drawing.Imaging; +namespace FireWallet; -namespace FireWallet +public partial class SplashScreen : Form { - public partial class SplashScreen : Form - { - public SplashScreen(bool timer) - { - InitializeComponent(); - close = false; - IsClosed = false; - } - bool close; - float opacity = 0.0f; - private void SplashScreen_FormClosing(object sender, FormClosingEventArgs e) - { - if (!close) - { - e.Cancel = true; - } - } - public bool IsClosed { get; set; } - public void CloseSplash() - { - close = true; + private bool close; + private float opacity; + private Bitmap splash; - // Fade out - timerIn.Stop(); - timerOut.Start(); - } - private void label2_Click(object sender, EventArgs e) + public SplashScreen(bool timer) + { + InitializeComponent(); + close = false; + IsClosed = false; + } + + public bool IsClosed { get; set; } + + private void SplashScreen_FormClosing(object sender, FormClosingEventArgs e) + { + if (!close) e.Cancel = true; + } + + public void CloseSplash() + { + close = true; + + // Fade out + timerIn.Stop(); + timerOut.Start(); + } + + private void label2_Click(object sender, EventArgs e) + { + var psi = new ProcessStartInfo { - ProcessStartInfo psi = new ProcessStartInfo + FileName = "https://nathan.woodburn.au", + UseShellExecute = true + }; + Process.Start(psi); + } + + //new Bitmap(Properties.Resources.FWSplash); + private void SplashScreen_Load(object sender, EventArgs e) + { + splash = pictureBoxNew.Image as Bitmap; + pictureBoxNew.Visible = true; + TransparencyKey = Color.FromArgb(0, 0, 0); + pictureBoxNew.Invalidate(); + } + + public Image SetImageOpacity(Image image, float opacity) + { + try + { + var bmp = new Bitmap(image.Width, image.Height); + using (var gfx = Graphics.FromImage(bmp)) { - FileName = "https://nathan.woodburn.au", - UseShellExecute = true - }; - Process.Start(psi); - } - Bitmap splash; - //new Bitmap(Properties.Resources.FWSplash); - private void SplashScreen_Load(object sender, EventArgs e) - { - splash = pictureBoxNew.Image as Bitmap; - pictureBoxNew.Visible = true; - this.TransparencyKey = Color.FromArgb(0, 0, 0); - pictureBoxNew.Invalidate(); - } - public Image SetImageOpacity(Image image, float opacity) - { - try - { - Bitmap bmp = new Bitmap(image.Width, image.Height); - using (Graphics gfx = Graphics.FromImage(bmp)) - { - ColorMatrix matrix = new ColorMatrix(); - matrix.Matrix33 = opacity; - ImageAttributes attributes = new ImageAttributes(); - attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); - gfx.DrawImage(image, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); - } - return bmp; - } - catch - { - return null; + var matrix = new ColorMatrix(); + matrix.Matrix33 = opacity; + var attributes = new ImageAttributes(); + attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); + gfx.DrawImage(image, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, image.Width, image.Height, + GraphicsUnit.Pixel, attributes); } + + return bmp; } - private void timerIn_Tick(object sender, EventArgs e) + catch { - if (opacity >= 1) - { - timerIn.Stop(); - return; - } - opacity += 0.05f; - pictureBoxNew.Image = SetImageOpacity(splash, opacity); - pictureBoxNew.Invalidate(); - } - private void timerOut_Tick(object sender, EventArgs e) - { - if (opacity <= 0) - { - timerOut.Stop(); - IsClosed = true; - this.Close(); - return; - } - opacity -= 0.05f; - pictureBoxNew.Image = SetImageOpacity(splash, opacity); - pictureBoxNew.Invalidate(); + return null; } } -} + + private void timerIn_Tick(object sender, EventArgs e) + { + if (opacity >= 1) + { + timerIn.Stop(); + return; + } + + opacity += 0.05f; + pictureBoxNew.Image = SetImageOpacity(splash, opacity); + pictureBoxNew.Invalidate(); + } + + private void timerOut_Tick(object sender, EventArgs e) + { + if (opacity <= 0) + { + timerOut.Stop(); + IsClosed = true; + Close(); + return; + } + + opacity -= 0.05f; + pictureBoxNew.Image = SetImageOpacity(splash, opacity); + pictureBoxNew.Invalidate(); + } +} \ No newline at end of file