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.
This commit is contained in:
Nathan Woodburn 2023-06-26 18:13:08 +10:00
parent 5be4f0d6e9
commit 6da345e650
Signed by: nathanwoodburn
GPG Key ID: 203B000478AD0EF1
2 changed files with 174 additions and 30 deletions

View File

@ -35,6 +35,11 @@
panelOut = new Panel(); panelOut = new Panel();
buttonSign = new Button(); buttonSign = new Button();
Cancelbutton2 = new Button(); Cancelbutton2 = new Button();
label1 = new Label();
labelSigsTotal = new Label();
labelSigsReq = new Label();
labelSigsSigned = new Label();
labelSigInfo = new Label();
groupBoxIn.SuspendLayout(); groupBoxIn.SuspendLayout();
groupBoxOut.SuspendLayout(); groupBoxOut.SuspendLayout();
SuspendLayout(); SuspendLayout();
@ -44,7 +49,7 @@
groupBoxIn.Controls.Add(panelIn); groupBoxIn.Controls.Add(panelIn);
groupBoxIn.Location = new Point(12, 83); groupBoxIn.Location = new Point(12, 83);
groupBoxIn.Name = "groupBoxIn"; groupBoxIn.Name = "groupBoxIn";
groupBoxIn.Size = new Size(341, 355); groupBoxIn.Size = new Size(376, 355);
groupBoxIn.TabIndex = 3; groupBoxIn.TabIndex = 3;
groupBoxIn.TabStop = false; groupBoxIn.TabStop = false;
groupBoxIn.Text = "Inputs"; groupBoxIn.Text = "Inputs";
@ -55,15 +60,15 @@
panelIn.Dock = DockStyle.Fill; panelIn.Dock = DockStyle.Fill;
panelIn.Location = new Point(3, 19); panelIn.Location = new Point(3, 19);
panelIn.Name = "panelIn"; panelIn.Name = "panelIn";
panelIn.Size = new Size(335, 333); panelIn.Size = new Size(370, 333);
panelIn.TabIndex = 0; panelIn.TabIndex = 0;
// //
// groupBoxOut // groupBoxOut
// //
groupBoxOut.Controls.Add(panelOut); groupBoxOut.Controls.Add(panelOut);
groupBoxOut.Location = new Point(359, 83); groupBoxOut.Location = new Point(391, 80);
groupBoxOut.Name = "groupBoxOut"; groupBoxOut.Name = "groupBoxOut";
groupBoxOut.Size = new Size(429, 355); groupBoxOut.Size = new Size(484, 355);
groupBoxOut.TabIndex = 0; groupBoxOut.TabIndex = 0;
groupBoxOut.TabStop = false; groupBoxOut.TabStop = false;
groupBoxOut.Text = "Outputs"; groupBoxOut.Text = "Outputs";
@ -74,25 +79,26 @@
panelOut.Dock = DockStyle.Fill; panelOut.Dock = DockStyle.Fill;
panelOut.Location = new Point(3, 19); panelOut.Location = new Point(3, 19);
panelOut.Name = "panelOut"; panelOut.Name = "panelOut";
panelOut.Size = new Size(423, 333); panelOut.Size = new Size(478, 333);
panelOut.TabIndex = 0; panelOut.TabIndex = 0;
// //
// buttonSign // buttonSign
// //
buttonSign.FlatStyle = FlatStyle.Flat; buttonSign.FlatStyle = FlatStyle.Flat;
buttonSign.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point); 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.Name = "buttonSign";
buttonSign.Size = new Size(83, 36); buttonSign.Size = new Size(83, 36);
buttonSign.TabIndex = 2; buttonSign.TabIndex = 2;
buttonSign.Text = "Sign"; buttonSign.Text = "Sign";
buttonSign.UseVisualStyleBackColor = true; buttonSign.UseVisualStyleBackColor = true;
buttonSign.Click += buttonSign_Click;
// //
// Cancelbutton2 // Cancelbutton2
// //
Cancelbutton2.FlatStyle = FlatStyle.Flat; Cancelbutton2.FlatStyle = FlatStyle.Flat;
Cancelbutton2.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point); 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.Name = "Cancelbutton2";
Cancelbutton2.Size = new Size(83, 36); Cancelbutton2.Size = new Size(83, 36);
Cancelbutton2.TabIndex = 2; Cancelbutton2.TabIndex = 2;
@ -100,11 +106,60 @@
Cancelbutton2.UseVisualStyleBackColor = true; Cancelbutton2.UseVisualStyleBackColor = true;
Cancelbutton2.Click += Cancelbutton2_Click; 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 // ImportTXForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font; 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(groupBoxOut);
Controls.Add(groupBoxIn); Controls.Add(groupBoxIn);
Controls.Add(Cancelbutton2); Controls.Add(Cancelbutton2);
@ -113,11 +168,12 @@
Icon = (Icon)resources.GetObject("$this.Icon"); Icon = (Icon)resources.GetObject("$this.Icon");
MaximizeBox = false; MaximizeBox = false;
Name = "ImportTXForm"; Name = "ImportTXForm";
Text = "ImportTXForm"; Text = "Import TX";
Load += ImportTXForm_Load; Load += ImportTXForm_Load;
groupBoxIn.ResumeLayout(false); groupBoxIn.ResumeLayout(false);
groupBoxOut.ResumeLayout(false); groupBoxOut.ResumeLayout(false);
ResumeLayout(false); ResumeLayout(false);
PerformLayout();
} }
#endregion #endregion
@ -127,5 +183,10 @@
private Button Cancelbutton2; private Button Cancelbutton2;
private Panel panelIn; private Panel panelIn;
private Panel panelOut; private Panel panelOut;
private Label label1;
private Label labelSigsTotal;
private Label labelSigsReq;
private Label labelSigsSigned;
private Label labelSigInfo;
} }
} }

