From 6da345e65012ff81424134528e39c710595576d9 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Mon, 26 Jun 2023 18:13:08 +1000 Subject: [PATCH] multisig: Added info on signers Added variables to track the number of total signers, required signers and signed signatures. Also added code to get multisig information from transaction inputs and display it in the UI. --- FireWallet/ImportTXForm.Designer.cs | 79 ++++++++++++++++-- FireWallet/ImportTXForm.cs | 125 +++++++++++++++++++++++----- 2 files changed, 174 insertions(+), 30 deletions(-) diff --git a/FireWallet/ImportTXForm.Designer.cs b/FireWallet/ImportTXForm.Designer.cs index 0ce2c2b..2e46a28 100644 --- a/FireWallet/ImportTXForm.Designer.cs +++ b/FireWallet/ImportTXForm.Designer.cs @@ -35,6 +35,11 @@ panelOut = new Panel(); buttonSign = new Button(); Cancelbutton2 = new Button(); + label1 = new Label(); + labelSigsTotal = new Label(); + labelSigsReq = new Label(); + labelSigsSigned = new Label(); + labelSigInfo = new Label(); groupBoxIn.SuspendLayout(); groupBoxOut.SuspendLayout(); SuspendLayout(); @@ -44,7 +49,7 @@ groupBoxIn.Controls.Add(panelIn); groupBoxIn.Location = new Point(12, 83); groupBoxIn.Name = "groupBoxIn"; - groupBoxIn.Size = new Size(341, 355); + groupBoxIn.Size = new Size(376, 355); groupBoxIn.TabIndex = 3; groupBoxIn.TabStop = false; groupBoxIn.Text = "Inputs"; @@ -55,15 +60,15 @@ panelIn.Dock = DockStyle.Fill; panelIn.Location = new Point(3, 19); panelIn.Name = "panelIn"; - panelIn.Size = new Size(335, 333); + panelIn.Size = new Size(370, 333); panelIn.TabIndex = 0; // // groupBoxOut // groupBoxOut.Controls.Add(panelOut); - groupBoxOut.Location = new Point(359, 83); + groupBoxOut.Location = new Point(391, 80); groupBoxOut.Name = "groupBoxOut"; - groupBoxOut.Size = new Size(429, 355); + groupBoxOut.Size = new Size(484, 355); groupBoxOut.TabIndex = 0; groupBoxOut.TabStop = false; groupBoxOut.Text = "Outputs"; @@ -74,25 +79,26 @@ panelOut.Dock = DockStyle.Fill; panelOut.Location = new Point(3, 19); panelOut.Name = "panelOut"; - panelOut.Size = new Size(423, 333); + 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(705, 444); + buttonSign.Location = new Point(789, 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(616, 444); + Cancelbutton2.Location = new Point(700, 444); Cancelbutton2.Name = "Cancelbutton2"; Cancelbutton2.Size = new Size(83, 36); Cancelbutton2.TabIndex = 2; @@ -100,11 +106,60 @@ Cancelbutton2.UseVisualStyleBackColor = true; Cancelbutton2.Click += Cancelbutton2_Click; // + // 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 = "#"; + // // ImportTXForm // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(800, 485); + 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(Cancelbutton2); @@ -113,11 +168,12 @@ Icon = (Icon)resources.GetObject("$this.Icon"); MaximizeBox = false; Name = "ImportTXForm"; - Text = "ImportTXForm"; + Text = "Import TX"; Load += ImportTXForm_Load; groupBoxIn.ResumeLayout(false); groupBoxOut.ResumeLayout(false); ResumeLayout(false); + PerformLayout(); } #endregion @@ -127,5 +183,10 @@ private Button Cancelbutton2; private Panel panelIn; private Panel panelOut; + private Label label1; + private Label labelSigsTotal; + private Label labelSigsReq; + private Label labelSigsSigned; + private Label labelSigInfo; } } \ No newline at end of file diff --git a/FireWallet/ImportTXForm.cs b/FireWallet/ImportTXForm.cs index d9696e9..ab9de67 100644 --- a/FireWallet/ImportTXForm.cs +++ b/FireWallet/ImportTXForm.cs @@ -6,6 +6,9 @@ namespace FireWallet { MainForm mainForm; JObject tx; + int totalSigs; + int reqSigs; + int sigs; public ImportTXForm(MainForm mainForm) { InitializeComponent(); @@ -14,6 +17,11 @@ namespace FireWallet private void ImportTXForm_Load(object sender, EventArgs e) { + // Default variables + totalSigs = 3; + reqSigs = 2; + sigs = 0; + // Theme this.BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]); this.ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]); @@ -74,6 +82,58 @@ namespace FireWallet 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; + + + + + for (int i = 0; i < inputs.Count; i++) { JObject input = (JObject)inputs[i]; @@ -84,11 +144,6 @@ namespace FireWallet PanelInput.Location = new Point(5, panelIn.Controls.Count * 50); PanelInput.BorderStyle = BorderStyle.FixedSingle; - Label txid = new Label(); - txid.Text = "TXID: " + input["txid"].ToString(); - txid.Location = new Point(5, 5); - txid.AutoSize = true; - PanelInput.Controls.Add(txid); if (metaInput.ContainsKey("sighashType")) { @@ -99,19 +154,40 @@ namespace FireWallet PanelInput.Controls.Add(sighashType); } - //Label address = new Label(); - //string addressString = input["address"].ToString().Substring(0, 5) + "..." + input["address"].ToString().Substring(input["address"].ToString().Length - 5, 5); - //address.Text = "Address: " + addressString; - //address.Location = new Point(5, 5); - //address.AutoSize = true; - //PanelInput.Controls.Add(address); + 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); + + } + - //Label amount = new Label(); - //Decimal value = Decimal.Parse(input["value"].ToString()) / 1000000; - //amount.Text = "Amount: " + value.ToString(); - //amount.Location = new Point(5, 25); - //amount.AutoSize = true; - //PanelInput.Controls.Add(amount); //if (input["path"].ToString() != "") //{ @@ -129,7 +205,7 @@ namespace FireWallet { 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); @@ -167,14 +243,14 @@ namespace FireWallet } bool own = false; - string addressResp = await mainForm.APIGet("wallet/" + mainForm.Account + "/key/" + addressRaw["string"].ToString(),true); + 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 - 100, 5); + ownAddress.Location = new Point(PanelOutput.Width - 150, 5); ownAddress.AutoSize = true; PanelOutput.Controls.Add(ownAddress); } @@ -182,11 +258,18 @@ namespace FireWallet Label amount = new Label(); Decimal value = Decimal.Parse(output["value"].ToString()); amount.Text = "Amount: " + value.ToString(); - amount.Location = new Point(PanelOutput.Width - 100, 25); + 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) + { + string content = "{\"tx\":\"" + tx["tx"].ToString() + "\", \"passphrase\":\"" + mainForm.Password + "\"}"; + string response = await mainForm.APIPost("wallet/" + mainForm.Account + "/sign", true, content); + mainForm.AddLog(response); + } } }