FireWallet/FireWallet/MainForm.cs

1037 lines
39 KiB
C#

using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Security.Policy;
using System.Windows.Forms;
using Newtonsoft.Json.Linq;
using Point = System.Drawing.Point;
using Size = System.Drawing.Size;
using IronBarCode;
using static System.Windows.Forms.DataFormats;
namespace FireWallet
{
public partial class MainForm : Form
{
#region Variables
string dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\FireWallet\\";
Dictionary<string, string> nodeSettings;
Dictionary<string, string> userSettings;
Dictionary<string, string> theme;
int Network;
string account;
string password;
decimal balance;
decimal balanceLocked;
int screen; // 0 = login, 1 = portfolio
int height;
double syncProgress;
int pendingTransactions;
#endregion
#region Application
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
UpdateTheme();
LoadNode();
LoadSettings();
// Edit the theme of the navigation panel
panelNav.BackColor = ColorTranslator.FromHtml(theme["background-alt"]);
panelNav.ForeColor = ColorTranslator.FromHtml(theme["foreground-alt"]);
foreach (Control c in panelNav.Controls)
{
c.BackColor = ColorTranslator.FromHtml(theme["background"]);
c.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
}
panelNav.Dock = DockStyle.Left;
ResizeForm();
panelNav.Visible = false;
screen = 0;
// Prompt for login
GetAccounts();
AddLog("Loaded");
}
private void MainForm_Closing(object sender, FormClosingEventArgs e)
{
AddLog("Closing");
}
#endregion
#region Settings
private void LoadNode()
{
if (!File.Exists(dir + "node.txt"))
{
NodeForm cf = new NodeForm();
cf.ShowDialog();
// Initial run
}
if (!File.Exists(dir + "node.txt"))
{
AddLog("Node setup failed");
this.Close();
return;
}
StreamReader sr = new StreamReader(dir + "node.txt");
nodeSettings = new Dictionary<string, string>();
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
string[] split = line.Split(':');
nodeSettings.Add(split[0].Trim(), split[1].Trim());
}
sr.Dispose();
if (!nodeSettings.ContainsKey("Network") || !nodeSettings.ContainsKey("Key") || !nodeSettings.ContainsKey("IP"))
{
AddLog("Node Settings file is missing key");
this.Close();
return;
}
Network = Convert.ToInt32(nodeSettings["Network"]);
switch (Network)
{
case 0:
toolStripStatusLabelNetwork.Text = "Network: Mainnet";
break;
case 1:
toolStripStatusLabelNetwork.Text = "Network: Regtest";
break;
case 2:
toolStripStatusLabelNetwork.Text = "Network: Testnet";
break;
}
NodeStatus();
}
private void LoadSettings()
{
if (!File.Exists(dir + "settings.txt"))
{
AddLog("Creating settings file");
StreamWriter sw = new StreamWriter(dir + "settings.txt");
sw.WriteLine("explorer-tx: https://niami.io/tx/");
sw.WriteLine("explorer-addr: https://niami.io/address/");
sw.WriteLine("explorer-block: https://niami.io/block/");
sw.WriteLine("explorer-domain: https://niami.io/domain/");
sw.WriteLine("confirmations: 1");
sw.Dispose();
}
StreamReader sr = new StreamReader(dir + "settings.txt");
userSettings = new Dictionary<string, string>();
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
userSettings.Add(line.Substring(0, line.IndexOf(":")).Trim(), line.Substring(line.IndexOf(":") + 1).Trim());
}
sr.Dispose();
}
#endregion
#region Logging
public void AddLog(string message)
{
StreamWriter sw = new StreamWriter(dir + "log.txt", true);
sw.WriteLine(DateTime.Now.ToString() + ": " + message);
sw.Dispose();
}
#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
StreamReader sr = new StreamReader(dir + "theme.txt");
theme = new Dictionary<string, string>();
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;
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.GetType() == typeof(ToolStrip))
{
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 applyTransparency(Dictionary<string, string> 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":
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;
}
}
else
{
AddLog("No transparency-key found in theme file");
}
break;
case "percent":
if (theme.ContainsKey("transparency-percent"))
{
Opacity = Convert.ToDouble(theme["transparency-percent"]) / 100;
}
else
{
AddLog("No transparency-percent found in theme file");
}
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.WriteLine("selected-bg: #000000");
sw.WriteLine("selected-fg: #ffffff");
sw.WriteLine("error: #ff0000");
sw.Dispose();
AddLog("Created theme file");
}
// 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);
}
private void Form1_Resize(object sender, EventArgs e)
{
ResizeForm();
}
private void ResizeForm()
{
groupBoxaccount.Left = (this.ClientSize.Width - groupBoxaccount.Width) / 2;
groupBoxaccount.Top = (this.ClientSize.Height - groupBoxaccount.Height) / 2;
}
#endregion
#region Accounts
private async void GetAccounts()
{
string APIresponse = await APIGet("wallet", true);
comboBoxaccount.Items.Clear();
if (APIresponse != "Error")
{
JArray jArray = JArray.Parse(APIresponse);
foreach (string account in jArray)
{
comboBoxaccount.Items.Add(account);
}
if (comboBoxaccount.Items.Count > 0)
{
comboBoxaccount.SelectedIndex = 0;
}
else
{
comboBoxaccount.Items.Add("No accounts found");
comboBoxaccount.Enabled = false;
}
}
else
{
comboBoxaccount.Items.Add("No accounts found");
comboBoxaccount.Enabled = false;
}
textBoxaccountpassword.Focus();
}
private async Task<bool> Login()
{
string path = "wallet/" + account + "/unlock";
string content = "{\"passphrase\": \"" + password + "\",\"timeout\": 60}";
string APIresponse = await APIPost(path, true, content);
if (!APIresponse.Contains("true"))
{
AddLog("Login failed");
NotifyForm notifyForm = new NotifyForm("Login Failed\nMake sure your password is correct");
notifyForm.ShowDialog();
notifyForm.Dispose();
return false;
}
path = "";
content = "{\"method\": \"selectwallet\",\"params\":[ \"" + account + "\"]}";
APIresponse = await APIPost(path, true, content);
if (!APIresponse.Contains("\"error\":null"))
{
AddLog("Wallet selection failed");
NotifyForm notifyForm = new NotifyForm("Wallet selection failed\n" + APIresponse);
notifyForm.ShowDialog();
notifyForm.Dispose();
return false;
}
UpdateBalance();
return true;
}
private async void LoginClick(object sender, EventArgs e)
{
account = comboBoxaccount.Text;
password = textBoxaccountpassword.Text;
bool loggedin = await Login();
if (loggedin)
{
toolStripStatusLabelaccount.Text = "Account: " + account;
textBoxaccountpassword.Text = "";
panelaccount.Visible = false;
toolStripSplitButtonlogout.Visible = true;
panelNav.Visible = true;
screen = 1;
buttonNavPortfolio.PerformClick();
}
}
private void PasswordEntered(object sender, KeyEventArgs e)
{
if (e.KeyValue == 13)
{
LoginClick(sender, e);
}
}
private void AccountChoose(object sender, EventArgs e)
{
textBoxaccountpassword.Focus();
}
private async void Logout(object sender, EventArgs e)
{
toolStripSplitButtonlogout.Visible = false;
string path = "wallet/" + account + "/lock";
string content = "";
string APIresponse = await APIPost(path, true, content);
if (!APIresponse.Contains("true"))
{
AddLog("Logout failed");
NotifyForm notifyForm = new NotifyForm("Logout Failed\n" + APIresponse);
notifyForm.ShowDialog();
notifyForm.Dispose();
panelaccount.Visible = true;
return;
}
panelaccount.Visible = true;
panelNav.Visible = false;
panelSend.Visible = false;
panelRecieve.Visible = false;
panelDomains.Visible = false;
panelPortfolio.Visible = false;
toolStripStatusLabelaccount.Text = "Account: Not Logged In";
screen = 0;
textBoxaccountpassword.Focus();
}
#endregion
#region API
HttpClient httpClient = new HttpClient();
private async void NodeStatus()
{
if (await APIGet("", false) == "Error")
{
toolStripStatusLabelstatus.Text = "Status: Node Not Connected";
}
else
{
toolStripStatusLabelstatus.Text = "Status: Node Connected";
}
}
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;
balanceLocked = locked;
}
/// <summary>
/// Post to HSD API
/// </summary>
/// <param name="path">Path to post to</param>
/// <param name="wallet">Whether to use port 12039</param>
/// <param name="content">Content to post</param>
/// <returns></returns>
private async Task<string> APIPost(string path, bool wallet, string content)
{
string key = nodeSettings["Key"];
string ip = nodeSettings["IP"];
string port = "1203";
if (Network == 1)
{
port = "1303";
}
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
HttpResponseMessage resp = await httpClient.SendAsync(req);
try
{
resp.EnsureSuccessStatusCode();
}
catch (Exception ex)
{
AddLog("Post Error: " + ex.Message);
return "Error";
}
return await resp.Content.ReadAsStringAsync();
}
/// <summary>
/// Get from HSD API
/// </summary>
/// <param name="path">Path to get</param>
/// <param name="wallet">Whether to use port 12039</param>
/// <returns></returns>
private async Task<string> APIGet(string path, bool wallet)
{
string key = nodeSettings["Key"];
string ip = nodeSettings["IP"];
string port = "1203";
if (Network == 1)
{
port = "1303";
}
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);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
// Log errors to log textbox
catch (Exception ex)
{
AddLog("Get Error: " + ex.Message);
return "Error";
}
}
private async Task<string> GetAddress()
{
string content = "{\"account\":\"default\"}";
string path = "wallet/" + account + "/address";
string APIresponse = await APIPost(path, true, content);
if (APIresponse == "Error")
{
AddLog("GetAddress Error");
return "Error";
}
JObject resp = JObject.Parse(APIresponse);
return resp["address"].ToString();
}
private async void GetTXHistory()
{
// Get height and progress
String APIresponse = await APIGet("", false);
JObject resp = JObject.Parse(APIresponse);
JObject chain = JObject.Parse(resp["chain"].ToString());
labelHeight.Text = "Height: " + chain["height"].ToString();
decimal progress = Convert.ToDecimal(chain["progress"].ToString());
labelSyncPercent.Text = "Sync: " + decimal.Round(progress * 100, 2) + "%";
// Get Unconfirmed TX
string path = "wallet/" + account + "/tx/unconfirmed";
APIresponse = await APIGet(path, true);
if (APIresponse == "Error")
{
AddLog("GetInfo Error");
return;
}
JArray pendingTxs = JArray.Parse(APIresponse);
labelPendingCount.Text = "Unconfirmed TX: " + pendingTxs.Count.ToString();
// Get TX's
APIresponse = await APIGet("wallet/" + account + "/tx/history", true);
if (APIresponse == "Error")
{
AddLog("GetInfo Error");
return;
}
JArray txs = JArray.Parse(APIresponse);
int txCount = txs.Count;
if (txCount > groupBoxTransactions.Height / 55) txCount = (int)Math.Floor(groupBoxTransactions.Height / 55.0);
Control[] tmpControls = new Control[txCount];
for (int i = 0; i < txCount; i++)
{
// Get last tx
JObject tx = JObject.Parse(txs[txs.Count - 1 - i].ToString());
string hash = tx["hash"].ToString();
string date = tx["mdate"].ToString();
Panel tmpPanel = new Panel();
tmpPanel.Width = groupBoxTransactions.Width - 20;
tmpPanel.Height = 50;
tmpPanel.Location = new Point(10, 20 + (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 (userSettings.ContainsKey("confirmations"))
{
if (confirmations < Convert.ToInt32(userSettings["confirmations"]))
{
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),
Font = new Font(this.Font, FontStyle.Underline)
};
labelHash.Click += (sender, e) =>
{
string url = userSettings["explorer-tx"] + hash;
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = url,
UseShellExecute = true
};
Process.Start(psi);
};
tmpPanel.Controls.Add(labelHash);
// Count inputs and outputs
JArray inputs = JArray.Parse(tx["inputs"].ToString());
JArray outputs = JArray.Parse(tx["outputs"].ToString());
int inputCount = inputs.Count;
int outputCount = outputs.Count;
Label labelInputOutput = new Label()
{
Text = "Inputs: " + inputCount + " Outputs: " + outputCount,
AutoSize = true,
Location = new Point(300, 20)
};
tmpPanel.Controls.Add(labelInputOutput);
tmpControls[i] = tmpPanel;
}
groupBoxTransactions.Controls.Clear();
groupBoxTransactions.Controls.AddRange(tmpControls);
}
private async Task<string> GetFee()
{
try
{
string response = await APIGet("fee", false);
JObject resp = JObject.Parse(response);
decimal fee = Convert.ToDecimal(resp["rate"].ToString());
fee = fee / 1000000;
if (fee < 0.0001m) fee = 1;
return fee.ToString();
//return resp["rate"].ToString();
}
catch
{
return "1";
}
}
private async Task<bool> 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;
}
#endregion
#region Timers
private void timerNodeStatus_Tick(object sender, EventArgs e)
{
NodeStatus();
// If logged in, update info
if (panelaccount.Visible == false)
{
GetTXHistory();
}
}
#endregion
#region Nav
private async void PortfolioPanel_Click(object sender, EventArgs e)
{
panelSend.Hide();
panelPortfolio.Show();
panelRecieve.Hide();
panelDomains.Hide();
buttonNavSend.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavSend.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
buttonNavReceive.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavReceive.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
buttonNavDomains.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavDomains.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
await UpdateBalance();
GetTXHistory();
labelBalance.Text = "Available: " + balance.ToString() + " HNS";
labelLocked.Text = "Locked: " + balanceLocked.ToString() + " HNS";
labelBalanceTotal.Text = "Total: " + (balance + balanceLocked).ToString() + " HNS";
if (theme.ContainsKey("selected-bg") && theme.ContainsKey("selected-fg"))
{
buttonNavPortfolio.BackColor = ColorTranslator.FromHtml(theme["selected-bg"]);
buttonNavPortfolio.ForeColor = ColorTranslator.FromHtml(theme["selected-fg"]);
}
}
private async void SendPanel_Click(object sender, EventArgs e)
{
panelPortfolio.Hide();
panelSend.Show();
panelRecieve.Hide();
panelDomains.Hide();
buttonNavPortfolio.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavPortfolio.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
buttonNavReceive.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavReceive.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
buttonNavDomains.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavDomains.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
if (theme.ContainsKey("selected-bg") && theme.ContainsKey("selected-fg"))
{
buttonNavSend.BackColor = ColorTranslator.FromHtml(theme["selected-bg"]);
buttonNavSend.ForeColor = ColorTranslator.FromHtml(theme["selected-fg"]);
}
if (theme.ContainsKey("error"))
{
labelSendingError.ForeColor = ColorTranslator.FromHtml(theme["error"]);
}
labelSendPrompt.Left = (panelSend.Width - labelSendPrompt.Width) / 2;
buttonSendHNS.Left = (panelSend.Width - buttonSendHNS.Width) / 2;
labelSendingTo.Left = (panelSend.Width - labelSendingTo.Width - textBoxSendingTo.Width) / 2;
labelSendingAmount.Left = labelSendingTo.Left;
textBoxSendingTo.Left = labelSendingTo.Left + labelSendingTo.Width + 10;
textBoxSendingAmount.Left = textBoxSendingTo.Left;
labelSendingMax.Left = labelSendingTo.Left;
labelSendingError.Left = textBoxSendingTo.Left + textBoxSendingTo.Width + 10;
labelSendingFee.Left = labelSendingTo.Left;
buttonSendMax.Left = textBoxSendingAmount.Left + textBoxSendingAmount.Width - buttonSendMax.Width;
checkBoxSendSubFee.Left = labelSendingTo.Left;
labelSendingMax.Text = "Max: " + balance.ToString() + " HNS";
textBoxSendingTo.Focus();
string fee = await GetFee();
labelSendingFee.Text = "Est. Fee: " + fee + " HNS";
labelSendingError.Hide();
}
private async void ReceivePanel_Click(object sender, EventArgs e)
{
panelSend.Hide();
panelPortfolio.Hide();
panelRecieve.Show();
panelDomains.Hide();
buttonNavSend.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavSend.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
buttonNavPortfolio.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavPortfolio.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
buttonNavDomains.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavDomains.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
if (theme.ContainsKey("selected-bg") && theme.ContainsKey("selected-fg"))
{
buttonNavReceive.BackColor = ColorTranslator.FromHtml(theme["selected-bg"]);
buttonNavReceive.ForeColor = ColorTranslator.FromHtml(theme["selected-fg"]);
}
labelReceive1.Left = (panelRecieve.Width - labelReceive1.Width) / 2;
labelReceive2.Left = (panelRecieve.Width - labelReceive2.Width) / 2;
textBoxReceiveAddress.Left = (panelRecieve.Width - textBoxReceiveAddress.Width) / 2;
string address = await GetAddress();
textBoxReceiveAddress.Text = address;
textBoxReceiveAddress.TextAlign = HorizontalAlignment.Center;
Size size = TextRenderer.MeasureText(textBoxReceiveAddress.Text, textBoxReceiveAddress.Font);
textBoxReceiveAddress.Width = size.Width + 10;
textBoxReceiveAddress.Left = (panelRecieve.Width - textBoxReceiveAddress.Width) / 2;
GeneratedBarcode Qrcode = QRCodeWriter.CreateQrCode(textBoxReceiveAddress.Text);
pictureBoxReceiveQR.Image = Qrcode.Image;
pictureBoxReceiveQR.SizeMode = PictureBoxSizeMode.Zoom;
pictureBoxReceiveQR.Width = panelRecieve.Width / 3;
pictureBoxReceiveQR.Left = (panelRecieve.Width - pictureBoxReceiveQR.Width) / 2;
}
private void buttonNavDomains_Click(object sender, EventArgs e)
{
panelSend.Hide();
panelPortfolio.Hide();
panelRecieve.Hide();
panelDomains.Show();
buttonNavSend.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavSend.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
buttonNavPortfolio.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavPortfolio.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
buttonNavReceive.BackColor = ColorTranslator.FromHtml(theme["background"]);
buttonNavReceive.ForeColor = ColorTranslator.FromHtml(theme["foreground"]);
if (theme.ContainsKey("selected-bg") && theme.ContainsKey("selected-fg"))
{
buttonNavDomains.BackColor = ColorTranslator.FromHtml(theme["selected-bg"]);
buttonNavDomains.ForeColor = ColorTranslator.FromHtml(theme["selected-fg"]);
}
textBoxDomainSearch.Focus();
}
#endregion
#region Send
private async void textBoxSendingTo_Leave(object sender, EventArgs e)
{
if (textBoxSendingTo.Text == "") return;
if (textBoxSendingTo.Text.Substring(0, 1) == "@")
{
labelSendingError.Show();
labelSendingError.Text = "HIP-02 Not supported yet";
return;
/*
string domain = textBoxSendingTo.Text.Substring(1);
try
{
string address = "";
bool valid = await ValidAddress(address);
if (valid)
{
labelSendingError.Hide();
labelSendingError.Text = "";
}
else
{
labelSendingError.Show();
labelSendingError.Text = "Invalid Address";
}
}
catch (Exception ex)
{
labelSendingError.Show();
labelSendingError.Text = ex.Message;
}*/
}
else
{
try
{
bool valid = await ValidAddress(textBoxSendingTo.Text);
if (valid)
{
labelSendingError.Hide();
labelSendingError.Text = "";
}
else
{
labelSendingError.Show();
labelSendingError.Text = "Invalid Address";
}
}
catch (Exception ex)
{
labelSendingError.Show();
labelSendingError.Text = ex.Message;
}
}
}
private void textBoxSendingAmount_Leave(object sender, EventArgs e)
{
decimal amount = 0;
if (decimal.TryParse(textBoxSendingAmount.Text, out amount))
{
labelSendingError.Hide();
labelSendingError.Text = "";
}
else
{
labelSendingError.Show();
labelSendingError.Text = "Invalid Amount";
}
}
private async void buttonSendMax_Click(object sender, EventArgs e)
{
string fee = await GetFee();
decimal feeDecimal = decimal.Parse(fee);
textBoxSendingAmount.Text = (balance - feeDecimal).ToString();
}
private async void buttonSendHNS_Click(object sender, EventArgs e)
{
try
{
string address = textBoxSendingTo.Text;
bool valid = await ValidAddress(address);
if (!valid)
{
labelSendingError.Show();
labelSendingError.Text = "Invalid Address";
return;
}
decimal amount = 0;
if (!decimal.TryParse(textBoxSendingAmount.Text, out amount))
{
labelSendingError.Show();
labelSendingError.Text += " Invalid Amount";
return;
}
string feeString = await GetFee();
decimal fee = decimal.Parse(feeString);
string subtractFee = "false";
if (checkBoxSendSubFee.Checked) subtractFee = "true";
else if (amount > (balance - fee))
{
labelSendingError.Show();
labelSendingError.Text += " Insufficient Funds";
return;
}
AddLog("Sending " + amount.ToString() + " HNS to " + address);
string content = "{\"method\": \"sendtoaddress\",\"params\": [ \"" + address + "\", " +
amount.ToString() + ", \"\", \"\", " + subtractFee + " ]}";
string output = await APIPost("", true, content);
JObject APIresp = JObject.Parse(output);
if (APIresp["error"].ToString() != "")
{
NotifyForm notify = new NotifyForm("Error Transaction Failed");
notify.ShowDialog();
return;
}
AddLog(APIresp.ToString());
string hash = APIresp["result"].ToString();
string link = userSettings["explorer-tx"] + hash;
NotifyForm notifySuccess = new NotifyForm("Transaction Sent\nThis transaction could take up to 20 minutes to mine",
"Explorer", link);
notifySuccess.ShowDialog();
textBoxSendingTo.Text = "";
textBoxSendingAmount.Text = "";
labelSendingError.Hide();
labelSendingError.Text = "";
buttonNavPortfolio.PerformClick();
}
catch (Exception ex)
{
AddLog(ex.Message);
labelSendingError.Show();
labelSendingError.Text = ex.Message;
}
}
#endregion
#region Receive
private void textBoxRecieveAddress_Click(object sender, EventArgs e)
{
Clipboard.SetText(textBoxReceiveAddress.Text);
labelReceive2.Text = "Copied to clipboard";
labelReceive2.Left = (panelRecieve.Width - labelReceive2.Width) / 2;
}
#endregion
private void textBoxDomainSearch_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyValue == 13)
{
e.SuppressKeyPress = true;
DomainForm domainForm = new DomainForm(textBoxDomainSearch.Text, userSettings["explorer-tx"], userSettings["explorer-domain"]);
domainForm.OriginalForm = this;
domainForm.Show();
}
}
}
}