View File

@ -6,6 +6,9 @@ namespace FireWallet
{ {
MainForm mainForm; MainForm mainForm;
JObject tx; JObject tx;
int totalSigs;
int reqSigs;
int sigs;
public ImportTXForm(MainForm mainForm) public ImportTXForm(MainForm mainForm)
{ {
InitializeComponent(); InitializeComponent();
@ -14,6 +17,11 @@ namespace FireWallet
private void ImportTXForm_Load(object sender, EventArgs e) private void ImportTXForm_Load(object sender, EventArgs e)
{ {
// Default variables
totalSigs = 3;
reqSigs = 2;
sigs = 0;
// Theme // Theme
this.BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]); this.BackColor = ColorTranslator.FromHtml(mainForm.Theme["background"]);
this.ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]); this.ForeColor = ColorTranslator.FromHtml(mainForm.Theme["foreground"]);
@ -74,6 +82,58 @@ namespace FireWallet
JArray inputs = (JArray)json["result"]["vin"]; JArray inputs = (JArray)json["result"]["vin"];
JArray outputs = (JArray)json["result"]["vout"]; 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++) for (int i = 0; i < inputs.Count; i++)
{ {
JObject input = (JObject)inputs[i]; JObject input = (JObject)inputs[i];
@ -84,11 +144,6 @@ namespace FireWallet
PanelInput.Location = new Point(5, panelIn.Controls.Count * 50); PanelInput.Location = new Point(5, panelIn.Controls.Count * 50);
PanelInput.BorderStyle = BorderStyle.FixedSingle; 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")) if (metaInput.ContainsKey("sighashType"))
{ {
@ -99,19 +154,40 @@ namespace FireWallet
PanelInput.Controls.Add(sighashType); PanelInput.Controls.Add(sighashType);
} }
//Label address = new Label(); string txid = input["txid"].ToString();
//string addressString = input["address"].ToString().Substring(0, 5) + "..." + input["address"].ToString().Substring(input["address"].ToString().Length - 5, 5); int vout = int.Parse(input["vout"].ToString());
//address.Text = "Address: " + addressString; string txInfo = await mainForm.APIGet("tx/" + txid, false);
//address.Location = new Point(5, 5); if (txInfo == "Error" || txInfo == "")
//address.AutoSize = true; {
//PanelInput.Controls.Add(address); 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() != "") //if (input["path"].ToString() != "")
//{ //{
@ -129,7 +205,7 @@ namespace FireWallet
{ {
JObject output = (JObject)outputs[i]; JObject output = (JObject)outputs[i];
JObject metaOutput = (JObject)metaOutputs[i]; JObject metaOutput = (JObject)metaOutputs[i];
Panel PanelOutput = new Panel(); Panel PanelOutput = new Panel();
PanelOutput.Size = new Size(panelOut.Width - SystemInformation.VerticalScrollBarWidth - 10, 50); PanelOutput.Size = new Size(panelOut.Width - SystemInformation.VerticalScrollBarWidth - 10, 50);
PanelOutput.Location = new Point(5, panelOut.Controls.Count * 50); PanelOutput.Location = new Point(5, panelOut.Controls.Count * 50);
@ -167,14 +243,14 @@ namespace FireWallet
} }
bool own = false; 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 (addressResp != "Error") own = true;
if (own) if (own)
{ {
Label ownAddress = new Label(); Label ownAddress = new Label();
ownAddress.Text = "Own Address"; ownAddress.Text = "Own Address";
ownAddress.Location = new Point(PanelOutput.Width - 100, 5); ownAddress.Location = new Point(PanelOutput.Width - 150, 5);
ownAddress.AutoSize = true; ownAddress.AutoSize = true;
PanelOutput.Controls.Add(ownAddress); PanelOutput.Controls.Add(ownAddress);
} }
@ -182,11 +258,18 @@ namespace FireWallet
Label amount = new Label(); Label amount = new Label();
Decimal value = Decimal.Parse(output["value"].ToString()); Decimal value = Decimal.Parse(output["value"].ToString());
amount.Text = "Amount: " + 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; amount.AutoSize = true;
PanelOutput.Controls.Add(amount); PanelOutput.Controls.Add(amount);
panelOut.Controls.Add(PanelOutput); 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);
}
} }
} }