diff --git a/FireWallet/BatchForm.cs b/FireWallet/BatchForm.cs
index ca43c28..bf77044 100644
--- a/FireWallet/BatchForm.cs
+++ b/FireWallet/BatchForm.cs
@@ -3,7 +3,6 @@ using System.Diagnostics;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
-using System.Windows.Forms.VisualStyles;
using Newtonsoft.Json.Linq;
using ContentAlignment = System.Drawing.ContentAlignment;
using Point = System.Drawing.Point;
@@ -78,7 +77,6 @@ namespace FireWallet
tx.Controls.Add(deleteTX);
panelTXs.Controls.Add(tx);
- UpdateTheme();
}
public void AddBatch(string domain, string operation, decimal bid, decimal lockup)
{
@@ -142,7 +140,6 @@ namespace FireWallet
tx.Controls.Add(deleteTX);
panelTXs.Controls.Add(tx);
- UpdateTheme();
}
public void AddBatch(string domain, string operation, string toAddress)
{
@@ -202,7 +199,6 @@ namespace FireWallet
tx.Controls.Add(deleteTX);
panelTXs.Controls.Add(tx);
- UpdateTheme();
}
public void AddBatch(string domain, string operation, DNS[] updateRecords)
@@ -258,7 +254,6 @@ namespace FireWallet
tx.Controls.Add(deleteTX);
panelTXs.Controls.Add(tx);
- UpdateTheme();
}
private void FixSpacing()
@@ -278,7 +273,7 @@ namespace FireWallet
}
#endregion
#region Theming
- private void UpdateTheme()
+ public void UpdateTheme()
{
// Check if file exists
if (!Directory.Exists(dir))
@@ -471,7 +466,7 @@ namespace FireWallet
HttpClient httpClient = new HttpClient();
private async void buttonSend_Click(object sender, EventArgs e)
{
- if (!mainForm.WatchOnly)
+ if (!mainForm.WatchOnly && !mainForm.multiSig)
{
string batchTX = "[" + string.Join(", ", batches.Select(batch => batch.ToString())) + "]";
string content = "{\"method\": \"sendbatch\",\"params\":[ " + batchTX + "]}";
@@ -519,6 +514,58 @@ namespace FireWallet
notifyForm2.Dispose();
this.Close();
}
+ else if (mainForm.multiSig)
+ {
+ string batchTX = "[" + string.Join(", ", batches.Select(batch => batch.ToString())) + "]";
+ string content = "{\"method\": \"createbatch\",\"params\":[ " + batchTX + "]}";
+ string responce = await APIPost("", true, content);
+
+ if (responce == "Error")
+ {
+ AddLog("Error sending batch");
+ NotifyForm notifyForm = new NotifyForm("Error sending batch");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ return;
+ }
+
+ JObject jObject = JObject.Parse(responce);
+ 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 if (jObject["error"].ToString().Contains("Name is not registered"))
+ {
+ NotifyForm notifyForm = new NotifyForm("Error: \nName is not registered\nRemember you can't renew domains in transfer");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ }
+ else
+ {
+ NotifyForm notifyForm = new NotifyForm("Error: \n" + jObject["error"].ToString());
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ }
+ return;
+ }
+
+ string[] domains = batches.Select(batch => batch.domain).ToArray();
+ string tx = await mainForm.ExportTransaction(jObject["result"].ToString(),domains);
+ if (tx != "Error")
+ {
+ ImportTXForm importTXForm = new ImportTXForm(mainForm, tx);
+ this.Hide();
+ importTXForm.ShowDialog();
+ importTXForm.Dispose();
+ this.Close();
+ }
+ }
else // watch only
{
string batchTX = "[" + string.Join(", ", batches.Select(batch => batch.ToString())) + "]";
diff --git a/FireWallet/DomainForm.cs b/FireWallet/DomainForm.cs
index 3cca470..adad9d6 100644
--- a/FireWallet/DomainForm.cs
+++ b/FireWallet/DomainForm.cs
@@ -157,9 +157,9 @@ namespace FireWallet
network = Convert.ToInt32(nodeSettings["Network"]);
GetName();
- if (mainForm.WatchOnly)
+ if (mainForm.WatchOnly || mainForm.multiSig)
{
- buttonActionMain.Enabled = false; // Only allow sending in batches for ledger
+ buttonActionMain.Enabled = false; // Only allow sending in batches for ledger and multisig to prevent confusion
}
}
#region API
diff --git a/FireWallet/FireWallet.csproj b/FireWallet/FireWallet.csproj
index 04dfcfd..386934d 100644
--- a/FireWallet/FireWallet.csproj
+++ b/FireWallet/FireWallet.csproj
@@ -12,7 +12,7 @@
HSDBatcher.png
https://github.com/Nathanwoodburn/FireWallet
git
- 3.4
+ 4.0
@@ -29,6 +29,7 @@
+
diff --git a/FireWallet/ImportTXForm.Designer.cs b/FireWallet/ImportTXForm.Designer.cs
new file mode 100644
index 0000000..2541a10
--- /dev/null
+++ b/FireWallet/ImportTXForm.Designer.cs
@@ -0,0 +1,223 @@
+namespace FireWallet
+{
+ partial class ImportTXForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImportTXForm));
+ groupBoxIn = new GroupBox();
+ panelIn = new Panel();
+ groupBoxOut = new GroupBox();
+ panelOut = new Panel();
+ buttonSign = new Button();
+ Cancelbutton2 = new Button();
+ label1 = new Label();
+ labelSigsTotal = new Label();
+ labelSigsReq = new Label();
+ labelSigsSigned = new Label();
+ labelSigInfo = new Label();
+ buttonExport = new Button();
+ buttonSend = new Button();
+ groupBoxIn.SuspendLayout();
+ groupBoxOut.SuspendLayout();
+ SuspendLayout();
+ //
+ // groupBoxIn
+ //
+ groupBoxIn.Controls.Add(panelIn);
+ groupBoxIn.Location = new Point(12, 83);
+ groupBoxIn.Name = "groupBoxIn";
+ groupBoxIn.Size = new Size(376, 355);
+ groupBoxIn.TabIndex = 3;
+ groupBoxIn.TabStop = false;
+ groupBoxIn.Text = "Inputs";
+ //
+ // panelIn
+ //
+ panelIn.AutoScroll = true;
+ panelIn.Dock = DockStyle.Fill;
+ panelIn.Location = new Point(3, 19);
+ panelIn.Name = "panelIn";
+ panelIn.Size = new Size(370, 333);
+ panelIn.TabIndex = 0;
+ //
+ // groupBoxOut
+ //
+ groupBoxOut.Controls.Add(panelOut);
+ groupBoxOut.Location = new Point(391, 80);
+ groupBoxOut.Name = "groupBoxOut";
+ groupBoxOut.Size = new Size(484, 355);
+ groupBoxOut.TabIndex = 0;
+ groupBoxOut.TabStop = false;
+ groupBoxOut.Text = "Outputs";
+ //
+ // panelOut
+ //
+ panelOut.AutoScroll = true;
+ panelOut.Dock = DockStyle.Fill;
+ panelOut.Location = new Point(3, 19);
+ panelOut.Name = "panelOut";
+ panelOut.Size = new Size(478, 333);
+ panelOut.TabIndex = 0;
+ //
+ // buttonSign
+ //
+ buttonSign.FlatStyle = FlatStyle.Flat;
+ buttonSign.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ buttonSign.Location = new Point(700, 444);
+ buttonSign.Name = "buttonSign";
+ buttonSign.Size = new Size(83, 36);
+ buttonSign.TabIndex = 2;
+ buttonSign.Text = "Sign";
+ buttonSign.UseVisualStyleBackColor = true;
+ buttonSign.Click += buttonSign_Click;
+ //
+ // Cancelbutton2
+ //
+ Cancelbutton2.FlatStyle = FlatStyle.Flat;
+ Cancelbutton2.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ Cancelbutton2.Location = new Point(12, 441);
+ Cancelbutton2.Name = "Cancelbutton2";
+ Cancelbutton2.Size = new Size(83, 36);
+ Cancelbutton2.TabIndex = 2;
+ Cancelbutton2.Text = "Cancel";
+ Cancelbutton2.UseVisualStyleBackColor = true;
+ Cancelbutton2.Click += Cancel;
+ //
+ // label1
+ //
+ label1.AutoSize = true;
+ label1.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ label1.Location = new Point(12, 9);
+ label1.Name = "label1";
+ label1.Size = new Size(87, 21);
+ label1.TabIndex = 4;
+ label1.Text = "Signatures:";
+ //
+ // labelSigsTotal
+ //
+ labelSigsTotal.BackColor = Color.Blue;
+ labelSigsTotal.Location = new Point(105, 7);
+ labelSigsTotal.Name = "labelSigsTotal";
+ labelSigsTotal.Size = new Size(250, 32);
+ labelSigsTotal.TabIndex = 5;
+ //
+ // labelSigsReq
+ //
+ labelSigsReq.BackColor = Color.FromArgb(255, 128, 0);
+ labelSigsReq.Location = new Point(105, 7);
+ labelSigsReq.Name = "labelSigsReq";
+ labelSigsReq.Size = new Size(191, 32);
+ labelSigsReq.TabIndex = 6;
+ //
+ // labelSigsSigned
+ //
+ labelSigsSigned.BackColor = Color.Lime;
+ labelSigsSigned.Location = new Point(105, 7);
+ labelSigsSigned.Name = "labelSigsSigned";
+ labelSigsSigned.Size = new Size(100, 32);
+ labelSigsSigned.TabIndex = 7;
+ //
+ // labelSigInfo
+ //
+ labelSigInfo.AutoSize = true;
+ labelSigInfo.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ labelSigInfo.Location = new Point(361, 7);
+ labelSigInfo.Name = "labelSigInfo";
+ labelSigInfo.Size = new Size(19, 21);
+ labelSigInfo.TabIndex = 8;
+ labelSigInfo.Text = "#";
+ //
+ // buttonExport
+ //
+ buttonExport.Enabled = false;
+ buttonExport.FlatStyle = FlatStyle.Flat;
+ buttonExport.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ buttonExport.Location = new Point(611, 444);
+ buttonExport.Name = "buttonExport";
+ buttonExport.Size = new Size(83, 36);
+ buttonExport.TabIndex = 2;
+ buttonExport.Text = "Export";
+ buttonExport.UseVisualStyleBackColor = true;
+ buttonExport.Click += buttonExport_Click;
+ //
+ // buttonSend
+ //
+ buttonSend.FlatStyle = FlatStyle.Flat;
+ buttonSend.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ buttonSend.Location = new Point(789, 444);
+ buttonSend.Name = "buttonSend";
+ buttonSend.Size = new Size(83, 36);
+ buttonSend.TabIndex = 2;
+ buttonSend.Text = "Send";
+ buttonSend.UseVisualStyleBackColor = true;
+ buttonSend.Click += buttonSend_Click;
+ //
+ // ImportTXForm
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(887, 485);
+ Controls.Add(labelSigInfo);
+ Controls.Add(labelSigsSigned);
+ Controls.Add(labelSigsReq);
+ Controls.Add(labelSigsTotal);
+ Controls.Add(label1);
+ Controls.Add(groupBoxOut);
+ Controls.Add(groupBoxIn);
+ Controls.Add(buttonSend);
+ Controls.Add(buttonExport);
+ Controls.Add(Cancelbutton2);
+ Controls.Add(buttonSign);
+ FormBorderStyle = FormBorderStyle.FixedSingle;
+ Icon = (Icon)resources.GetObject("$this.Icon");
+ MaximizeBox = false;
+ Name = "ImportTXForm";
+ Text = "Import TX";
+ Load += ImportTXForm_Load;
+ groupBoxIn.ResumeLayout(false);
+ groupBoxOut.ResumeLayout(false);
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+ private GroupBox groupBoxIn;
+ private GroupBox groupBoxOut;
+ private Button buttonSign;
+ private Button Cancelbutton2;
+ private Panel panelIn;
+ private Panel panelOut;
+ private Label label1;
+ private Label labelSigsTotal;
+ private Label labelSigsReq;
+ private Label labelSigsSigned;
+ private Label labelSigInfo;
+ private Button buttonExport;
+ private Button buttonSend;
+ }
+}
\ No newline at end of file
diff --git a/FireWallet/ImportTXForm.cs b/FireWallet/ImportTXForm.cs
new file mode 100644
index 0000000..508dabb
--- /dev/null
+++ b/FireWallet/ImportTXForm.cs
@@ -0,0 +1,347 @@
+using System.Windows.Forms.VisualStyles;
+using Newtonsoft.Json.Linq;
+
+namespace FireWallet
+{
+ public partial class ImportTXForm : Form
+ {
+ MainForm mainForm;
+ JObject tx;
+ int totalSigs;
+ int reqSigs;
+ int sigs;
+ string signedTX;
+ string[] domains;
+ public ImportTXForm(MainForm mainForm)
+ {
+ InitializeComponent();
+ this.mainForm = mainForm;
+ tx = null;
+ }
+ public ImportTXForm(MainForm mainForm, string tx)
+ {
+ InitializeComponent();
+ this.mainForm = mainForm;
+ JObject txObj = JObject.Parse(tx);
+ this.tx = txObj;
+ }
+
+ private void ImportTXForm_Load(object sender, EventArgs e)
+ {
+ // Default variables
+ domains = new string[0];
+ signedTX = "";
+ totalSigs = 3;
+ reqSigs = 2;
+ sigs = 0;
+
+ // Theme
+ this.BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]);
+ this.ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]);
+ foreach (Control c in Controls)
+ {
+ mainForm.ThemeControl(c);
+ }
+ if (tx == null)
+ {
+ OpenFileDialog openFileDialog = new OpenFileDialog();
+ openFileDialog.Filter = "Transaction files (*.json)|*.json";
+ if (openFileDialog.ShowDialog() == DialogResult.OK)
+ {
+ string tx = System.IO.File.ReadAllText(openFileDialog.FileName);
+ try
+ {
+ JObject txObj = JObject.Parse(tx);
+ this.tx = txObj;
+ }
+ catch
+ {
+ NotifyForm notifyForm = new NotifyForm("Invalid transaction file.");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ this.Close();
+ }
+ }
+ }
+ ParseTX();
+ }
+
+ private void Cancel(object sender, EventArgs e)
+ {
+ this.Close();
+ }
+ private async void ParseTX()
+ {
+ if (tx == null) this.Close();
+
+ string hex = tx["tx"].ToString();
+ string content = "{\"method\":\"decoderawtransaction\",\"params\":[\"" + hex + "\"]}";
+ string response = await mainForm.APIPost("", false, content);
+ if (response == null)
+ {
+ NotifyForm notifyForm = new NotifyForm("Error decoding transaction");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ return;
+ }
+ JObject json = JObject.Parse(response);
+ if (json["error"].ToString() != "")
+ {
+ NotifyForm notifyForm = new NotifyForm("Error decoding transaction");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ return;
+ }
+ JObject metadata = (JObject)tx["metadata"];
+ JArray metaInputs = (JArray)metadata["inputs"];
+ JArray metaOutputs = (JArray)metadata["outputs"];
+
+ JArray inputs = (JArray)json["result"]["vin"];
+ JArray outputs = (JArray)json["result"]["vout"];
+
+ // Get multisig info
+ JObject firstIn = (JObject)inputs[0];
+ JArray witnesses = (JArray)firstIn["txinwitness"];
+
+ string scriptSig = witnesses[witnesses.Count - 1].ToString();
+ // decode script
+ string sigGetContent = "{\"method\":\"decodescript\",\"params\":[\"" + scriptSig + "\"]}";
+ string sigGetResponse = await mainForm.APIPost("", false, sigGetContent);
+ if (sigGetResponse == null)
+ {
+ NotifyForm notifyForm = new NotifyForm("Error decoding transaction");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ return;
+ }
+ JObject sigGetJson = JObject.Parse(sigGetResponse);
+ if (sigGetJson["error"].ToString() != "")
+ {
+ NotifyForm notifyForm = new NotifyForm("Error decoding transaction");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ return;
+ }
+ JObject sigGetResult = (JObject)sigGetJson["result"];
+ string[] asm = sigGetResult["asm"].ToString().Split(" ");
+ string totalSigsStr = asm[asm.Length - 2];
+ totalSigs = int.Parse(totalSigsStr.Replace("OP_", ""));
+ reqSigs = int.Parse(sigGetResult["reqSigs"].ToString());
+ sigs = -1;
+ for (int i = 0; i < witnesses.Count; i++)
+ {
+ string witness = witnesses[i].ToString();
+ if (witness != "")
+ {
+ sigs++;
+ }
+ }
+
+ // Set sig label sizes
+ labelSigsReq.Width = (labelSigsTotal.Width / totalSigs) * reqSigs;
+ labelSigsSigned.Width = (labelSigsTotal.Width / totalSigs) * sigs;
+ labelSigInfo.Text = "Signed: " + sigs + "\nReq: " + reqSigs + " of " + totalSigs;
+
+ if (sigs >= totalSigs)
+ {
+ buttonSign.Enabled = false;
+ buttonSign.Text = "Signed";
+ }
+
+ for (int i = 0; i < inputs.Count; i++)
+ {
+ JObject input = (JObject)inputs[i];
+ JObject metaInput = (JObject)metaInputs[i];
+
+ Panel PanelInput = new Panel();
+ PanelInput.Size = new Size(panelIn.Width - SystemInformation.VerticalScrollBarWidth - 10, 50);
+ PanelInput.Location = new Point(5, panelIn.Controls.Count * 50);
+ PanelInput.BorderStyle = BorderStyle.FixedSingle;
+
+
+ if (metaInput.ContainsKey("sighashType"))
+ {
+ Label sighashType = new Label();
+ sighashType.Text = "Sighash Type: " + metaInput["sighashType"].ToString();
+ sighashType.Location = new Point(5, 25);
+ sighashType.AutoSize = true;
+ PanelInput.Controls.Add(sighashType);
+ }
+
+ string txid = input["txid"].ToString();
+ int vout = int.Parse(input["vout"].ToString());
+ string txInfo = await mainForm.APIGet("tx/" + txid, false);
+ if (txInfo == "Error" || txInfo == "")
+ {
+ NotifyForm notifyForm = new NotifyForm("Error getting transaction info");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ return;
+ }
+ else
+ {
+ JObject txInfoJson = JObject.Parse(txInfo);
+ JArray txoutputs = (JArray)txInfoJson["outputs"];
+ JObject txoutput = (JObject)txoutputs[vout];
+ string txoutputAddress = txoutput["address"].ToString();
+
+ Label address = new Label();
+ string addressString = txoutputAddress.Substring(0, 5) + "..." + txoutputAddress.Substring(txoutputAddress.Length - 5, 5);
+ address.Text = "Address: " + addressString;
+ address.Location = new Point(5, 5);
+ address.AutoSize = true;
+ PanelInput.Controls.Add(address);
+
+ Label amount = new Label();
+ Decimal value = Decimal.Parse(txoutput["value"].ToString()) / 1000000;
+ amount.Text = "Amount: " + value.ToString();
+ amount.Location = new Point(5, 25);
+ amount.AutoSize = true;
+ PanelInput.Controls.Add(amount);
+
+ }
+ panelIn.Controls.Add(PanelInput);
+ }
+
+ for (int i = 0; i < outputs.Count; i++)
+ {
+ JObject output = (JObject)outputs[i];
+ JObject metaOutput = (JObject)metaOutputs[i];
+
+ Panel PanelOutput = new Panel();
+ PanelOutput.Size = new Size(panelOut.Width - SystemInformation.VerticalScrollBarWidth - 10, 50);
+ PanelOutput.Location = new Point(5, panelOut.Controls.Count * 50);
+ PanelOutput.BorderStyle = BorderStyle.FixedSingle;
+
+ Label address = new Label();
+
+ JObject addressRaw = (JObject)output["address"];
+
+ string addressString = addressRaw["string"].ToString().Substring(0, 5) + "..." + addressRaw["string"].ToString().Substring(addressRaw["string"].ToString().Length - 5, 5);
+ address.Text = "Address: " + addressString;
+ address.Location = new Point(5, 5);
+ address.AutoSize = true;
+ PanelOutput.Controls.Add(address);
+
+ JObject covenant = (JObject)output["covenant"];
+ if (covenant.ContainsKey("action"))
+ {
+ if (covenant["action"].ToString() != "NONE")
+ {
+ if (metaOutput.ContainsKey("name"))
+ {
+ Label covenantLabel = new Label();
+ string name = metaOutput["name"].ToString();
+
+ covenantLabel.Text = covenant["action"].ToString() + ": " + name;
+ covenantLabel.Location = new Point(5, 25);
+ covenantLabel.AutoSize = true;
+ PanelOutput.Controls.Add(covenantLabel);
+
+ string[] domainsNew = new string[domains.Length + 1];
+ for (int j = 0; j < domains.Length; j++)
+ {
+ domainsNew[j] = domains[j];
+ }
+ domainsNew[domainsNew.Length - 1] = name;
+ domains = domainsNew;
+ }
+ }
+ }
+
+ bool own = false;
+ string addressResp = await mainForm.APIGet("wallet/" + mainForm.Account + "/key/" + addressRaw["string"].ToString(), true);
+ if (addressResp != "Error") own = true;
+
+ if (own)
+ {
+ Label ownAddress = new Label();
+ ownAddress.Text = "Own Address";
+ ownAddress.Location = new Point(PanelOutput.Width - 150, 5);
+ ownAddress.AutoSize = true;
+ PanelOutput.Controls.Add(ownAddress);
+ }
+
+ Label amount = new Label();
+ Decimal value = Decimal.Parse(output["value"].ToString());
+ amount.Text = "Amount: " + value.ToString();
+ amount.Location = new Point(PanelOutput.Width - 150, 25);
+ amount.AutoSize = true;
+ PanelOutput.Controls.Add(amount);
+ panelOut.Controls.Add(PanelOutput);
+ }
+ }
+
+ private async void buttonSign_Click(object sender, EventArgs e)
+ {
+ if (!mainForm.WatchOnly)
+ {
+ string content = "{\"tx\":\"" + tx["tx"].ToString() + "\", \"passphrase\":\"" + mainForm.Password + "\"}";
+ string response = await mainForm.APIPost("wallet/" + mainForm.Account + "/sign", true, content);
+ if (response == "Error" || response == "")
+ {
+ NotifyForm notifyForm = new NotifyForm("Error signing transaction");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ return;
+ }
+ buttonSign.Enabled = false;
+ buttonExport.Enabled = true;
+ sigs++;
+ // Set sig label sizes
+ labelSigsReq.Width = (labelSigsTotal.Width / totalSigs) * reqSigs;
+ labelSigsSigned.Width = (labelSigsTotal.Width / totalSigs) * sigs;
+ labelSigInfo.Text = "Signed: " + sigs + "\nReq: " + reqSigs + " of " + totalSigs;
+ signedTX = response;
+ } else {
+ NotifyForm notifyForm = new NotifyForm("Ledger signing not supported yet 😢");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ }
+ }
+
+ private void buttonExport_Click(object sender, EventArgs e)
+ {
+ mainForm.ExportTransaction(signedTX,domains);
+ }
+
+ private async void buttonSend_Click(object sender, EventArgs e)
+ {
+ string content = "";
+ if (signedTX != "")
+ {
+ JObject signed = JObject.Parse(signedTX);
+ content = "{\"method\":\"sendrawtransaction\", \"params\":[\"" + signed["hex"].ToString() + "\"]}";
+ }
+ else
+ {
+ content = "{\"method\":\"sendrawtransaction\", \"params\":[\"" + tx["tx"].ToString() + "\"]}";
+ }
+ string response = await mainForm.APIPost("", false, content);
+ if (response == "Error" || response == "")
+ {
+ mainForm.AddLog(response);
+ NotifyForm notifyError = new NotifyForm("Error sending transaction");
+ notifyError.ShowDialog();
+ notifyError.Dispose();
+ return;
+ }
+ JObject responseJson = JObject.Parse(response);
+ if (responseJson["error"].ToString() != "")
+ {
+ mainForm.AddLog(response);
+ JObject error = (JObject)responseJson["error"];
+ NotifyForm notifyError = new NotifyForm("Error sending transaction\n" + error["message"].ToString());
+ notifyError.ShowDialog();
+ notifyError.Dispose();
+ return;
+ }
+ string txHash = responseJson["result"].ToString();
+ NotifyForm notifyForm = new NotifyForm("Transaction sent\nIf the transaction hasn't been signed it might not be mined", "Explorer", mainForm.UserSettings["explorer-tx"] + txHash);
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ this.Close();
+
+ }
+ }
+}
diff --git a/FireWallet/ImportTXForm.resx b/FireWallet/ImportTXForm.resx
new file mode 100644
index 0000000..0464da4
--- /dev/null
+++ b/FireWallet/ImportTXForm.resx
@@ -0,0 +1,587 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA
+ IACoJQAA7h4AAAAAAAABACAAfScAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAI8/zACPQM0Aj0DNEo9AzVePQM02j0DNAI9AzQAAAAAAAAAAAI8/zQCPQM0Aj0DNNI9A
+ zViPQM0Sj0DNAI8/zACPQM0Uj0DNXY9AzcOPQM37j0DN1o9AzTuPQM0Ajz/NAI4/zACPQM0Aj0DNOY9A
+ zdWPQM37j0DNxI9AzV6PQM0Vj0DNso9AzfqPQM3/j0DN/49Azf+PQM3Wj0DNO49AzQCPQM0Aj0DNOY9A
+ zdSPQM3/j0DN/49Azf+PQM36j0DNtY9AzdmPQM3/j0DN/49Azf+PQM3/j0DN/49AzdaPQM05j0DNN49A
+ zdWPQM3/j0DN/49Azf+PQM3/j0DN/49AzdyRQ8XYkUPF/5FDxf+RQ8X/kUPF/5FDxf+RQ8X/kkPFsZJD
+ xa+RQ8X/kUPF/5FDxf+RQ8X/kUPF/5FDxf+RQ8Xbmkuu2JpLrv+aS67/mkuv/ppLrv6aS67/mkuu/5pL
+ r76aS6+9mkuu/5pLrv+aS67+mkuv/ppLrv+aS67/mkuu26VSkNilUpD/pVKQ/6RSkOajUZWrpVKQ+aVS
+ kP+lUpC+pVKQvKVSkP+lUpD6o1GVq6RSkOWlUpD/pVKQ/6VSkNuwVG3YsFRt/7BUbf+wVG3drlRzKq5U
+ c4+wVG3/sFRtv7BUbb6wVG3/rlRzka5UcymwVG3csFRt/7BUbf+wVG3cuVNI2blTSP+5U0j/uVNI3rlT
+ Rxy0VWELuFNOlblTSLq5U0i5uFNOlrRVYAy5U0cbuVNI3blTSP+5U0j/uVNI3MFQHtnBUB7/wVAe/8FQ
+ Ht/AUB4ewFAkAL5RMxC/USxQv1EsUL5RMxDAUCUAwFAeHMFQHt3BUB7/wVAe/8FQHtzDTwnZw08J/8NP
+ Cf/DTwnfw08JHsNPCQDETgAAx0wAAcdNAAHFTQAAw08JAMNPCR3DTwnew08J/8NPCf/DTwncw08J2MNP
+ Cf/DTwn/w08Jw8NPCRXDTwkAAAAAAAAAAAAAAAAAAAAAAMNPCQDDTwkUw08JwcNPCf/DTwn/w08J28NP
+ CdbDTwnbw08JfMNPCSHDTggAw08JAAAAAAAAAAAAAAAAAAAAAADCTwkAwU4HAMNPCSDDTwl7w08J28NP
+ CdjDTwlVw08JI8NOCAHDTwkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDTwgAwk4IAcNP
+ CSLDTwlWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAP//AADH4wAAA8AAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEIAAABmAAAAfg
+ AAAP8AAAH/gAAP//AAAoAAAAGAAAADAAAAABACAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI8/zACPP8wDjz/MAo8/
+ zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI8/zQCPP80Cjz/NA48/zQAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACPQM0Ajz/NBY9AzTePQM2Wj0DNYo4/zAOPP80AAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAj0DNAI8/zQKPQM1gj0DNl49AzTmPP80Fjz/NAAAAAAAAAAAAjz/NAI8/zQWPQM04j0DNm49A
+ zeuPQM3/j0DN749AzWeOP8wDjz/NAAAAAAAAAAAAAAAAAAAAAACPP80Ajz/MAo9AzWSPQM3uj0DN/49A
+ zeuPQM2dj0DNOY8/zQWPQM0Aj0DNN49AzZyPQM3rj0DN/49Azf+PQM3/j0DN/49Aze+PQM1njz/MA48/
+ zQAAAAAAAAAAAI9AzQCOP8wCj0DNZI9Aze6PQM3/j0DN/49Azf+PQM3/j0DN7I9AzZ6PQM05j0DNuY9A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3vj0DNZo4/zAOPQMwAjz/NAI8/zQKPQM1jj0DN7o9A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM2+j0DNwY9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN749AzWeOP84Djj7OAo9AzWWPQM3uj0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3Gj0DMwY9AzP+PQMz/j0DM/49AzP+PQMz/j0DM/49AzP+PQMz/j0DM/49AzPCPQMtZj0DLVo9A
+ zO+PQMz/j0DM/49AzP+PQMz/j0DM/49AzP+PQMz/j0DM/49AzP+PQMzFkkTDwJJEw/+SRMP/kkTD/5JE
+ w/+SRMP/kkTD/5JEw/+SRMP/kkTD/5JEw/+SRMOekkTDm5JEw/+SRMP/kkTD/5JEw/+SRMP/kkTD/5JE
+ w/+SRMP/kkTD/5JEw/+SRMPFmEqzwJhKs/+YSrP/mEqz/5hKs/+YSrP/mEqz/5hKs/+YSrP/mEqz/5hK
+ s/+YSrOfmEqznJhKs/+YSrP/mEqz/5hKs/+YSrP/mEqz/5hKs/+YSrP/mEqz/5hKs/+YSrPFn0+gwJ9P
+ oP+fT6D/n0+g/59PoP+fT6D2n0+h7J9PoP+fT6D/n0+g/59PoP+fT6Cfn0+gm59PoP+fT6D/n0+g/59P
+ oP+fT6Hsn0+g9p9PoP+fT6D/n0+g/59PoP+fT6DGp1OKwadTiv+nU4r/p1OK/6dTiv+nU4rdpVKPYqZT
+ jNynU4r/p1OK/6dTiv+nU4qfp1OKnKdTiv+nU4r/p1OK/6ZTjN6lUo9jp1OK26dTiv+nU4r/p1OK/6dT
+ iv+nU4rGrlRzwa5Uc/+uVHP/rlRz/65Uc/+uVHPdrlRzHKxUe0StVHTfrlRz/65Uc/+uVHOgrlRzna5U
+ c/+uVHP/rlR04KxUe0auVHMarlRz265Uc/+uVHP/rlRz/65Uc/+uVHPGtVRawbVUWv+1VFr/tVRa/7VU
+ Wv+1VFrdtVRaHLZTVgCzVWJHtFRc37VUWv+1VFqhtVRanbVUWv+0VFzhs1RiSbdTVAC1VFoatVRa27VU
+ Wv+1VFr/tVRa/7VUWv+1VFrHu1JBwbtSQf+7UkH/u1JB/7tSQf+7UkHdu1JBHbtSQgDAUikAuVNKR7tT
+ Q+K7UkGgu1JBnbtTQ+S5U0lJw1AYALtSQgC7UkEau1JB27tSQf+7UkH/u1JB/7tSQf+7UkHHwFAlwcBQ
+ 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
+ zf+PQM38j0DNl48/zA+PP80AAAAAAAAAAAAAAAAAAAAAAI9AzQCPQM0Oj0DNk49AzfuPQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/Y9AzdWPQM1ej0DNp49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM38j0DNl48/zA+PQM0AAAAAAAAAAACPQM0Aj0DNDo9AzZOPQM37j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Aza6PQM2oj0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM38j0DNl48/zRCPP80Aj0DNAI8/zQ+PQM2Uj0DN+49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DNr49AzaePQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM38j0DNmo4/zQ+PP80Oj0DNlo9A
+ zfyPQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM2ukEHKp5BB
+ yv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr9kEHJZ5BB
+ yWKQQcr8kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/49B
+ yq6TRcGnk0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NF
+ wf+TRcGEk0XBf5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NF
+ wf+TRcH/k0XBrpdJtaeXSbX/l0m1/5dJtf+XSbX/l0m1/5dJtf+XSbX/l0m1/5dJtf+XSbX/l0m1/5dJ
+ tf+XSbX/l0m1/5dJtYKXSbZ9l0m1/5dJtf+XSbX/l0m1/5dJtf+XSbX/l0m1/5dJtf+XSbX/l0m1/5dJ
+ tf+XSbX/l0m1/5dJtf+XSbWunE2op5xNqP+cTaj/nE2o/5xNqP+cTaj/nE2o/5xNqP+cTaf/nE2o/5xN
+ qP+cTaj/nE2o/5xNqP+cTaj/nE2ogZxNqHycTaj/nE2o/5xNqP+cTaj/nE2o/5xNqP+cTaf/nE2o/5xN
+ qP+cTaj/nE2o/5xNqP+cTaj/nE2o/5xNqK6iUZinolGY/6JRmP+iUZj/olGY/6JRmP+iUZj/olGY6KFQ
+ mrmiUZj8olGY/6JRmP+iUZj/olGY/6JRmP+iUZiBolGYfKJRmP+iUZj/olGY/6JRmP+iUZj/olGY/KFQ
+ mrqiUZjnolGY/6JRmP+iUZj/olGY/6JRmP+iUZj/olGYrqhTh6eoU4f/qFOH/6hTh/+oU4f/qFOH/6hT
+ h/+oU4fcplOLL6dTip6oU4f9qFOH/6hTh/+oU4f/qFOH/6hTh4KnU4d9qFOH/6hTh/+oU4f/qFOH/6hT
+ h/6nU4qiplOLLqhTh9moU4f/qFOH/6hTh/+oU4f/qFOH/6hTh/+oU4evrVR2p61Udv+tVHb/rVR2/61U
+ dv+tVHb/rVR2/61UdtytVHYbqlSAEaxUeaGtVHb9rVR2/61Udv+tVHb/rVR2g61Udn6tVHb/rVR2/61U
+ dv+tVHb+rFR5pKpUfxOtVHYYrVR22q1Udv+tVHb/rVR2/61Udv+tVHb/rVR2/61Udq+yVGSoslVk/7JV
+ ZP+yVWT/slVk/7JVZP+yVWT/slVk3LJUZByxVWcAsFVtFLJVZ6KyVWT+slVk/7JVZP+yVGSEslRkf7JV
+ ZP+yVWT/slVk/rJVZqawVW0VsVRnALJUZBmyVGTZslVk/7JVZP+yVWT/slVk/7JVZP+yVWT/slRkr7dU
+ Uai3VFH/t1RR/7dUUf+3VFH/t1RR/7dUUf+3VFHct1NRHLdTUQC1VFoAtVRaFLdUVKO3VFH+t1RR/7dU
+ UYO3VFF+t1RR/7dUUf63VFSmtVRaFrVUWQC3U1EAt1NRGbdUUdm3VFH/t1RR/7dUUf+3VFH/t1RR/7dU
+ Uf+3VFGwvFI+qLxSPv+8Uj7/vFI+/7xSPv+8Uj7/vFI+/7xSPty7Uj4cu1I+AMNRHQC6U0cAulNIFLtS
+ QaG8Uj7/vFI+gbxSPny8Uj7/u1JBpbpTSBa6U0cAv1E0ALtSPgC7Uj4ZvFI+2bxSPv+8Uj7/vFI+/7xS
+ Pv+8Uj7/vFI+/7xSPrC/UCqov1Eq/79RKv+/USr/v1Eq/79RKv+/USr/v1Aq3b9QKRy/UCkAAAAAANJE
+ AAC+UTMAvlE0E79RLZ+/UCp6v1Eqdr9RLaK+UTQUvlEzAMNNFwAAAAAAv1ApAL9QKRm/UCrZv1Eq/79R
+ Kv+/USr/v1Eq/79RKv+/USr/v1AqsMJPEqjCTxL/wk8S/8JPEv/CTxL/wk8S/8JPEv/CTxLdwk8SHcJP
+ EgAAAAAAAAAAAAAAAADBTx4AwU8eE8FPHCfBUBwnwVAeFMFQHgD/AAAAAAAAAAAAAADCTxIAwk8SGsJP
+ EtrCTxL/wk8S/8JPEv/CTxL/wk8S/8JPEv/CTxKww08JqMNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NP
+ Cd7DTwgdw08IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMNP
+ CADDTwgaw08J2sNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCbDDTwmow08J/8NPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J3sNPCR3DTwkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAw08JAMNPCRvDTwnbw08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08Jr8NPCafDTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwndw08JHMNPCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAADDTwkAw08JGsNPCdrDTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwmuw08Jp8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J88NPCZrDTgkMw08JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMJPCQDCTwkKw08JlsNPCfLDTwn/w08J/8NPCf/DTwn/w08J/8NP
+ Ca3DTwmmw08J/8NPCf/DTwn/w08J8sNPCavDTwlGw08JCcNPCQDCTgcAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw08GAMNPCQDCTwgIw08JRMNPCanDTwnxw08J/8NP
+ Cf/DTwn/w08JrMNPCaTDTwn/w08J8cNPCazDTwlGw04ICcNPCADDTgkAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMFMCQDDTwkAwk8JCMNP
+ CUTDTwmqw08J8cNPCf/DTwmqw08JkcNPCarDTwlFw08ICcNPCQDCTAgAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADCTwYAw08JAMNPCQjDTwlDw08JqcNPCZbDTwkXw08JCcNPCQC/SwUAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAw00FAMNPCQDDTgkIw04JGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////5/
+ /j/4P/wf4B/4B4AP8AAAB+AAAAPAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA
+ AgAAYAYAAHAOAAB4HgAAfD4AAH/+AAB//gAAf/4AAH/+AAD//wAD///AD///8D////z//////////ygA
+ AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjz7LAI8+
+ ywCPPssAjz7LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjkDLAI4/ywCOP8sAjkDLAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI5A
+ zACOP8wBjz/NJY9AzXmPQM1Ig0LIAI5AzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOP8wAkkfWAI9AzUOPQM17j0DNKI8/
+ zQKPP80AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACPP8wAjj/LAY8/zCaPQM2Cj0DN3I9Azf+PQM3hj0DNToQ2wQCOP8wAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI8/zQCORMsAj0DNSI9A
+ zd6PQM3/j0DN3o9AzYWPP80ojj7MAo8/zQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAjz/NAI8+zAGPQM0mj0DNgo9AzdyPQM3+j0DN/49Azf+PQM3/j0DN449AzU+QPcsAjz/NAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjz/NAI9J
+ zwCPQM1Jj0DN349Azf+PQM3/j0DN/49Azf6PQM3ej0DNhY8/zSiPPswCjz/MAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAI8/zACOPswCjz/NJ49AzYOPQM3dj0DN/o9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zeSPQM1QijbKAI4/zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACOP8wAk0XXAI9AzUqPQM3gj0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/o9Azd+PQM2Gjz/NKY8/
+ zAKPP80AAAAAAAAAAACPP8wAjj7MAo9AzSqPQM2Fj0DN3o9Azf6PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3kjz/NT4w6xgCOP8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAI8/zQCTS84Ajz/NSo9AzeCPQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3+j0DN349AzYiPP80sjj/NA44/zQCPQM0Xj0DNhI9AzeGPQM3+j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN449AzVCQLsMAjz/MAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAjj/NAJJB0ACPQM1Kj0DN4I9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf6PQM3jj0DNiY8/zRqPQM1nj0DN+o9Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49AzeOPP81PhzjFAI4/
+ zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPQM0Ak0HLAI9AzUmPQM3gj0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/I8/zXOPQM11j0DN/Y9A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3jj0DNT4c/wwCOP8wAAAAAAAAAAAAAAAAAAAAAAI8/zQCNSs4Aj0DNSo9AzeCPQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/48/
+ zX+PQM11j0DN/Y9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN449AzVCNOM0Ajj/NAAAAAAAAAAAAjj/MAJdJ3gCPP81Kj0DN4I9A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/o8/zX6PQM10j0DN/Y9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49AzeSPQM1Si0HNAY5AzQCPP80AkDjLAI9A
+ zU2PQM3hj0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/o8/zX2PQM1zj0DN/Y9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3mjz/NVY07
+ zwGRRsoAjz/NT49AzeOPQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/o8/zX2PQMtzj0DL/Y9Ay/+PQMv/j0DL/49A
+ y/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49A
+ y/+PQMv/j0DL349AyymPQMslj0DL2o9Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49A
+ y/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/o9Ay32RQ8ZykUPG/ZFD
+ xv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FD
+ xv+RQ8b/kUPG/5FDxv+RQ8b/kUPG+5FDxk2RQ8ZGkUPG+JFDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FD
+ xv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/pFD
+ xn2URsBylEbA/ZRGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RG
+ wP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/JRGwFCURsBJlEbA+ZRGwP+URsD/lEbA/5RG
+ wP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RG
+ wP+URsD/lEbA/pRGwH2XSbhyl0m4/ZdJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJ
+ uP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4+5dJuE6XSbhGl0m4+ZdJ
+ uP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJ
+ uP+XSbj/l0m4/5dJuP+XSbj/l0m4/pdJuH2aS69ymkyv/ZpMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pM
+ r/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv+5pM
+ r02aTK9Fmkyv+JpMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pM
+ r/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/ppMr32dTqVynU6l/Z1Opf+dTqX/nU6l/51O
+ pf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51O
+ pf+dTqX/nU6l+51OpU2dTqVEnU6l+J1Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51O
+ pf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/p1OpX2hUJtyoVCb/aFQ
+ m/+hUJv/oVCb/6FQm/+hUJv/oVCb/6FQm/+hUJv/oVCb/6FQm+uhUJzHoVCb/aFQm/+hUJv/oVCb/6FQ
+ m/+hUJv/oVCb/6FQm/+hUJv/oVCb+6FQm02hUJtFoVCb+KFQm/+hUJv/oVCb/6FQm/+hUJv/oVCb/6FQ
+ m/+hUJv/oVCb/qFQnMihUJvpoVCb/6FQm/+hUJv/oVCb/6FQm/+hUJv/oVCb/6FQm/+hUJv/oVCb/qFQ
+ m32lUpBypVKQ/aVSkP+lUpD/pVKQ/6VSkP+lUpD/pVKQ/6VSkP+lUpD/pVKQ/6VSkNqkUpI3pFKRraVS
+ kP+lUpD/pVKQ/6VSkP+lUpD/pVKQ/6VSkP+lUpD/pVKQ+6VSkE2lUpBFpVKQ+KVSkP+lUpD/pVKQ/6VS
+ kP+lUpD/pVKQ/6VSkP+lUpD/pFKRsqRSkzalUpDVpVKQ/6VSkP+lUpD/pVKQ/6VSkP+lUpD/pVKQ/6VS
+ kP+lUpD/pVKQ/qVSkH6oU4VzqFOF/ahThf+oU4X/qFOF/6hThf+oU4X/qFOF/6hThf+oU4X/qFOF/6hT
+ hdupU4QaplOKGahThq+oU4X/qFOF/6hThf+oU4X/qFOF/6hThf+oU4X/qFOF+6hThU6oU4VHqFOF+ahT
+ hf+oU4X/qFOF/6hThf+oU4X/qFOF/6hThf+oU4a0p1OKHalThBeoU4XXqFOF/6hThf+oU4X/qFOF/6hT
+ hf+oU4X/qFOF/6hThf+oU4X/qFOF/6hThX6sVHlzrFR5/axUef+sVHn/rFR5/6xUef+sVHn/rFR5/6xU
+ ef+sVHn/rFR5/6xUedqsVHkbq1R7AKpUfhusVHuwrFR5/6xUef+sVHn/rFR5/6xUef+sVHn/rFR5+6xU
+ eU+sVHlIrFR5+axUef+sVHn/rFR5/6xUef+sVHn/rFR5/6xUerWqVH4eq1R7AKxUeRisVHnWrFR5/6xU
+ ef+sVHn/rFR5/6xUef+sVHn/rFR5/6xUef+sVHn/rFR5/6xUeX+wVW1zsFVt/bBVbf+wVW3/sFVt/7BV
+ bf+wVW3/sFVt/7BVbf+wVW3/sFVt/7BVbdqwVW0bsFVtAK5VcQCuVHIcr1VvsrBVbf+wVW3/sFVt/7BV
+ bf+wVW3/sFVt+7BVbVCwVW1IsFVt+bBVbf+wVW3/sFVt/7BVbf+wVW3/r1Vutq5Uch+uVXEAsFVtALBV
+ bRewVW3WsFVt/7BVbf+wVW3/sFVt/7BVbf+wVW3/sFVt/7BVbf+wVW3/sFVt/7BVbX+zVGF0s1Rh/bNU
+ Yf+zVGH/s1Rh/7NUYf+zVGH/s1Rh/7NUYf+zVGH/s1Rh/7NUYdqzVGEbs1RhALJUZACyVWUAslVmHbNU
+ YrOzVGD/s1Rh/7NUYf+zVGH/s1Rh+7NUYVCzVGFJs1Rh+bNUYf+zVGH/s1Rh/7NUYP+zVGK3slVmILJV
+ ZQCyVGYAs1RhALNUYRezVGHVs1Rh/7NUYf+zVGH/s1Rh/7NUYf+zVGH/s1Rh/7NUYf+zVGH/s1Rh/7NU
+ YX+3VFR0t1RU/bdUVP+3VFT/t1RU/7dUVP+3VFT/t1RU/7dUVP+3VFT/t1RU/7dUVNq2VFQbtlRUAAAA
+ AAC5UE8AtVRZALVUWh62VFazt1RU/7dUVP+3VFT/t1RU+7dUVE+2VFRIt1RU+bdUVP+3VFT/t1RU/7ZU
+ Vri1VFohtVRZALZSVgAAAAAAtlNUALZTVBe2VFTVt1RU/7dUVP+3VFT/t1RU/7dUVP+3VFT/t1RU/7dU
+ VP+3VFT/t1RU/7ZUVIC6U0h0ulNI/bpTSP+6U0j/ulNI/7pTSP+6U0j/ulNI/7pTSP+6U0j/ulNI/7pT
+ SNq6U0gbulNIAAAAAAAAAAAAuFNPALlTTAC4U00euVNJs7pTSP+6U0j/uVNI+7lTSE65U0hGuVNI+bpT
+ SP+6U0j/uVNJt7hTTSG4U00AvlQ5AAAAAAAAAAAAuVNIALlTSBe5U0jVulNI/7pTSP+6U0j/ulNI/7pT
+ SP+6U0j/ulNI/7pTSP+6U0j/ulNI/7pTSIC8Ujt0vFI7/bxSO/+8Ujv/vFI7/7xSO/+8Ujv/vFI7/7xS
+ O/+8Ujv/vFI7/7xSO9q8UjsbvFI7AAAAAAAAAAAAAAAAALtRPwC7UkAAu1JBHbxSPbC8Ujv/vFI7+7xS
+ O0y8UjtEvFI7+LxSO/+8Ujy1u1JBILtSPwC7UkEAAAAAAAAAAAAAAAAAvFI7ALxSOxe8UjvVvFI7/7xS
+ O/+8Ujv/vFI7/7xSO/+8Ujv/vFI7/7xSO/+8Ujv/vFI7/7xSO4C/US11v1Et/b9RLf+/US3/v1Et/79R
+ Lf+/US3/v1Et/79RLf+/US3/v1Et/79RLdu/US0bv1EtAAAAAAAAAAAAAAAAAAAAAADAUBwAvlEzAL5R
+ NBq+US+rv1Et+L9RLUm/US1Cv1Et9r5RL7C+UTMdvlEzAMBOKwAAAAAAAAAAAAAAAAAAAAAAvlEtAL5R
+ LRe/US3Vv1Et/79RLf+/US3/v1Et/79RLf+/US3/v1Et/79RLf+/US3/v1Et/79RLYDBUB51wVAe/cFQ
+ Hv/BUB7/wVAe/8FQHv/BUB7/wVAe/8FQHv/BUB7/wVAe/8FQHtvBUB4cwVAeAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAwU8kAMBQJQDAUCYYwFAhm8FQH0DBUB86wVAhncBQJhvAUCUAwFAlAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAwVAeAMFPHhfBUB7WwVAe/8FQHv/BUB7/wVAe/8FQHv/BUB7/wVAe/8FQHv/BUB7/wVAe/8FQ
+ HoDCTw51wk8O/cNPDv/DTw7/w08O/8NPDv/DTw7/w08O/8NPDv/DTw7/w08O/8JPDtzCTw4cwk8OAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMM9AADCTxcAwk8WD8JPFg7CTxYNwk8WEMJPFwDETwUAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAwk8OAMJPDhjCTw7Ww08O/8NPDv/DTw7/w08O/8NPDv/DTw7/w08O/8NP
+ Dv/DTw7/w08O/8JPDoDDTwh0w08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NP
+ CdzDTggdw04IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwk8IAMJPCBjDTwnXw08J/8NPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCIDDTwl0w08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCdzDTwgdw08IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw04IAMNOCBnDTwnXw08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCX/DTwl0w08J/cNPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCd3DTwgdw08IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw08IAMNP
+ CBnDTwnYw08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCX/DTwlzw08J/cNP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCdzDTwgdw08IAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAw08IAMNPCBnDTwnYw08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/sNP
+ CX7DTwlzw08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCdXDTgkXw04JAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAwk8JAMJPCRTDTwnQw08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J/sNPCX3DTwlyw08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn9w08J1cNP
+ CWjDTggEw04IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwk8IAMFOCAPDTwljw08J08NPCfzDTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/sNPCXvDTwlxw08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/cNP
+ CdPDTwl0w04JHsNPBwHDTwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMJPCAC/TQcAw08JHMNP
+ CXHDTwnRw08J/MNPCf/DTwn/w08J/8NPCf/DTwn/w08J/sNPCXrDTwlww08J/cNPCf/DTwn/w08J/8NP
+ Cf3DTwnUw08JdMNOCR3DTQcAw04IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAwk4IAMFLBwDCTwkbw08JccNPCdHDTwn8w08J/8NPCf/DTwn/w08J/sNPCXjDTwluw08J/MNP
+ Cf/DTwn8w08J08NPCXXDTwkewU0EAMJOBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCTgkAv00KAMNOCBzDTwlyw08J0cNPCfzDTwn/w08J/sNP
+ CXbDTwltw08J+cNPCdDDTwlyw04JHcFPBgDCTggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMJOCQDDTgkAw08JG8NP
+ CW/DTwnOw08J+cNPCXXDTwlGw08JaMJPCRrATAUAwk4IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAwk8IAL5QBADDTwgZw08JaMNOCUrDTQgBw00IAMNNCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDTggAw04IAMNPCAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ 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
+ RU5ErkJggg==
+
+
+
\ No newline at end of file
diff --git a/FireWallet/MainForm.Designer.cs b/FireWallet/MainForm.Designer.cs
index cf2a87a..f4461f7 100644
--- a/FireWallet/MainForm.Designer.cs
+++ b/FireWallet/MainForm.Designer.cs
@@ -39,6 +39,7 @@ namespace FireWallet
toolStripStatusLabelNetwork = new ToolStripStatusLabel();
toolStripStatusLabelstatus = new ToolStripStatusLabel();
toolStripStatusLabelaccount = new ToolStripStatusLabel();
+ toolStripStatusLabelMultisig = new ToolStripStatusLabel();
toolStripStatusLabelLedger = new ToolStripStatusLabel();
toolStripSplitButtonlogout = new ToolStripSplitButton();
toolStripDropDownButtonHelp = new ToolStripDropDownButton();
@@ -59,12 +60,14 @@ namespace FireWallet
buttonaccountnew = new Button();
panelNav = new Panel();
buttonNavSettings = new Button();
+ buttonMultiSign = new Button();
buttonBatch = new Button();
buttonNavDomains = new Button();
buttonNavReceive = new Button();
buttonNavSend = new Button();
buttonNavPortfolio = new Button();
panelPortfolio = new Panel();
+ buttonSendAll = new Button();
buttonRedeemAll = new Button();
buttonRevealAll = new Button();
groupBoxTransactions = new GroupBox();
@@ -127,7 +130,7 @@ namespace FireWallet
textBoxExAddr = new TextBox();
labelSettings4 = new Label();
textBoxExTX = new TextBox();
- buttonSendAll = new Button();
+ buttonMultiSettings = new Button();
statusStripmain.SuspendLayout();
panelaccount.SuspendLayout();
groupBoxaccount.SuspendLayout();
@@ -151,7 +154,7 @@ namespace FireWallet
// statusStripmain
//
statusStripmain.Dock = DockStyle.Top;
- statusStripmain.Items.AddRange(new ToolStripItem[] { toolStripStatusLabelNetwork, toolStripStatusLabelstatus, toolStripStatusLabelaccount, toolStripStatusLabelLedger, toolStripSplitButtonlogout, toolStripDropDownButtonHelp });
+ statusStripmain.Items.AddRange(new ToolStripItem[] { toolStripStatusLabelNetwork, toolStripStatusLabelstatus, toolStripStatusLabelaccount, toolStripStatusLabelMultisig, toolStripStatusLabelLedger, toolStripSplitButtonlogout, toolStripDropDownButtonHelp });
statusStripmain.Location = new Point(0, 0);
statusStripmain.Name = "statusStripmain";
statusStripmain.Size = new Size(1152, 22);
@@ -183,12 +186,20 @@ namespace FireWallet
toolStripStatusLabelaccount.Size = new Size(55, 17);
toolStripStatusLabelaccount.Text = "Account:";
//
+ // toolStripStatusLabelMultisig
+ //
+ toolStripStatusLabelMultisig.Margin = new Padding(50, 3, 50, 2);
+ toolStripStatusLabelMultisig.Name = "toolStripStatusLabelMultisig";
+ toolStripStatusLabelMultisig.Size = new Size(50, 17);
+ toolStripStatusLabelMultisig.Text = "Multisig";
+ toolStripStatusLabelMultisig.Visible = false;
+ //
// toolStripStatusLabelLedger
//
toolStripStatusLabelLedger.Margin = new Padding(50, 3, 50, 2);
toolStripStatusLabelLedger.Name = "toolStripStatusLabelLedger";
- toolStripStatusLabelLedger.Size = new Size(71, 17);
- toolStripStatusLabelLedger.Text = "Cold Wallet:";
+ toolStripStatusLabelLedger.Size = new Size(68, 17);
+ toolStripStatusLabelLedger.Text = "Cold Wallet";
toolStripStatusLabelLedger.Visible = false;
//
// toolStripSplitButtonlogout
@@ -356,6 +367,8 @@ namespace FireWallet
// panelNav
//
panelNav.Controls.Add(buttonNavSettings);
+ panelNav.Controls.Add(buttonMultiSettings);
+ panelNav.Controls.Add(buttonMultiSign);
panelNav.Controls.Add(buttonBatch);
panelNav.Controls.Add(buttonNavDomains);
panelNav.Controls.Add(buttonNavReceive);
@@ -380,6 +393,19 @@ namespace FireWallet
buttonNavSettings.UseVisualStyleBackColor = true;
buttonNavSettings.Click += buttonNavSettings_Click;
//
+ // buttonMultiSign
+ //
+ buttonMultiSign.FlatStyle = FlatStyle.Flat;
+ buttonMultiSign.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ buttonMultiSign.Location = new Point(12, 301);
+ buttonMultiSign.Name = "buttonMultiSign";
+ buttonMultiSign.Size = new Size(89, 30);
+ buttonMultiSign.TabIndex = 3;
+ buttonMultiSign.TabStop = false;
+ buttonMultiSign.Text = "Import TX";
+ buttonMultiSign.UseVisualStyleBackColor = true;
+ buttonMultiSign.Click += buttonMultiSign_Click;
+ //
// buttonBatch
//
buttonBatch.FlatStyle = FlatStyle.Flat;
@@ -459,6 +485,18 @@ namespace FireWallet
panelPortfolio.TabIndex = 7;
panelPortfolio.Visible = false;
//
+ // buttonSendAll
+ //
+ buttonSendAll.FlatStyle = FlatStyle.Flat;
+ buttonSendAll.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ buttonSendAll.Location = new Point(761, 12);
+ buttonSendAll.Name = "buttonSendAll";
+ buttonSendAll.Size = new Size(106, 44);
+ buttonSendAll.TabIndex = 9;
+ buttonSendAll.Text = "Send All TXs";
+ buttonSendAll.UseVisualStyleBackColor = true;
+ buttonSendAll.Click += buttonSendAll_Click;
+ //
// buttonRedeemAll
//
buttonRedeemAll.FlatStyle = FlatStyle.Flat;
@@ -1121,17 +1159,18 @@ namespace FireWallet
textBoxExTX.Size = new Size(307, 29);
textBoxExTX.TabIndex = 1;
//
- // buttonSendAll
+ // buttonMultiSettings
//
- buttonSendAll.FlatStyle = FlatStyle.Flat;
- buttonSendAll.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
- buttonSendAll.Location = new Point(761, 12);
- buttonSendAll.Name = "buttonSendAll";
- buttonSendAll.Size = new Size(106, 44);
- buttonSendAll.TabIndex = 9;
- buttonSendAll.Text = "Send All TXs";
- buttonSendAll.UseVisualStyleBackColor = true;
- buttonSendAll.Click += buttonSendAll_Click;
+ buttonMultiSettings.FlatStyle = FlatStyle.Flat;
+ buttonMultiSettings.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point);
+ buttonMultiSettings.Location = new Point(12, 466);
+ buttonMultiSettings.Name = "buttonMultiSettings";
+ buttonMultiSettings.Size = new Size(89, 30);
+ buttonMultiSettings.TabIndex = 3;
+ buttonMultiSettings.TabStop = false;
+ buttonMultiSettings.Text = "Multisig";
+ buttonMultiSettings.UseVisualStyleBackColor = true;
+ buttonMultiSettings.Click += buttonMultiSettings_Click;
//
// MainForm
//
@@ -1281,5 +1320,8 @@ namespace FireWallet
private ToolStripMenuItem otherProjectsToolStripMenuItem;
private Button buttonRedeemAll;
private Button buttonSendAll;
+ private ToolStripStatusLabel toolStripStatusLabelMultisig;
+ private Button buttonMultiSign;
+ private Button buttonMultiSettings;
}
}
\ No newline at end of file
diff --git a/FireWallet/MainForm.cs b/FireWallet/MainForm.cs
index e0b4def..1bd227a 100644
--- a/FireWallet/MainForm.cs
+++ b/FireWallet/MainForm.cs
@@ -1,17 +1,17 @@
using System.Diagnostics;
-using System.Runtime.InteropServices;
-using Newtonsoft.Json.Linq;
-using Point = System.Drawing.Point;
-using Size = System.Drawing.Size;
-using QRCoder;
-using System.Text.RegularExpressions;
-using System.Security.Cryptography;
-using System.Text;
using System.Net;
+using System.Net.Security;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Text.RegularExpressions;
using DnsClient;
using DnsClient.Protocol;
-using System.Security.Cryptography.X509Certificates;
-using System.Net.Security;
+using Newtonsoft.Json.Linq;
+using QRCoder;
+using Point = System.Drawing.Point;
+using Size = System.Drawing.Size;
namespace FireWallet
{
@@ -37,6 +37,7 @@ namespace FireWallet
// Batching variables
public bool BatchMode { get; set; }
public BatchForm BatchForm { get; set; }
+ public bool multiSig { get; set; }
#endregion
#region Application
public MainForm()
@@ -767,28 +768,59 @@ namespace FireWallet
if (jObject["watchOnly"].ToString() == "True")
{
WatchOnly = true;
- toolStripStatusLabelLedger.Text = "Cold Wallet";
toolStripStatusLabelLedger.Visible = true;
+ buttonAddressVerify.Visible = true;
+ }
+ else
+ {
+ WatchOnly = false;
+ toolStripStatusLabelLedger.Visible = false;
+ buttonAddressVerify.Visible = false;
+ }
+
+ path = "wallet/" + Account + "/account/default";
+ APIresponse = await APIGet(path, true);
+ if (APIresponse.Contains("Error"))
+ {
+ AddLog("Error getting default account");
+ multiSig = false;
+ }
+ else
+ {
+ jObject = JObject.Parse(APIresponse);
+ if (jObject["n"].ToString() == "1")
+ {
+ multiSig = false;
+ }
+ else
+ {
+ multiSig = true;
+ }
+ }
+
+ if (multiSig)
+ {
+ toolStripStatusLabelMultisig.Visible = true;
+ buttonMultiSettings.Visible = true;
+ }
+ else
+ {
+ toolStripStatusLabelMultisig.Visible = false;
+ buttonMultiSettings.Visible = false;
+ }
+ if (WatchOnly || multiSig)
+ {
buttonRevealAll.Visible = false;
buttonRedeemAll.Visible = false;
buttonSendAll.Visible = false;
}
else
{
- WatchOnly = false;
- toolStripStatusLabelLedger.Visible = false;
buttonRevealAll.Visible = true;
buttonRedeemAll.Visible = true;
buttonSendAll.Visible = true;
}
- if (WatchOnly)
- {
- buttonAddressVerify.Visible = true;
- }
- else
- {
- buttonAddressVerify.Visible = false;
- }
+
return true;
}
@@ -1495,6 +1527,12 @@ namespace FireWallet
}
#endregion
#region Nav
+ private void buttonMultiSign_Click(object sender, EventArgs e)
+ {
+ ImportTXForm importTXForm = new ImportTXForm(this);
+ importTXForm.ShowDialog();
+ importTXForm.Dispose();
+ }
private async void PortfolioPanel_Click(object sender, EventArgs e)
{
hidePages();
@@ -1763,7 +1801,8 @@ namespace FireWallet
{
labelSendingError.Show();
labelSendingError.Text = "HIP-02 lookup failed";
- } else
+ }
+ else
{
labelSendingHIPAddress.Text = address;
labelSendingHIPAddress.Show();
@@ -1887,7 +1926,7 @@ namespace FireWallet
return;
}
- if (!WatchOnly)
+ if (!WatchOnly && !multiSig)
{
string content = "{\"method\": \"sendtoaddress\",\"params\": [ \"" + address + "\", " +
amount.ToString() + ", \"\", \"\", " + subtractFee + " ]}";
@@ -1897,7 +1936,10 @@ namespace FireWallet
{
AddLog("Failed:");
AddLog(APIresp.ToString());
- NotifyForm notify = new NotifyForm("Error Transaction Failed");
+ JObject error = JObject.Parse(APIresp["error"].ToString());
+ string ErrorMessage = error["message"].ToString();
+
+ NotifyForm notify = new NotifyForm("Error Transaction Failed\n" + ErrorMessage);
notify.ShowDialog();
return;
}
@@ -1912,96 +1954,156 @@ namespace FireWallet
labelSendingError.Text = "";
buttonNavPortfolio.PerformClick();
}
- else // Cold wallet signing
+ else // Cold or multisig wallet signing
{
- AddLog("Sending CW " + amount.ToString() + " HNS to " + address);
-
- if (!Directory.Exists(dir + "hsd-ledger"))
+ if (multiSig)
{
- if (CheckNodeInstalled() == false)
+ if (!WatchOnly)
{
- AddLog("Node not installed");
- NotifyForm notify1 = new NotifyForm("Node not installed\nPlease install it to use Ledger");
- notify1.ShowDialog();
- notify1.Dispose();
- return;
+ string content = "{\"method\": \"createsendtoaddress\",\"params\": [ \"" + address + "\", " +
+ amount.ToString() + ", \"\", \"\", " + subtractFee + " ]}";
+ string output = await APIPost("", true, content);
+ JObject APIresp = JObject.Parse(output);
+ if (APIresp["error"].ToString() != "")
+ {
+ AddLog("Failed:");
+ 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();
+ return;
+ }
+ JObject result = JObject.Parse(APIresp["result"].ToString());
+ string hex = result["hex"].ToString();
+
+ content = "{\"tx\": \"" + hex + "\",\"passphrase\":\"" + Password + "\"}";
+ output = await APIPost("wallet/" + Account + "/sign", true, content);
+ if (!output.Contains("hex"))
+ {
+ AddLog("Failed:");
+ AddLog(APIresp.ToString());
+ NotifyForm notify = new NotifyForm("Error Transaction Failed\nCheck the logs");
+ notify.ShowDialog();
+ return;
+ }
+ ExportTransaction(output);
}
- AddLog("Installing hsd-ledger");
-
- // Try to install hsd-ledger
- try
+ else
{
- NotifyForm Notifyinstall = new NotifyForm("Installing hsd-ledger\nThis may take a few minutes\nDo not close FireWallet", false);
- Notifyinstall.Show();
- // Wait for the notification to show
- await Task.Delay(1000);
+ string content = "{\"method\": \"createsendtoaddress\",\"params\": [ \"" + address + "\", " +
+ amount.ToString() + ", \"\", \"\", " + subtractFee + " ]}";
+ string output = await APIPost("", true, content);
+ JObject APIresp = JObject.Parse(output);
+ if (APIresp["error"].ToString() != "")
+ {
+ AddLog("Failed:");
+ AddLog(APIresp.ToString());
+ JObject error = JObject.Parse(APIresp["error"].ToString());
+ string ErrorMessage = error["message"].ToString();
- string repositoryUrl = "https://github.com/handshake-org/hsd-ledger.git";
- string destinationPath = dir + "hsd-ledger";
- CloneRepository(repositoryUrl, destinationPath);
-
- Notifyinstall.CloseNotification();
- Notifyinstall.Dispose();
+ NotifyForm notify = new NotifyForm("Error Transaction Failed\n" + ErrorMessage);
+ notify.ShowDialog();
+ return;
+ }
+ string signed = signRaw(output, new string[0]);
+ ExportTransaction(signed);
}
- catch (Exception ex)
+
+
+ }
+ else // Cold wallet non multisig
+ {
+ AddLog("Sending CW " + amount.ToString() + " HNS to " + address);
+
+ if (!Directory.Exists(dir + "hsd-ledger"))
{
- NotifyForm notifyError = new NotifyForm("Error installing hsd-ledger\n" + ex.Message);
- AddLog(ex.Message);
+ if (CheckNodeInstalled() == false)
+ {
+ AddLog("Node not installed");
+ NotifyForm notify1 = new NotifyForm("Node not installed\nPlease install it to use Ledger");
+ notify1.ShowDialog();
+ notify1.Dispose();
+ return;
+ }
+ AddLog("Installing hsd-ledger");
+
+ // Try to install hsd-ledger
+ try
+ {
+ NotifyForm Notifyinstall = new NotifyForm("Installing hsd-ledger\nThis may take a few minutes\nDo not close FireWallet", false);
+ Notifyinstall.Show();
+ // Wait for the notification to show
+ await Task.Delay(1000);
+
+ string repositoryUrl = "https://github.com/handshake-org/hsd-ledger.git";
+ string destinationPath = dir + "hsd-ledger";
+ CloneRepository(repositoryUrl, destinationPath);
+
+ Notifyinstall.CloseNotification();
+ Notifyinstall.Dispose();
+ }
+ catch (Exception ex)
+ {
+ NotifyForm notifyError = new NotifyForm("Error installing hsd-ledger\n" + ex.Message);
+ AddLog(ex.Message);
+ notifyError.ShowDialog();
+ notifyError.Dispose();
+ return;
+ }
+
+ }
+
+ NotifyForm notify = new NotifyForm("Please confirm the transaction on your Ledger device", false);
+ notify.Show();
+
+ var proc = new Process();
+ proc.StartInfo.CreateNoWindow = true;
+ proc.StartInfo.RedirectStandardInput = true;
+ proc.StartInfo.RedirectStandardOutput = true;
+ proc.StartInfo.UseShellExecute = false;
+ proc.StartInfo.RedirectStandardError = true;
+ proc.StartInfo.FileName = "node.exe";
+ proc.StartInfo.Arguments = dir + "hsd-ledger/bin/hsd-ledger sendtoaddress " + textBoxSendingTo.Text
+ + " " + textBoxSendingAmount.Text + " --api-key " + NodeSettings["Key"] + " -w " + Account;
+ var outputBuilder = new StringBuilder();
+
+ // Event handler for capturing output data
+ proc.OutputDataReceived += (sender, args) =>
+ {
+ if (!string.IsNullOrEmpty(args.Data))
+ {
+ outputBuilder.AppendLine(args.Data);
+ }
+ };
+
+ proc.Start();
+ proc.BeginOutputReadLine();
+ proc.WaitForExit();
+
+ notify.CloseNotification();
+ notify.Dispose();
+
+ string output = outputBuilder.ToString();
+ AddLog(output);
+ if (output.Contains("Submitted TXID"))
+ {
+ string hash = output.Substring(output.IndexOf("Submitted TXID") + 16, 64);
+ 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 = "";
+ buttonNavPortfolio.PerformClick();
+ }
+ else
+ {
+ NotifyForm notifyError = new NotifyForm("Error Transaction Failed\nCheck logs for more details");
notifyError.ShowDialog();
notifyError.Dispose();
- return;
}
-
- }
-
- NotifyForm notify = new NotifyForm("Please confirm the transaction on your Ledger device", false);
- notify.Show();
-
- var proc = new Process();
- proc.StartInfo.CreateNoWindow = true;
- proc.StartInfo.RedirectStandardInput = true;
- proc.StartInfo.RedirectStandardOutput = true;
- proc.StartInfo.UseShellExecute = false;
- proc.StartInfo.RedirectStandardError = true;
- proc.StartInfo.FileName = "node.exe";
- proc.StartInfo.Arguments = dir + "hsd-ledger/bin/hsd-ledger sendtoaddress " + textBoxSendingTo.Text
- + " " + textBoxSendingAmount.Text + " --api-key " + NodeSettings["Key"] + " -w " + Account;
- var outputBuilder = new StringBuilder();
-
- // Event handler for capturing output data
- proc.OutputDataReceived += (sender, args) =>
- {
- if (!string.IsNullOrEmpty(args.Data))
- {
- outputBuilder.AppendLine(args.Data);
- }
- };
-
- proc.Start();
- proc.BeginOutputReadLine();
- proc.WaitForExit();
-
- notify.CloseNotification();
- notify.Dispose();
-
- string output = outputBuilder.ToString();
- AddLog(output);
- if (output.Contains("Submitted TXID"))
- {
- string hash = output.Substring(output.IndexOf("Submitted TXID") + 16, 64);
- 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 = "";
- buttonNavPortfolio.PerformClick();
- }
- else
- {
- NotifyForm notifyError = new NotifyForm("Error Transaction Failed\nCheck logs for more details");
- notifyError.ShowDialog();
- notifyError.Dispose();
}
}
@@ -2014,6 +2116,7 @@ namespace FireWallet
labelSendingError.Text = ex.Message;
}
}
+
public void CloneRepository(string repositoryUrl, string destinationPath)
{
try
@@ -2446,6 +2549,7 @@ namespace FireWallet
BatchMode = true;
}
BatchForm.AddBatch(domain, operation);
+ BatchForm.UpdateTheme();
}
public void AddBatch(string domain, string operation, decimal bid, decimal lockup)
@@ -2458,6 +2562,7 @@ namespace FireWallet
BatchMode = true;
}
BatchForm.AddBatch(domain, operation, bid, lockup);
+ BatchForm.UpdateTheme();
}
public void AddBatch(string domain, string operation, DNS[] updateRecords)
@@ -2469,6 +2574,7 @@ namespace FireWallet
BatchMode = true;
}
BatchForm.AddBatch(domain, operation, updateRecords);
+ BatchForm.UpdateTheme();
}
public void AddBatch(string domain, string operation, string address)
{
@@ -2479,6 +2585,7 @@ namespace FireWallet
BatchMode = true;
}
BatchForm.AddBatch(domain, operation, address);
+ BatchForm.UpdateTheme();
}
public void FinishBatch()
{
@@ -2622,5 +2729,170 @@ namespace FireWallet
#endregion
+
+ #region Multi
+ public async Task ExportTransaction(string rawTX)
+ {
+ return await ExportTransaction(rawTX, new string[0]);
+ }
+ public async Task ExportTransaction(string rawTX, string[] domains)
+ {
+ JObject tx = JObject.Parse(rawTX);
+ JObject toExport = new JObject();
+ toExport["version"] = 1;
+ toExport["tx"] = tx["hex"];
+ JArray inputsParsed = new JArray();
+ JArray outputsParsed = new JArray();
+ JArray inputs = JArray.Parse(tx["inputs"].ToString());
+ JArray outputs = JArray.Parse(tx["outputs"].ToString());
+
+ Dictionary hashes = new Dictionary();
+ foreach (string domain in domains)
+ {
+ // sha3 hash of domain
+ hashes.Add(CalculateSHA3Hash(domain), domain);
+ }
+
+ foreach (JObject input in inputs)
+ {
+ JObject coin = JObject.Parse(input["coin"].ToString());
+ JObject covenant = JObject.Parse(coin["covenant"].ToString());
+ string type = covenant["type"].ToString();
+ JObject data = new JObject();
+ if (type == "0")
+ {
+ inputsParsed.Add(data);
+ }
+ else
+ {
+ AddLog("Not supported yet");
+ return "Error";
+ }
+ }
+ foreach (JObject output in outputs)
+ {
+ JObject covenant = JObject.Parse(output["covenant"].ToString());
+ string type = covenant["type"].ToString();
+ JObject data = new JObject();
+ if (type == "0")
+ {
+ outputsParsed.Add(data);
+ }
+ else
+ {
+ string hash = covenant["items"][0].ToString();
+ if (hashes.ContainsKey(hash))
+ {
+ data["name"] = hashes[hash];
+ }
+ else
+ {
+ AddLog("Cannot find name for hash " + hash);
+ return "Error";
+ }
+
+ //data["name"];
+ outputsParsed.Add(data);
+ }
+ }
+ JObject metadata = new JObject();
+ metadata["inputs"] = inputsParsed;
+ metadata["outputs"] = outputsParsed;
+ toExport["metadata"] = metadata;
+
+ SaveFileDialog saveFileDialog = new SaveFileDialog
+ {
+ Filter = "JSON file (*.json)|*.json",
+ Title = "Save transaction as JSON"
+ };
+ if (saveFileDialog.ShowDialog() == DialogResult.OK)
+ {
+ StreamWriter sw = new StreamWriter(saveFileDialog.FileName);
+ sw.Write(toExport.ToString());
+ sw.Dispose();
+ return toExport.ToString();
+ }
+ else
+ {
+ return "Error";
+ }
+ }
+ public string signRaw(string tx, string[] domains)
+ {
+ string domainslist = string.Join(",", domains.Select(domain => "\\\"" + domain + "\\\""));
+ NotifyForm notify = new NotifyForm("Please confirm the transaction on your Ledger device", false);
+ notify.Show();
+
+ var proc = new Process();
+ proc.StartInfo.CreateNoWindow = true;
+ proc.StartInfo.RedirectStandardInput = true;
+ proc.StartInfo.RedirectStandardOutput = true;
+ proc.StartInfo.UseShellExecute = false;
+ proc.StartInfo.RedirectStandardError = true;
+ proc.StartInfo.FileName = "node.exe";
+ proc.StartInfo.WorkingDirectory = dir + "hsd-ledger/bin/";
+ string args = "hsd-ledger/bin/hsd-ledger signraw \"\"" + tx.Replace("\"", "\\\"").Trim() + "\"\" [" + domainslist + "] --api-key " + NodeSettings["Key"] + " -w " + Account;
+ AddLog(args);
+
+ proc.StartInfo.Arguments = dir + args;
+ var outputBuilder = new StringBuilder();
+
+ // Event handler for capturing output data
+ proc.OutputDataReceived += (sender, args) =>
+ {
+ if (!string.IsNullOrEmpty(args.Data))
+ {
+ outputBuilder.AppendLine(args.Data);
+ }
+ };
+
+ proc.Start();
+ proc.BeginOutputReadLine();
+ proc.WaitForExit();
+
+ notify.CloseNotification();
+ notify.Dispose();
+
+ string output = outputBuilder.ToString();
+ AddLog(output);
+ if (output.Length > 2)
+ {
+ // Signed
+ return output;
+ }
+ else
+ {
+ AddLog(args);
+ AddLog(proc.StandardError.ReadToEnd());
+ NotifyForm notifyError = new NotifyForm("Error sign Failed\nCheck logs for more details");
+ notifyError.ShowDialog();
+ notifyError.Dispose();
+ return "Error";
+ }
+ }
+ static string CalculateSHA3Hash(string input)
+ {
+ var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(256);
+
+ // Choose correct encoding based on your usecase
+ byte[] inputBytes = Encoding.UTF8.GetBytes(input);
+
+ hashAlgorithm.BlockUpdate(inputBytes, 0, inputBytes.Length);
+
+ byte[] result = new byte[256 / 8];
+ hashAlgorithm.DoFinal(result, 0);
+
+ string hashString = BitConverter.ToString(result);
+ hashString = hashString.Replace("-", "").ToLowerInvariant();
+ return hashString;
+ }
+ private void buttonMultiSettings_Click(object sender, EventArgs e)
+ {
+ MultisigSettingsForm multisigSettingsForm = new MultisigSettingsForm(this);
+ multisigSettingsForm.Show();
+ }
+ #endregion
+
+
}
}
\ No newline at end of file
diff --git a/FireWallet/MultisigSettingsForm.Designer.cs b/FireWallet/MultisigSettingsForm.Designer.cs
new file mode 100644
index 0000000..6842c55
--- /dev/null
+++ b/FireWallet/MultisigSettingsForm.Designer.cs
@@ -0,0 +1,141 @@
+namespace FireWallet
+{
+ partial class MultisigSettingsForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MultisigSettingsForm));
+ groupBoxSigners = new GroupBox();
+ panelSigners = new Panel();
+ labelSigners = new Label();
+ groupBoxAddSig = new GroupBox();
+ buttoAddSigner = new Button();
+ textBoxAddSig = new TextBox();
+ labelAddXpub = new Label();
+ groupBoxSigners.SuspendLayout();
+ groupBoxAddSig.SuspendLayout();
+ SuspendLayout();
+ //
+ // groupBoxSigners
+ //
+ groupBoxSigners.Controls.Add(panelSigners);
+ groupBoxSigners.Location = new Point(0, 0);
+ groupBoxSigners.Name = "groupBoxSigners";
+ groupBoxSigners.Size = new Size(418, 463);
+ groupBoxSigners.TabIndex = 0;
+ groupBoxSigners.TabStop = false;
+ groupBoxSigners.Text = "Signers";
+ //
+ // panelSigners
+ //
+ panelSigners.Dock = DockStyle.Fill;
+ panelSigners.Location = new Point(3, 19);
+ panelSigners.Name = "panelSigners";
+ panelSigners.Size = new Size(412, 441);
+ panelSigners.TabIndex = 0;
+ //
+ // labelSigners
+ //
+ labelSigners.AutoSize = true;
+ labelSigners.Location = new Point(424, 9);
+ labelSigners.Name = "labelSigners";
+ labelSigners.Size = new Size(48, 15);
+ labelSigners.TabIndex = 1;
+ labelSigners.Text = "Signers:";
+ //
+ // groupBoxAddSig
+ //
+ groupBoxAddSig.Controls.Add(buttoAddSigner);
+ groupBoxAddSig.Controls.Add(textBoxAddSig);
+ groupBoxAddSig.Controls.Add(labelAddXpub);
+ groupBoxAddSig.Location = new Point(421, 255);
+ groupBoxAddSig.Name = "groupBoxAddSig";
+ groupBoxAddSig.Size = new Size(381, 208);
+ groupBoxAddSig.TabIndex = 2;
+ groupBoxAddSig.TabStop = false;
+ groupBoxAddSig.Text = "Add Signer";
+ //
+ // buttoAddSigner
+ //
+ buttoAddSigner.FlatStyle = FlatStyle.Flat;
+ buttoAddSigner.Location = new Point(6, 45);
+ buttoAddSigner.Name = "buttoAddSigner";
+ buttoAddSigner.Size = new Size(75, 23);
+ buttoAddSigner.TabIndex = 2;
+ buttoAddSigner.Text = "Add";
+ buttoAddSigner.UseVisualStyleBackColor = true;
+ buttoAddSigner.Click += buttoAddSigner_Click;
+ //
+ // textBoxAddSig
+ //
+ textBoxAddSig.Location = new Point(51, 16);
+ textBoxAddSig.Name = "textBoxAddSig";
+ textBoxAddSig.Size = new Size(324, 23);
+ textBoxAddSig.TabIndex = 1;
+ textBoxAddSig.KeyDown += textBoxAddSig_KeyDown;
+ //
+ // labelAddXpub
+ //
+ labelAddXpub.AutoSize = true;
+ labelAddXpub.Location = new Point(6, 19);
+ labelAddXpub.Name = "labelAddXpub";
+ labelAddXpub.Size = new Size(39, 15);
+ labelAddXpub.TabIndex = 0;
+ labelAddXpub.Text = "XPUB:";
+ //
+ // MultisigSettingsForm
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(814, 475);
+ Controls.Add(groupBoxAddSig);
+ Controls.Add(labelSigners);
+ Controls.Add(groupBoxSigners);
+ FormBorderStyle = FormBorderStyle.Fixed3D;
+ Icon = (Icon)resources.GetObject("$this.Icon");
+ MaximizeBox = false;
+ Name = "MultisigSettingsForm";
+ Text = "Multisig Settings";
+ Load += MultisigSettingsForm_Load;
+ groupBoxSigners.ResumeLayout(false);
+ groupBoxAddSig.ResumeLayout(false);
+ groupBoxAddSig.PerformLayout();
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private GroupBox groupBoxSigners;
+ private Label labelSigners;
+ private Panel panelSigners;
+ private GroupBox groupBoxAddSig;
+ private Button buttoAddSigner;
+ private TextBox textBoxAddSig;
+ private Label labelAddXpub;
+ }
+}
\ No newline at end of file
diff --git a/FireWallet/MultisigSettingsForm.cs b/FireWallet/MultisigSettingsForm.cs
new file mode 100644
index 0000000..982387c
--- /dev/null
+++ b/FireWallet/MultisigSettingsForm.cs
@@ -0,0 +1,216 @@
+using Newtonsoft.Json.Linq;
+
+namespace FireWallet
+{
+ public partial class MultisigSettingsForm : Form
+ {
+ MainForm mainForm;
+ int n;
+ int m;
+ int current;
+ string OwnKey;
+ public MultisigSettingsForm(MainForm mainForm)
+ {
+ InitializeComponent();
+ this.mainForm = mainForm;
+ this.BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]);
+ this.ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]);
+ foreach (Control c in Controls)
+ {
+ mainForm.ThemeControl(c);
+ }
+ }
+
+ private void MultisigSettingsForm_Load(object sender, EventArgs e)
+ {
+ UpdateInfo();
+ }
+ private async void UpdateInfo()
+ {
+ // Get multisig info
+ string infoResp = await mainForm.APIGet("wallet/" + mainForm.Account + "/account/default", true);
+ mainForm.AddLog(infoResp);
+
+ if (infoResp == "Error")
+ {
+ NotifyForm notifyForm = new NotifyForm("Error getting multisig info");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ this.Close();
+ }
+ JObject info = JObject.Parse(infoResp);
+ n = int.Parse(info["n"].ToString());
+ m = int.Parse(info["m"].ToString());
+ labelSigners.Text = "Signers: " + m + "/" + n;
+
+ panelSigners.Controls.Clear();
+ Panel selfInfo = new Panel();
+ selfInfo.Width = panelSigners.Width - SystemInformation.VerticalScrollBarWidth;
+ selfInfo.Height = 50;
+ selfInfo.Location = new Point(0, 0);
+ selfInfo.BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]);
+ selfInfo.ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]);
+ selfInfo.BorderStyle = BorderStyle.FixedSingle;
+
+ Label selfLabel = new Label();
+ selfLabel.Text = "Own Key";
+ selfLabel.Location = new Point(10, 10);
+ selfLabel.AutoSize = true;
+ selfInfo.Controls.Add(selfLabel);
+
+ Label pubKey = new Label();
+ OwnKey = info["accountKey"].ToString();
+ string pukKeyShort = info["accountKey"].ToString().Substring(0, 10) + "..." + info["accountKey"].ToString().Substring(info["accountKey"].ToString().Length - 10);
+
+ pubKey.Text = pukKeyShort;
+ pubKey.Location = new Point(10, 30);
+ pubKey.AutoSize = true;
+ selfInfo.Controls.Add(pubKey);
+
+ Button copyPubKey = new Button();
+ copyPubKey.Text = "Copy";
+ copyPubKey.AutoSize = true;
+ copyPubKey.FlatStyle = FlatStyle.Flat;
+ copyPubKey.Location = new Point(selfInfo.Width - copyPubKey.Width - 10, 10);
+ copyPubKey.Click += (s, e) =>
+ {
+ Clipboard.SetText(OwnKey);
+ };
+ selfInfo.Controls.Add(copyPubKey);
+ panelSigners.Controls.Add(selfInfo);
+
+ // Get signers
+ int y = 50;
+ JArray signers = JArray.Parse(info["keys"].ToString());
+ current = signers.Count;
+ foreach (string sig in signers)
+ {
+ Panel signerInfo = new Panel();
+ signerInfo.Width = panelSigners.Width - SystemInformation.VerticalScrollBarWidth;
+ signerInfo.Height = 50;
+ signerInfo.Location = new Point(0, y);
+ signerInfo.BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]);
+ signerInfo.ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]);
+ signerInfo.BorderStyle = BorderStyle.FixedSingle;
+
+ Label signerLabel = new Label();
+ signerLabel.Text = "Signer";
+ signerLabel.Location = new Point(10, 10);
+ signerLabel.AutoSize = true;
+ signerInfo.Controls.Add(signerLabel);
+
+ Label signerKey = new Label();
+ string signerKeyShort = sig.Substring(0, 10) + "..." + sig.Substring(sig.Length - 10);
+ signerKey.Text = signerKeyShort;
+ signerKey.Location = new Point(10, 30);
+ signerKey.AutoSize = true;
+ signerInfo.Controls.Add(signerKey);
+
+ Button DelSignerKey = new Button();
+ DelSignerKey.Text = "Remove";
+ DelSignerKey.AutoSize = true;
+ DelSignerKey.FlatStyle = FlatStyle.Flat;
+ DelSignerKey.Location = new Point(signerInfo.Width - DelSignerKey.Width - 10, 10);
+ DelSignerKey.Click += (s, e) =>
+ {
+ RemoveSig(sig);
+ };
+ signerInfo.Controls.Add(DelSignerKey);
+ panelSigners.Controls.Add(signerInfo);
+ y += 50;
+ }
+
+
+ }
+ private async Task RemoveSig(string sig)
+ {
+ string path = "wallet/" + mainForm.Account + "/shared-key";
+ string content = "{\"accountKey\": \"" + sig + "\",\"account\":\"default\"}";
+ string resp = await APIPut(path, true, content);
+ mainForm.AddLog(resp);
+ UpdateInfo();
+
+ }
+ private async Task AddSigAsync(string sig)
+ {
+ string path = "wallet/" + mainForm.Account + "/shared-key";
+ string content = "{\"accountKey\": \"" + sig + "\",\"account\":\"default\"}";
+ string resp = await APIPut(path, true, content);
+ mainForm.AddLog(resp);
+ UpdateInfo();
+ }
+
+ private async void buttoAddSigner_Click(object sender, EventArgs e)
+ {
+ if (textBoxAddSig.Text.Length < 5)
+ {
+ NotifyForm notifyForm = new NotifyForm("You need to add a XPUB key");
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ return;
+ }
+
+ await AddSigAsync(textBoxAddSig.Text);
+
+ textBoxAddSig.Text = "";
+ }
+
+ HttpClient httpClient = new HttpClient();
+ ///
+ /// Put to HSD API
+ ///
+ /// Path to put to
+ /// Whether to use port 12039
+ /// Content to put
+ ///
+ public async Task APIPut(string path, bool wallet, string content)
+ {
+ if (content == "{\"passphrase\": \"\",\"timeout\": 60}")
+ {
+ return "";
+ }
+ string key = mainForm.NodeSettings["Key"];
+ string ip = mainForm.NodeSettings["IP"];
+ string port = "1203";
+ if (mainForm.HSDNetwork == 1)
+ {
+ port = "1303";
+ }
+ if (wallet) port = port + "9";
+ else port = port + "7";
+
+ HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Put, "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)
+ {
+ mainForm.AddLog("Post Error: " + resp.StatusCode);
+ mainForm.AddLog(await resp.Content.ReadAsStringAsync());
+ return "Error";
+ }
+ return await resp.Content.ReadAsStringAsync();
+
+ }
+ catch (Exception ex)
+ {
+ mainForm.AddLog("Post Error: " + ex.Message);
+ return "Error";
+ }
+ }
+
+ private void textBoxAddSig_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Enter)
+ {
+ buttoAddSigner_Click(sender, e);
+ e.SuppressKeyPress = true;
+ }
+ }
+ }
+}
diff --git a/FireWallet/MultisigSettingsForm.resx b/FireWallet/MultisigSettingsForm.resx
new file mode 100644
index 0000000..0464da4
--- /dev/null
+++ b/FireWallet/MultisigSettingsForm.resx
@@ -0,0 +1,587 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA
+ IACoJQAA7h4AAAAAAAABACAAfScAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAI8/zACPQM0Aj0DNEo9AzVePQM02j0DNAI9AzQAAAAAAAAAAAI8/zQCPQM0Aj0DNNI9A
+ zViPQM0Sj0DNAI8/zACPQM0Uj0DNXY9AzcOPQM37j0DN1o9AzTuPQM0Ajz/NAI4/zACPQM0Aj0DNOY9A
+ zdWPQM37j0DNxI9AzV6PQM0Vj0DNso9AzfqPQM3/j0DN/49Azf+PQM3Wj0DNO49AzQCPQM0Aj0DNOY9A
+ zdSPQM3/j0DN/49Azf+PQM36j0DNtY9AzdmPQM3/j0DN/49Azf+PQM3/j0DN/49AzdaPQM05j0DNN49A
+ zdWPQM3/j0DN/49Azf+PQM3/j0DN/49AzdyRQ8XYkUPF/5FDxf+RQ8X/kUPF/5FDxf+RQ8X/kkPFsZJD
+ xa+RQ8X/kUPF/5FDxf+RQ8X/kUPF/5FDxf+RQ8Xbmkuu2JpLrv+aS67/mkuv/ppLrv6aS67/mkuu/5pL
+ r76aS6+9mkuu/5pLrv+aS67+mkuv/ppLrv+aS67/mkuu26VSkNilUpD/pVKQ/6RSkOajUZWrpVKQ+aVS
+ kP+lUpC+pVKQvKVSkP+lUpD6o1GVq6RSkOWlUpD/pVKQ/6VSkNuwVG3YsFRt/7BUbf+wVG3drlRzKq5U
+ c4+wVG3/sFRtv7BUbb6wVG3/rlRzka5UcymwVG3csFRt/7BUbf+wVG3cuVNI2blTSP+5U0j/uVNI3rlT
+ Rxy0VWELuFNOlblTSLq5U0i5uFNOlrRVYAy5U0cbuVNI3blTSP+5U0j/uVNI3MFQHtnBUB7/wVAe/8FQ
+ Ht/AUB4ewFAkAL5RMxC/USxQv1EsUL5RMxDAUCUAwFAeHMFQHt3BUB7/wVAe/8FQHtzDTwnZw08J/8NP
+ Cf/DTwnfw08JHsNPCQDETgAAx0wAAcdNAAHFTQAAw08JAMNPCR3DTwnew08J/8NPCf/DTwncw08J2MNP
+ Cf/DTwn/w08Jw8NPCRXDTwkAAAAAAAAAAAAAAAAAAAAAAMNPCQDDTwkUw08JwcNPCf/DTwn/w08J28NP
+ CdbDTwnbw08JfMNPCSHDTggAw08JAAAAAAAAAAAAAAAAAAAAAADCTwkAwU4HAMNPCSDDTwl7w08J28NP
+ CdjDTwlVw08JI8NOCAHDTwkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDTwgAwk4IAcNP
+ CSLDTwlWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAP//AADH4wAAA8AAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEIAAABmAAAAfg
+ AAAP8AAAH/gAAP//AAAoAAAAGAAAADAAAAABACAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI8/zACPP8wDjz/MAo8/
+ zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI8/zQCPP80Cjz/NA48/zQAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACPQM0Ajz/NBY9AzTePQM2Wj0DNYo4/zAOPP80AAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAj0DNAI8/zQKPQM1gj0DNl49AzTmPP80Fjz/NAAAAAAAAAAAAjz/NAI8/zQWPQM04j0DNm49A
+ zeuPQM3/j0DN749AzWeOP8wDjz/NAAAAAAAAAAAAAAAAAAAAAACPP80Ajz/MAo9AzWSPQM3uj0DN/49A
+ zeuPQM2dj0DNOY8/zQWPQM0Aj0DNN49AzZyPQM3rj0DN/49Azf+PQM3/j0DN/49Aze+PQM1njz/MA48/
+ zQAAAAAAAAAAAI9AzQCOP8wCj0DNZI9Aze6PQM3/j0DN/49Azf+PQM3/j0DN7I9AzZ6PQM05j0DNuY9A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3vj0DNZo4/zAOPQMwAjz/NAI8/zQKPQM1jj0DN7o9A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM2+j0DNwY9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN749AzWeOP84Djj7OAo9AzWWPQM3uj0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3Gj0DMwY9AzP+PQMz/j0DM/49AzP+PQMz/j0DM/49AzP+PQMz/j0DM/49AzPCPQMtZj0DLVo9A
+ zO+PQMz/j0DM/49AzP+PQMz/j0DM/49AzP+PQMz/j0DM/49AzP+PQMzFkkTDwJJEw/+SRMP/kkTD/5JE
+ w/+SRMP/kkTD/5JEw/+SRMP/kkTD/5JEw/+SRMOekkTDm5JEw/+SRMP/kkTD/5JEw/+SRMP/kkTD/5JE
+ w/+SRMP/kkTD/5JEw/+SRMPFmEqzwJhKs/+YSrP/mEqz/5hKs/+YSrP/mEqz/5hKs/+YSrP/mEqz/5hK
+ s/+YSrOfmEqznJhKs/+YSrP/mEqz/5hKs/+YSrP/mEqz/5hKs/+YSrP/mEqz/5hKs/+YSrPFn0+gwJ9P
+ oP+fT6D/n0+g/59PoP+fT6D2n0+h7J9PoP+fT6D/n0+g/59PoP+fT6Cfn0+gm59PoP+fT6D/n0+g/59P
+ oP+fT6Hsn0+g9p9PoP+fT6D/n0+g/59PoP+fT6DGp1OKwadTiv+nU4r/p1OK/6dTiv+nU4rdpVKPYqZT
+ jNynU4r/p1OK/6dTiv+nU4qfp1OKnKdTiv+nU4r/p1OK/6ZTjN6lUo9jp1OK26dTiv+nU4r/p1OK/6dT
+ iv+nU4rGrlRzwa5Uc/+uVHP/rlRz/65Uc/+uVHPdrlRzHKxUe0StVHTfrlRz/65Uc/+uVHOgrlRzna5U
+ c/+uVHP/rlR04KxUe0auVHMarlRz265Uc/+uVHP/rlRz/65Uc/+uVHPGtVRawbVUWv+1VFr/tVRa/7VU
+ Wv+1VFrdtVRaHLZTVgCzVWJHtFRc37VUWv+1VFqhtVRanbVUWv+0VFzhs1RiSbdTVAC1VFoatVRa27VU
+ Wv+1VFr/tVRa/7VUWv+1VFrHu1JBwbtSQf+7UkH/u1JB/7tSQf+7UkHdu1JBHbtSQgDAUikAuVNKR7tT
+ Q+K7UkGgu1JBnbtTQ+S5U0lJw1AYALtSQgC7UkEau1JB27tSQf+7UkH/u1JB/7tSQf+7UkHHwFAlwcBQ
+ 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
+ zf+PQM38j0DNl48/zA+PP80AAAAAAAAAAAAAAAAAAAAAAI9AzQCPQM0Oj0DNk49AzfuPQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/Y9AzdWPQM1ej0DNp49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM38j0DNl48/zA+PQM0AAAAAAAAAAACPQM0Aj0DNDo9AzZOPQM37j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Aza6PQM2oj0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM38j0DNl48/zRCPP80Aj0DNAI8/zQ+PQM2Uj0DN+49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DNr49AzaePQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM38j0DNmo4/zQ+PP80Oj0DNlo9A
+ zfyPQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM2ukEHKp5BB
+ yv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr9kEHJZ5BB
+ yWKQQcr8kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/5BByv+QQcr/kEHK/49B
+ yq6TRcGnk0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NF
+ wf+TRcGEk0XBf5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NFwf+TRcH/k0XB/5NF
+ wf+TRcH/k0XBrpdJtaeXSbX/l0m1/5dJtf+XSbX/l0m1/5dJtf+XSbX/l0m1/5dJtf+XSbX/l0m1/5dJ
+ tf+XSbX/l0m1/5dJtYKXSbZ9l0m1/5dJtf+XSbX/l0m1/5dJtf+XSbX/l0m1/5dJtf+XSbX/l0m1/5dJ
+ tf+XSbX/l0m1/5dJtf+XSbWunE2op5xNqP+cTaj/nE2o/5xNqP+cTaj/nE2o/5xNqP+cTaf/nE2o/5xN
+ qP+cTaj/nE2o/5xNqP+cTaj/nE2ogZxNqHycTaj/nE2o/5xNqP+cTaj/nE2o/5xNqP+cTaf/nE2o/5xN
+ qP+cTaj/nE2o/5xNqP+cTaj/nE2o/5xNqK6iUZinolGY/6JRmP+iUZj/olGY/6JRmP+iUZj/olGY6KFQ
+ mrmiUZj8olGY/6JRmP+iUZj/olGY/6JRmP+iUZiBolGYfKJRmP+iUZj/olGY/6JRmP+iUZj/olGY/KFQ
+ mrqiUZjnolGY/6JRmP+iUZj/olGY/6JRmP+iUZj/olGYrqhTh6eoU4f/qFOH/6hTh/+oU4f/qFOH/6hT
+ h/+oU4fcplOLL6dTip6oU4f9qFOH/6hTh/+oU4f/qFOH/6hTh4KnU4d9qFOH/6hTh/+oU4f/qFOH/6hT
+ h/6nU4qiplOLLqhTh9moU4f/qFOH/6hTh/+oU4f/qFOH/6hTh/+oU4evrVR2p61Udv+tVHb/rVR2/61U
+ dv+tVHb/rVR2/61UdtytVHYbqlSAEaxUeaGtVHb9rVR2/61Udv+tVHb/rVR2g61Udn6tVHb/rVR2/61U
+ dv+tVHb+rFR5pKpUfxOtVHYYrVR22q1Udv+tVHb/rVR2/61Udv+tVHb/rVR2/61Udq+yVGSoslVk/7JV
+ ZP+yVWT/slVk/7JVZP+yVWT/slVk3LJUZByxVWcAsFVtFLJVZ6KyVWT+slVk/7JVZP+yVGSEslRkf7JV
+ ZP+yVWT/slVk/rJVZqawVW0VsVRnALJUZBmyVGTZslVk/7JVZP+yVWT/slVk/7JVZP+yVWT/slRkr7dU
+ Uai3VFH/t1RR/7dUUf+3VFH/t1RR/7dUUf+3VFHct1NRHLdTUQC1VFoAtVRaFLdUVKO3VFH+t1RR/7dU
+ UYO3VFF+t1RR/7dUUf63VFSmtVRaFrVUWQC3U1EAt1NRGbdUUdm3VFH/t1RR/7dUUf+3VFH/t1RR/7dU
+ Uf+3VFGwvFI+qLxSPv+8Uj7/vFI+/7xSPv+8Uj7/vFI+/7xSPty7Uj4cu1I+AMNRHQC6U0cAulNIFLtS
+ QaG8Uj7/vFI+gbxSPny8Uj7/u1JBpbpTSBa6U0cAv1E0ALtSPgC7Uj4ZvFI+2bxSPv+8Uj7/vFI+/7xS
+ Pv+8Uj7/vFI+/7xSPrC/UCqov1Eq/79RKv+/USr/v1Eq/79RKv+/USr/v1Aq3b9QKRy/UCkAAAAAANJE
+ AAC+UTMAvlE0E79RLZ+/UCp6v1Eqdr9RLaK+UTQUvlEzAMNNFwAAAAAAv1ApAL9QKRm/UCrZv1Eq/79R
+ Kv+/USr/v1Eq/79RKv+/USr/v1AqsMJPEqjCTxL/wk8S/8JPEv/CTxL/wk8S/8JPEv/CTxLdwk8SHcJP
+ EgAAAAAAAAAAAAAAAADBTx4AwU8eE8FPHCfBUBwnwVAeFMFQHgD/AAAAAAAAAAAAAADCTxIAwk8SGsJP
+ EtrCTxL/wk8S/8JPEv/CTxL/wk8S/8JPEv/CTxKww08JqMNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NP
+ Cd7DTwgdw08IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMNP
+ CADDTwgaw08J2sNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCbDDTwmow08J/8NPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J3sNPCR3DTwkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAw08JAMNPCRvDTwnbw08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08Jr8NPCafDTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwndw08JHMNPCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAADDTwkAw08JGsNPCdrDTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwmuw08Jp8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J88NPCZrDTgkMw08JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMJPCQDCTwkKw08JlsNPCfLDTwn/w08J/8NPCf/DTwn/w08J/8NP
+ Ca3DTwmmw08J/8NPCf/DTwn/w08J8sNPCavDTwlGw08JCcNPCQDCTgcAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw08GAMNPCQDCTwgIw08JRMNPCanDTwnxw08J/8NP
+ Cf/DTwn/w08JrMNPCaTDTwn/w08J8cNPCazDTwlGw04ICcNPCADDTgkAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMFMCQDDTwkAwk8JCMNP
+ CUTDTwmqw08J8cNPCf/DTwmqw08JkcNPCarDTwlFw08ICcNPCQDCTAgAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADCTwYAw08JAMNPCQjDTwlDw08JqcNPCZbDTwkXw08JCcNPCQC/SwUAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAw00FAMNPCQDDTgkIw04JGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////5/
+ /j/4P/wf4B/4B4AP8AAAB+AAAAPAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA
+ AgAAYAYAAHAOAAB4HgAAfD4AAH/+AAB//gAAf/4AAH/+AAD//wAD///AD///8D////z//////////ygA
+ AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjz7LAI8+
+ ywCPPssAjz7LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjkDLAI4/ywCOP8sAjkDLAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI5A
+ zACOP8wBjz/NJY9AzXmPQM1Ig0LIAI5AzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOP8wAkkfWAI9AzUOPQM17j0DNKI8/
+ zQKPP80AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACPP8wAjj/LAY8/zCaPQM2Cj0DN3I9Azf+PQM3hj0DNToQ2wQCOP8wAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI8/zQCORMsAj0DNSI9A
+ zd6PQM3/j0DN3o9AzYWPP80ojj7MAo8/zQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAjz/NAI8+zAGPQM0mj0DNgo9AzdyPQM3+j0DN/49Azf+PQM3/j0DN449AzU+QPcsAjz/NAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjz/NAI9J
+ zwCPQM1Jj0DN349Azf+PQM3/j0DN/49Azf6PQM3ej0DNhY8/zSiPPswCjz/MAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAI8/zACOPswCjz/NJ49AzYOPQM3dj0DN/o9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zeSPQM1QijbKAI4/zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACOP8wAk0XXAI9AzUqPQM3gj0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/o9Azd+PQM2Gjz/NKY8/
+ zAKPP80AAAAAAAAAAACPP8wAjj7MAo9AzSqPQM2Fj0DN3o9Azf6PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3kjz/NT4w6xgCOP8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAI8/zQCTS84Ajz/NSo9AzeCPQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3+j0DN349AzYiPP80sjj/NA44/zQCPQM0Xj0DNhI9AzeGPQM3+j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN449AzVCQLsMAjz/MAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAjj/NAJJB0ACPQM1Kj0DN4I9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf6PQM3jj0DNiY8/zRqPQM1nj0DN+o9Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49AzeOPP81PhzjFAI4/
+ zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPQM0Ak0HLAI9AzUmPQM3gj0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/I8/zXOPQM11j0DN/Y9A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3jj0DNT4c/wwCOP8wAAAAAAAAAAAAAAAAAAAAAAI8/zQCNSs4Aj0DNSo9AzeCPQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/48/
+ zX+PQM11j0DN/Y9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN449AzVCNOM0Ajj/NAAAAAAAAAAAAjj/MAJdJ3gCPP81Kj0DN4I9A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/o8/zX6PQM10j0DN/Y9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49AzeSPQM1Si0HNAY5AzQCPP80AkDjLAI9A
+ zU2PQM3hj0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/o8/zX2PQM1zj0DN/Y9Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3mjz/NVY07
+ zwGRRsoAjz/NT49AzeOPQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/49A
+ zf+PQM3/j0DN/49Azf+PQM3/j0DN/49Azf+PQM3/j0DN/o8/zX2PQMtzj0DL/Y9Ay/+PQMv/j0DL/49A
+ y/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49A
+ y/+PQMv/j0DL349AyymPQMslj0DL2o9Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49A
+ y/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/49Ay/+PQMv/j0DL/o9Ay32RQ8ZykUPG/ZFD
+ xv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FD
+ xv+RQ8b/kUPG/5FDxv+RQ8b/kUPG+5FDxk2RQ8ZGkUPG+JFDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FD
+ xv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/5FDxv+RQ8b/kUPG/pFD
+ xn2URsBylEbA/ZRGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RG
+ wP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/JRGwFCURsBJlEbA+ZRGwP+URsD/lEbA/5RG
+ wP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RGwP+URsD/lEbA/5RG
+ wP+URsD/lEbA/pRGwH2XSbhyl0m4/ZdJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJ
+ uP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4+5dJuE6XSbhGl0m4+ZdJ
+ uP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJuP+XSbj/l0m4/5dJ
+ uP+XSbj/l0m4/5dJuP+XSbj/l0m4/pdJuH2aS69ymkyv/ZpMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pM
+ r/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv+5pM
+ r02aTK9Fmkyv+JpMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/5pM
+ r/+aTK//mkyv/5pMr/+aTK//mkyv/5pMr/+aTK//mkyv/ppMr32dTqVynU6l/Z1Opf+dTqX/nU6l/51O
+ pf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51O
+ pf+dTqX/nU6l+51OpU2dTqVEnU6l+J1Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51O
+ pf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/51Opf+dTqX/nU6l/p1OpX2hUJtyoVCb/aFQ
+ m/+hUJv/oVCb/6FQm/+hUJv/oVCb/6FQm/+hUJv/oVCb/6FQm+uhUJzHoVCb/aFQm/+hUJv/oVCb/6FQ
+ m/+hUJv/oVCb/6FQm/+hUJv/oVCb+6FQm02hUJtFoVCb+KFQm/+hUJv/oVCb/6FQm/+hUJv/oVCb/6FQ
+ m/+hUJv/oVCb/qFQnMihUJvpoVCb/6FQm/+hUJv/oVCb/6FQm/+hUJv/oVCb/6FQm/+hUJv/oVCb/qFQ
+ m32lUpBypVKQ/aVSkP+lUpD/pVKQ/6VSkP+lUpD/pVKQ/6VSkP+lUpD/pVKQ/6VSkNqkUpI3pFKRraVS
+ kP+lUpD/pVKQ/6VSkP+lUpD/pVKQ/6VSkP+lUpD/pVKQ+6VSkE2lUpBFpVKQ+KVSkP+lUpD/pVKQ/6VS
+ kP+lUpD/pVKQ/6VSkP+lUpD/pFKRsqRSkzalUpDVpVKQ/6VSkP+lUpD/pVKQ/6VSkP+lUpD/pVKQ/6VS
+ kP+lUpD/pVKQ/qVSkH6oU4VzqFOF/ahThf+oU4X/qFOF/6hThf+oU4X/qFOF/6hThf+oU4X/qFOF/6hT
+ hdupU4QaplOKGahThq+oU4X/qFOF/6hThf+oU4X/qFOF/6hThf+oU4X/qFOF+6hThU6oU4VHqFOF+ahT
+ hf+oU4X/qFOF/6hThf+oU4X/qFOF/6hThf+oU4a0p1OKHalThBeoU4XXqFOF/6hThf+oU4X/qFOF/6hT
+ hf+oU4X/qFOF/6hThf+oU4X/qFOF/6hThX6sVHlzrFR5/axUef+sVHn/rFR5/6xUef+sVHn/rFR5/6xU
+ ef+sVHn/rFR5/6xUedqsVHkbq1R7AKpUfhusVHuwrFR5/6xUef+sVHn/rFR5/6xUef+sVHn/rFR5+6xU
+ eU+sVHlIrFR5+axUef+sVHn/rFR5/6xUef+sVHn/rFR5/6xUerWqVH4eq1R7AKxUeRisVHnWrFR5/6xU
+ ef+sVHn/rFR5/6xUef+sVHn/rFR5/6xUef+sVHn/rFR5/6xUeX+wVW1zsFVt/bBVbf+wVW3/sFVt/7BV
+ bf+wVW3/sFVt/7BVbf+wVW3/sFVt/7BVbdqwVW0bsFVtAK5VcQCuVHIcr1VvsrBVbf+wVW3/sFVt/7BV
+ bf+wVW3/sFVt+7BVbVCwVW1IsFVt+bBVbf+wVW3/sFVt/7BVbf+wVW3/r1Vutq5Uch+uVXEAsFVtALBV
+ bRewVW3WsFVt/7BVbf+wVW3/sFVt/7BVbf+wVW3/sFVt/7BVbf+wVW3/sFVt/7BVbX+zVGF0s1Rh/bNU
+ Yf+zVGH/s1Rh/7NUYf+zVGH/s1Rh/7NUYf+zVGH/s1Rh/7NUYdqzVGEbs1RhALJUZACyVWUAslVmHbNU
+ YrOzVGD/s1Rh/7NUYf+zVGH/s1Rh+7NUYVCzVGFJs1Rh+bNUYf+zVGH/s1Rh/7NUYP+zVGK3slVmILJV
+ ZQCyVGYAs1RhALNUYRezVGHVs1Rh/7NUYf+zVGH/s1Rh/7NUYf+zVGH/s1Rh/7NUYf+zVGH/s1Rh/7NU
+ YX+3VFR0t1RU/bdUVP+3VFT/t1RU/7dUVP+3VFT/t1RU/7dUVP+3VFT/t1RU/7dUVNq2VFQbtlRUAAAA
+ AAC5UE8AtVRZALVUWh62VFazt1RU/7dUVP+3VFT/t1RU+7dUVE+2VFRIt1RU+bdUVP+3VFT/t1RU/7ZU
+ Vri1VFohtVRZALZSVgAAAAAAtlNUALZTVBe2VFTVt1RU/7dUVP+3VFT/t1RU/7dUVP+3VFT/t1RU/7dU
+ VP+3VFT/t1RU/7ZUVIC6U0h0ulNI/bpTSP+6U0j/ulNI/7pTSP+6U0j/ulNI/7pTSP+6U0j/ulNI/7pT
+ SNq6U0gbulNIAAAAAAAAAAAAuFNPALlTTAC4U00euVNJs7pTSP+6U0j/uVNI+7lTSE65U0hGuVNI+bpT
+ SP+6U0j/uVNJt7hTTSG4U00AvlQ5AAAAAAAAAAAAuVNIALlTSBe5U0jVulNI/7pTSP+6U0j/ulNI/7pT
+ SP+6U0j/ulNI/7pTSP+6U0j/ulNI/7pTSIC8Ujt0vFI7/bxSO/+8Ujv/vFI7/7xSO/+8Ujv/vFI7/7xS
+ O/+8Ujv/vFI7/7xSO9q8UjsbvFI7AAAAAAAAAAAAAAAAALtRPwC7UkAAu1JBHbxSPbC8Ujv/vFI7+7xS
+ O0y8UjtEvFI7+LxSO/+8Ujy1u1JBILtSPwC7UkEAAAAAAAAAAAAAAAAAvFI7ALxSOxe8UjvVvFI7/7xS
+ O/+8Ujv/vFI7/7xSO/+8Ujv/vFI7/7xSO/+8Ujv/vFI7/7xSO4C/US11v1Et/b9RLf+/US3/v1Et/79R
+ Lf+/US3/v1Et/79RLf+/US3/v1Et/79RLdu/US0bv1EtAAAAAAAAAAAAAAAAAAAAAADAUBwAvlEzAL5R
+ NBq+US+rv1Et+L9RLUm/US1Cv1Et9r5RL7C+UTMdvlEzAMBOKwAAAAAAAAAAAAAAAAAAAAAAvlEtAL5R
+ LRe/US3Vv1Et/79RLf+/US3/v1Et/79RLf+/US3/v1Et/79RLf+/US3/v1Et/79RLYDBUB51wVAe/cFQ
+ Hv/BUB7/wVAe/8FQHv/BUB7/wVAe/8FQHv/BUB7/wVAe/8FQHtvBUB4cwVAeAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAwU8kAMBQJQDAUCYYwFAhm8FQH0DBUB86wVAhncBQJhvAUCUAwFAlAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAwVAeAMFPHhfBUB7WwVAe/8FQHv/BUB7/wVAe/8FQHv/BUB7/wVAe/8FQHv/BUB7/wVAe/8FQ
+ HoDCTw51wk8O/cNPDv/DTw7/w08O/8NPDv/DTw7/w08O/8NPDv/DTw7/w08O/8JPDtzCTw4cwk8OAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMM9AADCTxcAwk8WD8JPFg7CTxYNwk8WEMJPFwDETwUAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAwk8OAMJPDhjCTw7Ww08O/8NPDv/DTw7/w08O/8NPDv/DTw7/w08O/8NP
+ Dv/DTw7/w08O/8JPDoDDTwh0w08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NP
+ CdzDTggdw04IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwk8IAMJPCBjDTwnXw08J/8NPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCIDDTwl0w08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCdzDTwgdw08IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw04IAMNOCBnDTwnXw08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCX/DTwl0w08J/cNPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCd3DTwgdw08IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw08IAMNP
+ CBnDTwnYw08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCX/DTwlzw08J/cNP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCdzDTwgdw08IAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAw08IAMNPCBnDTwnYw08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/sNP
+ CX7DTwlzw08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCdXDTgkXw04JAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAwk8JAMJPCRTDTwnQw08J/8NPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NP
+ Cf/DTwn/w08J/sNPCX3DTwlyw08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/8NPCf/DTwn9w08J1cNP
+ CWjDTggEw04IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwk8IAMFOCAPDTwljw08J08NPCfzDTwn/w08J/8NP
+ Cf/DTwn/w08J/8NPCf/DTwn/w08J/sNPCXvDTwlxw08J/cNPCf/DTwn/w08J/8NPCf/DTwn/w08J/cNP
+ CdPDTwl0w04JHsNPBwHDTwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMJPCAC/TQcAw08JHMNP
+ CXHDTwnRw08J/MNPCf/DTwn/w08J/8NPCf/DTwn/w08J/sNPCXrDTwlww08J/cNPCf/DTwn/w08J/8NP
+ Cf3DTwnUw08JdMNOCR3DTQcAw04IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAwk4IAMFLBwDCTwkbw08JccNPCdHDTwn8w08J/8NPCf/DTwn/w08J/sNPCXjDTwluw08J/MNP
+ Cf/DTwn8w08J08NPCXXDTwkewU0EAMJOBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCTgkAv00KAMNOCBzDTwlyw08J0cNPCfzDTwn/w08J/sNP
+ CXbDTwltw08J+cNPCdDDTwlyw04JHcFPBgDCTggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMJOCQDDTgkAw08JG8NP
+ CW/DTwnOw08J+cNPCXXDTwlGw08JaMJPCRrATAUAwk4IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAwk8IAL5QBADDTwgZw08JaMNOCUrDTQgBw00IAMNNCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDTggAw04IAMNPCAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ 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
+ RU5ErkJggg==
+
+
+
\ No newline at end of file
diff --git a/FireWallet/NewAccountForm.Designer.cs b/FireWallet/NewAccountForm.Designer.cs
index b661948..6e4089b 100644
--- a/FireWallet/NewAccountForm.Designer.cs
+++ b/FireWallet/NewAccountForm.Designer.cs
@@ -46,9 +46,18 @@
label2 = new Label();
groupBoxSeed = new GroupBox();
textBoxSeedPhrase = new TextBox();
+ groupBoxMulti = new GroupBox();
+ numericUpDownM = new NumericUpDown();
+ numericUpDownN = new NumericUpDown();
+ label7 = new Label();
+ label6 = new Label();
+ checkBoxMulti = new CheckBox();
groupBoxMode.SuspendLayout();
groupBoxNew.SuspendLayout();
groupBoxSeed.SuspendLayout();
+ groupBoxMulti.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)numericUpDownM).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)numericUpDownN).BeginInit();
SuspendLayout();
//
// buttonNext
@@ -241,11 +250,74 @@
textBoxSeedPhrase.Size = new Size(438, 288);
textBoxSeedPhrase.TabIndex = 0;
//
+ // groupBoxMulti
+ //
+ groupBoxMulti.Controls.Add(numericUpDownM);
+ groupBoxMulti.Controls.Add(numericUpDownN);
+ groupBoxMulti.Controls.Add(label7);
+ groupBoxMulti.Controls.Add(label6);
+ groupBoxMulti.Controls.Add(checkBoxMulti);
+ groupBoxMulti.Location = new Point(125, 22);
+ groupBoxMulti.Name = "groupBoxMulti";
+ groupBoxMulti.Size = new Size(450, 319);
+ groupBoxMulti.TabIndex = 6;
+ groupBoxMulti.TabStop = false;
+ groupBoxMulti.Text = "Multisig";
+ //
+ // numericUpDownM
+ //
+ numericUpDownM.Location = new Point(223, 91);
+ numericUpDownM.Maximum = new decimal(new int[] { 1000, 0, 0, 0 });
+ numericUpDownM.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
+ numericUpDownM.Name = "numericUpDownM";
+ numericUpDownM.Size = new Size(120, 23);
+ numericUpDownM.TabIndex = 2;
+ numericUpDownM.Value = new decimal(new int[] { 1, 0, 0, 0 });
+ //
+ // numericUpDownN
+ //
+ numericUpDownN.Location = new Point(223, 55);
+ numericUpDownN.Maximum = new decimal(new int[] { 1000, 0, 0, 0 });
+ numericUpDownN.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
+ numericUpDownN.Name = "numericUpDownN";
+ numericUpDownN.Size = new Size(120, 23);
+ numericUpDownN.TabIndex = 2;
+ numericUpDownN.Value = new decimal(new int[] { 1, 0, 0, 0 });
+ //
+ // label7
+ //
+ label7.AutoSize = true;
+ label7.Location = new Point(6, 93);
+ label7.Name = "label7";
+ label7.Size = new Size(211, 15);
+ label7.TabIndex = 1;
+ label7.Text = "Required Signers to send a transaction:";
+ //
+ // label6
+ //
+ label6.AutoSize = true;
+ label6.Location = new Point(141, 61);
+ label6.Name = "label6";
+ label6.Size = new Size(76, 15);
+ label6.TabIndex = 1;
+ label6.Text = "Total Signers:";
+ //
+ // checkBoxMulti
+ //
+ checkBoxMulti.AutoSize = true;
+ checkBoxMulti.Location = new Point(6, 23);
+ checkBoxMulti.Name = "checkBoxMulti";
+ checkBoxMulti.Size = new Size(115, 19);
+ checkBoxMulti.TabIndex = 0;
+ checkBoxMulti.Text = "Create a multisig";
+ checkBoxMulti.UseVisualStyleBackColor = true;
+ //
// NewAccountForm
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(680, 430);
+ Controls.Add(groupBoxMulti);
Controls.Add(groupBoxSeed);
Controls.Add(buttonCancel);
Controls.Add(buttonNext);
@@ -263,6 +335,10 @@
groupBoxNew.PerformLayout();
groupBoxSeed.ResumeLayout(false);
groupBoxSeed.PerformLayout();
+ groupBoxMulti.ResumeLayout(false);
+ groupBoxMulti.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)numericUpDownM).EndInit();
+ ((System.ComponentModel.ISupportInitialize)numericUpDownN).EndInit();
ResumeLayout(false);
}
@@ -285,5 +361,11 @@
private Label label5;
private GroupBox groupBoxSeed;
private TextBox textBoxSeedPhrase;
+ private GroupBox groupBoxMulti;
+ private CheckBox checkBoxMulti;
+ private NumericUpDown numericUpDownM;
+ private NumericUpDown numericUpDownN;
+ private Label label7;
+ private Label label6;
}
}
\ No newline at end of file
diff --git a/FireWallet/NewAccountForm.cs b/FireWallet/NewAccountForm.cs
index a0ea6a4..deafc09 100644
--- a/FireWallet/NewAccountForm.cs
+++ b/FireWallet/NewAccountForm.cs
@@ -1,17 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Diagnostics;
-using System.Drawing;
-using System.Linq;
-using System.Net.Http;
-using System.Security.Principal;
+using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using Microsoft.VisualBasic.Devices;
+using Newtonsoft.Json.Linq;
namespace FireWallet
{
@@ -34,7 +24,7 @@ namespace FireWallet
{
mainForm.ThemeControl(c);
}
-
+ groupBoxMulti.Hide();
}
@@ -148,53 +138,179 @@ namespace FireWallet
if (page == 1)
{
- // Create new wallet
- buttonNext.Enabled = false;
- string path = "wallet/" + textBoxNewName.Text;
- string content = "{\"passphrase\":\"" + textBoxNewPass1.Text + "\"}";
- string response = await APIPut(path, true, content);
- if (response == "Error")
- {
- NotifyForm notify = new NotifyForm("Error creating wallet");
- notify.ShowDialog();
- notify.Dispose();
- buttonNext.Enabled = true;
- return;
- }
- mainForm.AddLog("Created wallet: " + textBoxNewName.Text);
- NotifyForm notify2 = new NotifyForm("Created wallet: " + textBoxNewName.Text);
- notify2.ShowDialog();
- notify2.Dispose();
- this.Close();
+ groupBoxMulti.Show();
+ page = 6;
}
else if (page == 2)
{
groupBoxSeed.Show();
- buttonNext.Text = "Import";
page = 3;
}
else if (page == 3)
{
- // Create new wallet
- buttonNext.Enabled = false;
- string path = "wallet/" + textBoxNewName.Text;
- string content = "{\"passphrase\":\"" + textBoxNewPass1.Text + "\",\"mnemonic\":\"" + textBoxSeedPhrase.Text + "\"}";
- string response = await APIPut(path, true, content);
- if (response == "Error")
- {
- NotifyForm notify = new NotifyForm("Error creating wallet");
- notify.ShowDialog();
- notify.Dispose();
- buttonNext.Enabled = true;
- return;
- }
- mainForm.AddLog("Created wallet: " + textBoxNewName.Text);
- NotifyForm notify2 = new NotifyForm("Imported wallet: " + textBoxNewName.Text);
- notify2.ShowDialog();
- notify2.Dispose();
- this.Close();
+ page = 5;
+ groupBoxMulti.Show();
+ buttonNext.Text = "Import";
}
+ else if (page == 5)
+ {
+ if (!checkBoxMulti.Checked)
+ {
+ // Import wallet from seed
+ buttonNext.Enabled = false;
+ string path = "wallet/" + textBoxNewName.Text;
+ string content = "{\"passphrase\":\"" + textBoxNewPass1.Text + "\",\"mnemonic\":\"" + textBoxSeedPhrase.Text + "\"}";
+ string response = await APIPut(path, true, content);
+ if (response == "Error")
+ {
+ NotifyForm notify = new NotifyForm("Error creating wallet");
+ notify.ShowDialog();
+ notify.Dispose();
+ buttonNext.Enabled = true;
+ return;
+ }
+ mainForm.AddLog("Created wallet: " + textBoxNewName.Text);
+ NotifyForm notify2 = new NotifyForm("Imported wallet: " + textBoxNewName.Text);
+ notify2.ShowDialog();
+ notify2.Dispose();
+ this.Close();
+ }
+ else
+ {
+ // Import wallet from seed and create multisig
+ buttonNext.Enabled = false;
+ string path = "wallet/" + textBoxNewName.Text;
+ string content = "{\"passphrase\":\"" + textBoxNewPass1.Text + "\",\"mnemonic\":\"" + textBoxSeedPhrase.Text + "\", \"type\":\"multisig\",\"m\":"+numericUpDownM.Value.ToString()+ ",\"n\":" +numericUpDownN.Value.ToString() + "}";
+ string response = await APIPut(path, true, content);
+ if (response == "Error")
+ {
+ NotifyForm notify = new NotifyForm("Error creating wallet");
+ notify.ShowDialog();
+ notify.Dispose();
+ buttonNext.Enabled = true;
+ return;
+ }
+ mainForm.AddLog("Created wallet: " + textBoxNewName.Text);
+ NotifyForm notify2 = new NotifyForm("Imported wallet: " + textBoxNewName.Text);
+ notify2.ShowDialog();
+ notify2.Dispose();
+ this.Close();
+ }
+ }
+ else if (page == 6)
+ {
+ if (!checkBoxMulti.Checked)
+ {
+ // Create new wallet
+ buttonNext.Enabled = false;
+ string path = "wallet/" + textBoxNewName.Text;
+ string content = "{}";
+ //content = "{\"passphrase\":\"" + textBoxNewPass1.Text + "\"}";
+ string response = await APIPut(path, true, content);
+ if (response == "Error")
+ {
+ NotifyForm notify = new NotifyForm("Error creating wallet");
+ notify.ShowDialog();
+ notify.Dispose();
+ buttonNext.Enabled = true;
+ return;
+ }
+ mainForm.AddLog("Created wallet: " + textBoxNewName.Text);
+
+ // Show SEED PHRASE
+ path = "wallet/" + textBoxNewName.Text + "/master";
+ response = await mainForm.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();
+ NotifyForm notifyForm = new NotifyForm("SEED PHRASE\nSTORE THIS SOMEWHERE SECURE\n" + phrase, "Copy", phrase, true);
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+ }
+
+ // Select wallet
+ content = "{\"method\":\"selectwallet\",\"params\":[\"" + textBoxNewName.Text + "\"]}";
+ response = await mainForm.APIPost("", true, content);
+ if (response == "Error")
+ {
+ NotifyForm notify = new NotifyForm("Error selecting wallet");
+ notify.ShowDialog();
+ notify.Dispose();
+ buttonNext.Enabled = true;
+ return;
+ }
+
+ // Encrypt wallet
+ content = "{\"method\":\"encryptwallet\",\"params\":[\"" + textBoxNewPass1.Text + "\"]}";
+ response = await mainForm.APIPost("", true, content);
+ if (response == "Error")
+ {
+ NotifyForm notify = new NotifyForm("Error encrypting wallet");
+ notify.ShowDialog();
+ notify.Dispose();
+ buttonNext.Enabled = true;
+ return;
+ }
+ mainForm.AddLog("Encrypted wallet: " + textBoxNewName.Text);
+ this.Close();
+ } else
+ {
+ // Create new wallet
+ buttonNext.Enabled = false;
+ string path = "wallet/" + textBoxNewName.Text;
+ string content = "{\"type\":\"multisig\",\"m\":"+numericUpDownM.Value.ToString()+ ",\"n\":" +numericUpDownN.Value.ToString() + "}";
+ string response = await APIPut(path, true, content);
+ if (response == "Error")
+ {
+ NotifyForm notify = new NotifyForm("Error creating wallet");
+ notify.ShowDialog();
+ notify.Dispose();
+ buttonNext.Enabled = true;
+ return;
+ }
+ path = "wallet/" + textBoxNewName.Text + "/master";
+ response = await mainForm.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();
+ NotifyForm notifyForm = new NotifyForm("SEED PHRASE\nSTORE THIS SOMEWHERE SECURE\n" + phrase, "Copy", phrase, true);
+ notifyForm.ShowDialog();
+ notifyForm.Dispose();
+
+ }
+ // Select wallet
+ content = "{\"method\":\"selectwallet\",\"params\":[\"" + textBoxNewName.Text + "\"]}";
+ response = await mainForm.APIPost("", true, content);
+ if (response == "Error")
+ {
+ NotifyForm notify = new NotifyForm("Error selecting wallet");
+ notify.ShowDialog();
+ notify.Dispose();
+ buttonNext.Enabled = true;
+ return;
+ }
+ // Encrypt wallet
+ content = "{\"method\":\"encryptwallet\",\"params\":[\"" + textBoxNewPass1.Text + "\"]}";
+ response = await mainForm.APIPost("", true, content);
+ if (response == "Error")
+ {
+ NotifyForm notify = new NotifyForm("Error encrypting wallet");
+ notify.ShowDialog();
+ notify.Dispose();
+ buttonNext.Enabled = true;
+ return;
+ }
+ mainForm.AddLog("Encrypted wallet: " + textBoxNewName.Text);
+ this.Close();
+
+ }
+ }
+
else if (page == 4)
{
try
@@ -228,7 +344,7 @@ namespace FireWallet
}
catch (Exception ex)
{
- mainForm.AddLog(ex.Message);
+ mainForm.AddLog(ex.Message);
NotifyForm notify = new NotifyForm("Error importing wallet\n" + ex.Message);
notify.ShowDialog();
notify.Dispose();
@@ -256,16 +372,17 @@ namespace FireWallet
HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Put, "http://" + ip + ":" + port + "/" + path);
req.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes("x:" + key)));
req.Content = new StringContent(content);
-
+
try
{
// Send request
HttpResponseMessage resp = await httpClient.SendAsync(req);
-
+
if (resp.IsSuccessStatusCode)
{
return await resp.Content.ReadAsStringAsync();
- } else
+ }
+ else
{
mainForm.AddLog("Put Error: " + await resp.Content.ReadAsStringAsync());
return "Error";
@@ -277,7 +394,7 @@ namespace FireWallet
return "Error";
}
-
+
}
}
}
diff --git a/FireWalletSetup/FireWalletSetup.vdproj b/FireWalletSetup/FireWalletSetup.vdproj
index 1c4b3bd..0b2b2d6 100644
--- a/FireWalletSetup/FireWalletSetup.vdproj
+++ b/FireWalletSetup/FireWalletSetup.vdproj
@@ -224,15 +224,15 @@
{
"Name" = "8:Microsoft Visual Studio"
"ProductName" = "8:FireWallet"
- "ProductCode" = "8:{E636567F-DDA4-4C6E-89B0-38DC64FD5528}"
- "PackageCode" = "8:{AEAF1ABA-01E0-4A71-A8CC-0D6DDA44E907}"
+ "ProductCode" = "8:{E904E664-B1F3-4DEB-9FB0-91BCBEE3B5A6}"
+ "PackageCode" = "8:{0B16637D-C5AC-41D4-9D13-D57F3A0AEF25}"
"UpgradeCode" = "8:{0C86F725-6B01-4173-AA05-3F0EDF481362}"
"AspNetVersion" = "8:"
"RestartWWWService" = "11:FALSE"
"RemovePreviousVersions" = "11:TRUE"
"DetectNewerInstalledVersion" = "11:TRUE"
"InstallAllUsers" = "11:FALSE"
- "ProductVersion" = "8:3.4"
+ "ProductVersion" = "8:4.0"
"Manufacturer" = "8:Nathan.Woodburn/"
"ARPHELPTELEPHONE" = "8:"
"ARPHELPLINK" = "8:https://l.woodburn.au/discord"