MetacoSA / NBitcoin

Comprehensive Bitcoin library for the .NET framework.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

multisig partially signed transaction example

VahidShir opened this issue · comments

Could you please show me a sample code of how to sign and create partially signed bitcoin transaction given following scenario?
(I followed a tutorial here but it was too old and at that time psbt protocol wasn't introduced).

In a 2-3 multisig I'm a cosigner and would like to sign a transaction by sending an amount of bitcoin say(0.1 BTC to some address) and then deliver the partially signed psbt content (or .psbt file) to other co-signers? The other co-signers have setup this multisig setup on their electrum wallet (I gave them my xpub).

//seed generated for testing
string mySeed = "amused raven leopard happy actor car emotion brisk pretty canvas bomb bench vague off duck marine wasp bar boring enact confirm cover admit ridge";
string coSigner2Xpub = "tpub.......";
string coSigner3Xpub = "tpub.......";

Mnemonic mnemonic = new Mnemonic(mySeed );
var mySeedByte = mnemonic.DeriveSeed();
string path = "m/44'/1'/0'/0";
KeyPath keyPath = new KeyPath(path);
var network = Network.TestNet;

ExtKey myExtKey = ExtKey.CreateFromSeed(mySeedByte).Derive(keyPath);
ExtPubKey myXpubKey = myExtKey.Neuter();
BitcoinExtPubKey myBitcoinExtPubKey = myXpubKey.GetWif(network);
var myXpub = myBitcoinExtPubKey.ToString(); // I already sent this xpub of mine to other cosigners

// Here is the sample code taken from the tutorial:
var network = Network.TestNet;

Key bob = new Key();
Key alice = new Key();
Key satoshi = new Key();

var scriptPubKey = PayToMultiSigTemplate
    .Instance
    .GenerateScriptPubKey(2, new[] { bob.PubKey, alice.PubKey, satoshi.PubKey });

var received = Transaction.Create(network);
received.Outputs.Add(Money.Coins(1.0m), scriptPubKey);

Coin coin = received.Outputs.AsCoins().First();

BitcoinAddress nico = new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main);

TransactionBuilder builder = Network.Main.CreateTransactionBuilder();

Transaction unsigned =
    builder
      .AddCoins(coin)
      .Send(nico, Money.Coins(1.0m))
      .BuildTransaction(sign: false);

Transaction aliceSigned =
    builder
        .AddCoins(coin)
        .AddKeys(alice)
        .SignTransaction(unsigned);

//Transaction bobSigned =
//                builder
//                    .AddCoins(coin)
//                    .AddKeys(bob)
//                    //At this line, SignTransaction(unSigned) has the identical functionality with the SignTransaction(aliceSigned).
//                    //It's because unsigned transaction has already been signed by Alice privateKey from above.
//                    .SignTransaction(aliceSigned);

//Transaction fullySigned =
//                builder
//                    .AddCoins(coin)
//                    .CombineSignatures(aliceSigned, bobSigned);


// Here I only signed as Alice since we wanna send the psbt to Bob so that he signs this psbt (and finalizing) then
// either broadcasting it himself or send the psbt back to us and we broadcast it.
var psbt = PSBT.FromTransaction(aliceSigned, network);

//This line throws the exception:
//NBitcoin.PSBTException: 'Input 0: Neither witness_utxo nor non_witness_output is set'
psbt.Finalize();