How to use bitcoinj to implement multisig transactions

Bitcoin is the dawn of the exciting blockchain technology. Although using bitcoin directly to build blockchain applications is somewhat obscure, it still can build many vivid applications based on smart contracts -- https://en.bitcoin.it/wiki/Contract. Among others, multisig technology is the cornerstone to leverage bitcoin to implement those features.

The following tutorial will show how to use a popular Java bitcoin library to build transactions inherently multisig-based.

Basically, it demonstrates three steps to go through whole workflow.
  1. Prepare coins.
  2. Send coins to a multisig address.
  3. Spend coins at this multisig address.
The example's source code can be download via github repository: https://github.com/Bo-Ye/bitcoinj-multisig-example and the example is based on testnet.

In order to build applications sitting on testnet, we should leverage following websites to assist development:
  1. https://testnet.manu.backend.hamburg/faucet
  2. https://live.blockcypher.com/btc-testnet/
The former one is to get some free coins, the latter one is for checking if transactions are confirmed and accepted by blockchain.

Essentially, multisignature (multisig) refers to requiring more than one key to authorize a Bitcoin transaction. It is generally used to divide up responsibility for possession of bitcoins. For more information, please refer to https://en.bitcoin.it/wiki/Multisignature 

Prepare coins

To begin with, we must have some coins to move around after all bitcoin is all about how to circulate money. Let's prepare a wallet locally to receive some coins to play with. The code would looks like this:
 
 import org.bitcoinj.kits.WalletAppKit;  
 import org.bitcoinj.params.TestNet3Params;  
 import org.bitcoinj.wallet.Wallet;  
 import java.io.File;  
 public class CheckingWallet {  
   public static void main(String[] args) {  
     TestNet3Params params = TestNet3Params.get();  
     WalletAppKit appKit = new WalletAppKit(params, new File("."), "wallet"); //create a new wallet or load an existing wallet.  
     appKit.startAsync();  
     appKit.awaitRunning();  
     System.out.println("Network connected!");  
     Wallet wallet = appKit.wallet();  
     System.out.println("Wallet's current receive address: " + wallet.currentReceiveAddress());  
     System.out.println("Wallet contents: " + wallet);  
   }  
 }  

As the class name suggested, it has dual functions. Running first time will create a new wallet to store coins locally, afterwards, it checks all details inside that newly created wallet. By running this application first time, you'll get following alike output:

 Network connected!  
 Wallet's current receive address: mw4J3xZqoXy5heforQqwv6KyGddU3oagGE  
 Wallet contents: Wallet containing 0.00 BTC (spendable: 0.00 BTC) in:  
  0 pending transactions  
  0 unspent transactions  
  0 spent transactions  
  0 dead transactions  
 Last seen best block: 1348772 (2018-07-01T23:28:29Z): 00000000000001db3d8051dbdfceb088b7a41a904ff2c3cd4a82bd696d3fe20d  
 Keys:  
 Earliest creation time: 2018-07-01T23:43:30Z  
 Seed birthday: 1530488610 [2018-07-01T23:43:30Z]  
 Key to watch: tpubD8xnQctrUtegeLVkDMy6sEebcbq9TJjNVCbuswUv1XUsBzmMCZAcVWbTufgDs6NmF9BnnGiAZTkv6FQnoXEkKgocQyEXzYQe92bKbUj8oRR  
  addr:mw4J3xZqoXy5heforQqwv6KyGddU3oagGE hash160:aa77461c3d60ed5fe10f366943e683acd0246d8d (M/0H/0/0)  

Pay attention to the wallet's current receive address, we'll use this address to get some free coins from testnet faucet: https://testnet.manu.backend.hamburg/faucet, put the current receive address in the address input box and hit the give me some coins button. After a while, let's run CheckingWallet again:

 Network connected!  
 Wallet's current receive address: mkrr59Mrtff3JVoDcfX3bjy4LEFTVyqQQX  
 Wallet contents: Wallet containing 1.30 BTC (spendable: 1.30 BTC) in:  
  0 pending transactions  
  1 unspent transactions  
  0 spent transactions  
  0 dead transactions  
 Last seen best block: 1348795 (2018-07-02T02:21:13Z): 000000000000023c0d533a0bc81f00f49280c425382cfd5178aaab92327acaec  
 Keys:  
 Earliest creation time: 2018-07-01T23:43:30Z  
 Seed birthday: 1530488610 [2018-07-01T23:43:30Z]  
 Key to watch: tpubD8xnQctrUtegeLVkDMy6sEebcbq9TJjNVCbuswUv1XUsBzmMCZAcVWbTufgDs6NmF9BnnGiAZTkv6FQnoXEkKgocQyEXzYQe92bKbUj8oRR  
  addr:mw4J3xZqoXy5heforQqwv6KyGddU3oagGE hash160:aa77461c3d60ed5fe10f366943e683acd0246d8d (M/0H/0/0)  
  addr:mkrr59Mrtff3JVoDcfX3bjy4LEFTVyqQQX hash160:3a9bc0f9ff2048c3668caed35eb0e3f3b8498669 (M/0H/0/1)  
 >>> UNSPENT:  
 1.30 BTC total value (sends 0.00 BTC and receives 1.30 BTC)  
  confidence: Appeared in best chain at height 1348778, depth 18. Source: NETWORK  
  818721a12db6d9b2876cced77999c0aa36295e2089e1a18f1aba6f586f906f3c  
  updated: 2018-07-02T00:38:02Z  
  version 2  
  time locked until block 1348692  
    in  PUSHDATA(71)[304402203bd81b7bd9ff413752e7a79104aff2b5eb3b256db318b4e5887ac36182efd7e4022073dc50b0c254ced6a8fdafff121ffbc980c8dd060c22879fdfa56934d3d5740001] PUSHDATA(33)[02c5462ac8c6e90a929f8fe32f77a5333d3d35f6d07482847c9742582e24951a97]  
      outpoint:2aef0a373f8272333f386a019d8987f66db38a2af06b33980e1ddf764ca5d67d:1  
      sequence:fffffffe  
    out DUP HASH160 PUSHDATA(20)[aa77461c3d60ed5fe10f366943e683acd0246d8d] EQUALVERIFY CHECKSIG 1.30 BTC  
    out DUP HASH160 PUSHDATA(20)[af65b0a6a7144413c0a55090410beb6da010582a] EQUALVERIFY CHECKSIG 30.65906828 BTC  
    prps UNKNOWN  

At this moment, we've received 1.30 BTC as indicated by UNSPENT transaction: 818721a12db6d9b2876cced77999c0aa36295e2089e1a18f1aba6f586f906f3c.

As a side note: two files are also created locally -- wallet.wallet and wallet.spvchain. These files store wallet and blockchain information locally, do not delete them when executing applications!

Send coins to a multisig address

Now that we've got coins in our wallet, we need send some coins to a multisig address. Let's create another application:

 import org.bitcoinj.core.*;  
 import org.bitcoinj.kits.WalletAppKit;  
 import org.bitcoinj.params.TestNet3Params;  
 import org.bitcoinj.script.Script;  
 import org.bitcoinj.script.ScriptBuilder;  
 import org.bitcoinj.wallet.SendRequest;  
 import org.bitcoinj.wallet.Wallet;  
 import java.io.File;  
 import java.util.Arrays;  
 import java.util.List;  
 import java.util.concurrent.ExecutionException;  
 public class FundingTransaction {  
   private TestNet3Params params = TestNet3Params.get();  
   private WalletAppKit appKit;  
   private Wallet wallet;  
   private Script payingToMultisigTxoutScript;  
   public FundingTransaction() {  
     appKit = new WalletAppKit(params, new File("."), "wallet"); //Loading existing wallet  
     appKit.startAsync();  
     appKit.awaitRunning();  
     System.out.println("Network connected!");  
     wallet = appKit.wallet();  
   }  
   public static void main(String[] args) throws InterruptedException, InsufficientMoneyException, ExecutionException {  
     FundingTransaction ft = new FundingTransaction();  
     ft.createMultisigAddress();  
     ft.sendCoinsToMultisigAddress();  
   }  
   private void createMultisigAddress() {  
     List<ECKey> keys = Arrays.asList(new ECKey(), new ECKey(), new ECKey());  
     wallet.importKeys(keys);  
     //the below is redeem script  
     payingToMultisigTxoutScript = ScriptBuilder.createMultiSigOutputScript(2, keys); //2 of 3 multisig  
     System.out.println("Is sent to multisig: " + payingToMultisigTxoutScript.isSentToMultiSig());  
     System.out.println("redeemScript: " + payingToMultisigTxoutScript);  
   }  
   private void sendCoinsToMultisigAddress() throws InsufficientMoneyException, ExecutionException, InterruptedException {  
     Transaction payingToMultisigTx = new Transaction(params);  
     Coin value = Coin.valueOf(0, 2); // send 2 cents of BTC  
     payingToMultisigTx.addOutput(value, payingToMultisigTxoutScript);  
     SendRequest request = SendRequest.forTx(payingToMultisigTx);  
     wallet.completeTx(request);  
     PeerGroup peerGroup = appKit.peerGroup();  
     peerGroup.broadcastTransaction(request.tx).broadcast().get();  
     System.out.println("Paying to multisig transaction broadcasted!");  
   }  
 }  

This FundingTransaction application can run independently, there're two steps comprised -- create an multisig address and send coins to the multisig address. Our case is a 2 of 3 multisig address, which means the address is generated by three keys and in order to redeem the fund at this address any two keys should present to sign. The createMultisigAddress method tells all the details, which also generates the output's ScriptPubKey, the multisig address is implicitly contained inside ScriptPubKey. In the method sendCoinsToMultisigAddress, a transaction that moves some fund out of the coins received in the previous step to the newly generated multisig address is constructed and broadcasted. After running this application and wait for a while to let this transaction mined and confirmed, we can run CheckingWallet again:
(you can also go to testnet explorer website listed above to check progress)

 Network connected!  
 Wallet's current receive address: mkrr59Mrtff3JVoDcfX3bjy4LEFTVyqQQX  
 Wallet contents: Wallet containing 1.279693 BTC (spendable: 1.279693 BTC) in:  
  0 pending transactions  
  1 unspent transactions  
  1 spent transactions  
  0 dead transactions  
 Last seen best block: 1349027 (2018-07-02T21:21:57Z): 00000000000002489c61f19f41da84475daed022ebdf0bdb2951dc90d24ac604  
 Keys:  
 Earliest creation time: 2018-07-01T23:43:30Z  
  addr:mnTLZeWSAF2fwNyALhynuDKqsaN6HiAQfN hash160:4c19ce4515ec6734cedac8998ae8a2ceae39e9c4 creationTimeSeconds:1530503906  
  addr:n2uYLzr4eYaVpuVDvwF3bZhH8ckAe8z4Bo hash160:eaa0377dc04bda2db95b02c2dec1d01947412925 creationTimeSeconds:1530503906  
  addr:mtmpz9Q95MAvHy5R7Eb62AHbFMn9LReAaT hash160:9169c60868c568822007b080e4b2e088be6b5552 creationTimeSeconds:1530503906  
 Seed birthday: 1530488610 [2018-07-01T23:43:30Z]  
 Key to watch: tpubD8xnQctrUtegeLVkDMy6sEebcbq9TJjNVCbuswUv1XUsBzmMCZAcVWbTufgDs6NmF9BnnGiAZTkv6FQnoXEkKgocQyEXzYQe92bKbUj8oRR  
  addr:mw4J3xZqoXy5heforQqwv6KyGddU3oagGE hash160:aa77461c3d60ed5fe10f366943e683acd0246d8d (M/0H/0/0)  
  addr:mkrr59Mrtff3JVoDcfX3bjy4LEFTVyqQQX hash160:3a9bc0f9ff2048c3668caed35eb0e3f3b8498669 (M/0H/0/1)  
  addr:mqQuPkRfbsKwXXatqzjBrbvFVEpmDCLnis hash160:6c8c56fad7a3c899f425c5d0ab67b217c3e74175 (M/0H/1/0)  
  addr:n4fTrg9H3bSLcvYPAHygarnTPf8RvaBCCP hash160:fde6e5f0cbfbf8d99be308e24b488e1aa6cb0e54 (M/0H/1/1)  
 >>> UNSPENT:  
 -0.020307 BTC total value (sends 1.30 BTC and receives 1.279693 BTC)  
  confidence: Appeared in best chain at height 1348809, depth 219. Source: NETWORK  
  984d090af0afb0e371f535ba03ba6daac42ac37408b4ee7e2300403d133a1eb7  
  updated: 2018-07-02T03:58:32Z  
    in  PUSHDATA(72)[3045022100911bf3219462de5279a71221ed4042bd50e203aeb7fae09c4617ee2fdf8417f0022061d2a41b917e9a01a24da2f6edacdada8ce6491bb5d56b05350848ce10af597801] PUSHDATA(33)[02bd51003c6a6fa7c236c4704b2a6bc3c4256ba8512ae35b3d09653a2e971ec59c] 1.30 BTC  
      outpoint:818721a12db6d9b2876cced77999c0aa36295e2089e1a18f1aba6f586f906f3c:0 hash160:aa77461c3d60ed5fe10f366943e683acd0246d8d  
    out 2 PUSHDATA(33)[0233896a708d3ac3f4f871abe26b3b38f32bcb4402b3fe12046278376fbc770625] PUSHDATA(33)[037f9ebcc6412702be3c0dcca071c612a8414f6f3cbea12a81c76edf2f17f6f231] PUSHDATA(33)[028516c2b2407a985ede41676c3e5ad328b9e99cb928d7042cc79014fe68632eaf] 3 CHECKMULTISIG 0.02 BTC  
    out DUP HASH160 PUSHDATA(20)[6c8c56fad7a3c899f425c5d0ab67b217c3e74175] EQUALVERIFY CHECKSIG 1.279693 BTC  
    fee 0.00100326 BTC/kB, 0.000307 BTC for 306 bytes  
    prps USER_PAYMENT  
 >>> SPENT:  
 1.30 BTC total value (sends 0.00 BTC and receives 1.30 BTC)  
  confidence: Appeared in best chain at height 1348778, depth 250. Source: NETWORK  
  818721a12db6d9b2876cced77999c0aa36295e2089e1a18f1aba6f586f906f3c  
  updated: 2018-07-02T00:38:02Z  
  version 2  
  time locked until block 1348692  
    in  PUSHDATA(71)[304402203bd81b7bd9ff413752e7a79104aff2b5eb3b256db318b4e5887ac36182efd7e4022073dc50b0c254ced6a8fdafff121ffbc980c8dd060c22879fdfa56934d3d5740001] PUSHDATA(33)[02c5462ac8c6e90a929f8fe32f77a5333d3d35f6d07482847c9742582e24951a97]  
      outpoint:2aef0a373f8272333f386a019d8987f66db38a2af06b33980e1ddf764ca5d67d:1  
      sequence:fffffffe  
    out DUP HASH160 PUSHDATA(20)[aa77461c3d60ed5fe10f366943e683acd0246d8d] EQUALVERIFY CHECKSIG 1.30 BTC Spent by 984d090af0afb0e371f535ba03ba6daac42ac37408b4ee7e2300403d133a1eb7  
    out DUP HASH160 PUSHDATA(20)[af65b0a6a7144413c0a55090410beb6da010582a] EQUALVERIFY CHECKSIG 30.65906828 BTC  
    prps UNKNOWN  

We can find a new UNSPENT transaction generated and confirmed, the outpoint of this transaction tells us that previous received coins are origin of transaction input and one of output is sending 0.02 BTC to the multisig address.

All right, we've done the step moving some coins from an original address to a multisig address!

Spend coins at this multisig address

In the last step, we'll create an application to redeem the coins stored in the multisig address used in the previous step. In order to redeem the coins at a multisig address, we must request multiple key holders to sign the redeeming transaction. The application would look like this:

 import org.bitcoinj.core.*;  
 import org.bitcoinj.crypto.TransactionSignature;  
 import org.bitcoinj.kits.WalletAppKit;  
 import org.bitcoinj.params.TestNet3Params;  
 import org.bitcoinj.script.Script;  
 import org.bitcoinj.script.ScriptBuilder;  
 import org.bitcoinj.wallet.Wallet;  
 import java.io.File;  
 import java.util.concurrent.ExecutionException;  
 import static com.google.common.base.Preconditions.checkState;  
 public class RedeemingTransaction {  
   private TestNet3Params params = TestNet3Params.get();  
   private WalletAppKit appKit;  
   private Wallet wallet;  
   private TransactionOutput multisigOutput;  
   private Transaction redeemingMultisigTx1;  
   private Transaction redeemingMultisigTx2;  
   private TransactionInput redeemMultisigTxInput;  
   private ECKey.ECDSASignature partyASignature;  
   private ECKey.ECDSASignature partyBSignature;  
   public RedeemingTransaction() {  
     appKit = new WalletAppKit(params, new File("."), "wallet");  
     appKit.startAsync();  
     appKit.awaitRunning();  
     System.out.println("Network connected!");  
     wallet = appKit.wallet();  
   }  
   public static void main(String[] args) throws ExecutionException, InterruptedException {  
     RedeemingTransaction rt = new RedeemingTransaction();  
     rt.createRawTransactionForMultisigRedeemingByA();  
     rt.signRawTransactionForMultisigRedeemingByA();  
     rt.createRawTransactionForMultisigRedeemingByB();  
     rt.signRawTransactionForMultisigRedeemingByB();  
     rt.createAndBroadcastMultisigRedeemingTx();  
   }  
   private void createRawTransactionForMultisigRedeemingByA() {  
     redeemingMultisigTx1 = new Transaction(params);  
     multisigOutput = wallet.getUnspents().get(0).getParentTransaction().getOutputs().stream().filter(unspent -> unspent.getScriptPubKey().isSentToMultiSig()).findFirst().get();  
     System.out.println("multisigOutput: " + multisigOutput);  
     redeemingMultisigTx1.addInput(multisigOutput);  
     Coin value = multisigOutput.getValue();  
     wallet = appKit.wallet();  
     Address finalAddress = wallet.currentReceiveAddress();  
     redeemingMultisigTx1.addOutput(value.div(2), finalAddress);  //leave some mining fee  
     System.out.println("Send to final address: " + finalAddress);  
   }  
   private void signRawTransactionForMultisigRedeemingByA() {  
     Script payingToMultisigTxoutScriptPubKey = multisigOutput.getScriptPubKey();  
     System.out.println("payingToMultisigTxoutScriptPubKey: " + payingToMultisigTxoutScriptPubKey);  
     checkState(payingToMultisigTxoutScriptPubKey.isSentToMultiSig());  
     Sha256Hash sighash = redeemingMultisigTx1.hashForSignature(0, payingToMultisigTxoutScriptPubKey, Transaction.SigHash.ALL, false);  
     partyASignature = wallet.getImportedKeys().get(0).sign(sighash);  
   }  
   private void createRawTransactionForMultisigRedeemingByB() {  
     redeemingMultisigTx2 = new Transaction(params);  
     redeemMultisigTxInput = redeemingMultisigTx2.addInput(multisigOutput);  
     Coin value = multisigOutput.getValue();  
     wallet = appKit.wallet();  
     Address finalAddress = wallet.currentReceiveAddress();  
     redeemingMultisigTx2.addOutput(value.div(2), finalAddress);  
     System.out.println("Send to final address: " + finalAddress);  
   }  
   private void signRawTransactionForMultisigRedeemingByB() {  
     Script payingToMultisigTxoutScriptPubKey = multisigOutput.getScriptPubKey();  
     Sha256Hash sighash = redeemingMultisigTx2.hashForSignature(0, payingToMultisigTxoutScriptPubKey, Transaction.SigHash.ALL, false);  
     partyBSignature = wallet.getImportedKeys().get(1).sign(sighash);  
   }  
   private void createAndBroadcastMultisigRedeemingTx() throws ExecutionException, InterruptedException {  
     TransactionSignature signatureA = new TransactionSignature(partyASignature, Transaction.SigHash.ALL, false);  
     TransactionSignature signatureB = new TransactionSignature(partyBSignature, Transaction.SigHash.ALL, false);  
     Script inputScript = ScriptBuilder.createMultiSigInputScript(signatureA, signatureB);  
     System.out.println("redeeming Tx input script: " + inputScript);  
     redeemMultisigTxInput.setScriptSig(inputScript);  
     redeemMultisigTxInput.verify(multisigOutput);  
     PeerGroup peerGroup = appKit.peerGroup();  
     peerGroup.broadcastTransaction(redeemingMultisigTx2).broadcast().get();  
     System.out.println("Multisig redeeming transaction broadcasted!");  
   }  
 }  

It consists of several key methods:
  • createRawTransactionForMultisigRedeemingByA
  • signRawTransactionForMultisigRedeemingByA
  • createRawTransactionForMultisigRedeemingByB
  • signRawTransactionForMultisigRedeemingByB
As method names indicate, we need to request key A holder and key B holder both sign the transaction. Once we attain two signatures from A and B, in the final method, it combines two signatures to form the ScriptSig of the redeeming transaction. The coins will be sending to a new address in the wallet.

Run this application, then wait for a while to let the transaction mined and confirmed. To confirm the sending is done and dusted, let's run CheckingWallet again:

 Network connected!  
 Wallet's current receive address: mkQ78nnJvZ8RKBbGAxTcmJXjw7rRgHmw7W  
 Wallet contents: Wallet containing 1.289693 BTC (spendable: 1.289693 BTC) in:  
  0 pending transactions  
  2 unspent transactions  
  1 spent transactions  
  0 dead transactions  
 Last seen best block: 1349055 (2018-07-03T01:07:07Z): 00000000000002e948be15d30d9c3242715cf274c208a2aee9df14b62987ee0a  
 Keys:  
 Earliest creation time: 2018-07-01T23:43:30Z  
  addr:mnTLZeWSAF2fwNyALhynuDKqsaN6HiAQfN hash160:4c19ce4515ec6734cedac8998ae8a2ceae39e9c4 creationTimeSeconds:1530503906  
  addr:n2uYLzr4eYaVpuVDvwF3bZhH8ckAe8z4Bo hash160:eaa0377dc04bda2db95b02c2dec1d01947412925 creationTimeSeconds:1530503906  
  addr:mtmpz9Q95MAvHy5R7Eb62AHbFMn9LReAaT hash160:9169c60868c568822007b080e4b2e088be6b5552 creationTimeSeconds:1530503906  
 Seed birthday: 1530488610 [2018-07-01T23:43:30Z]  
 Key to watch: tpubD8xnQctrUtegeLVkDMy6sEebcbq9TJjNVCbuswUv1XUsBzmMCZAcVWbTufgDs6NmF9BnnGiAZTkv6FQnoXEkKgocQyEXzYQe92bKbUj8oRR  
  addr:mw4J3xZqoXy5heforQqwv6KyGddU3oagGE hash160:aa77461c3d60ed5fe10f366943e683acd0246d8d (M/0H/0/0)  
  addr:mkrr59Mrtff3JVoDcfX3bjy4LEFTVyqQQX hash160:3a9bc0f9ff2048c3668caed35eb0e3f3b8498669 (M/0H/0/1)  
  addr:mkQ78nnJvZ8RKBbGAxTcmJXjw7rRgHmw7W hash160:358d18bff1dcf68c5f242cc6d1acfe191289cf5b (M/0H/0/2)  
  addr:mqQuPkRfbsKwXXatqzjBrbvFVEpmDCLnis hash160:6c8c56fad7a3c899f425c5d0ab67b217c3e74175 (M/0H/1/0)  
  addr:n4fTrg9H3bSLcvYPAHygarnTPf8RvaBCCP hash160:fde6e5f0cbfbf8d99be308e24b488e1aa6cb0e54 (M/0H/1/1)  
 >>> UNSPENT:  
 0.01 BTC total value (sends 0.00 BTC and receives 0.01 BTC)  
  confidence: Seen by 3 peers (most recently: 2018-07-03T00:49:10Z). Appeared in best chain at height 1349050, depth 6. Source: NETWORK  
  f81af0eda458e7109c709982a3ce1e8ea455af94b89fda373da02e6c3fb120b0  
  updated: 2018-07-03T00:49:10Z  
    in  0[] PUSHDATA(71)[304402201eb74f5e52610f817e939279ff44a03e906f08613c3d84124f3e583f238c34aa022067d065b63ed3a28c71ee481d0e108bec007900d2de677ec7b0e692d2d66c00f201] PUSHDATA(71)[304402205276cfe52278e7d5f33e3b4d93685b9e15ec8151a331710a6b58c1609e9640770220240c763147fdf16d1199f57f0605d7086b41924c27b3e23435440d8a587de02201] 0.02 BTC  
      outpoint:984d090af0afb0e371f535ba03ba6daac42ac37408b4ee7e2300403d133a1eb7:0  
    out DUP HASH160 PUSHDATA(20)[3a9bc0f9ff2048c3668caed35eb0e3f3b8498669] EQUALVERIFY CHECKSIG 0.01 BTC  
    fee 0.04347826 BTC/kB, 0.01 BTC for 230 bytes  
    prps UNKNOWN  
 -0.020307 BTC total value (sends 1.30 BTC and receives 1.279693 BTC)  
  confidence: Appeared in best chain at height 1348809, depth 247. Source: NETWORK  
  984d090af0afb0e371f535ba03ba6daac42ac37408b4ee7e2300403d133a1eb7  
  updated: 2018-07-02T03:58:32Z  
    in  PUSHDATA(72)[3045022100911bf3219462de5279a71221ed4042bd50e203aeb7fae09c4617ee2fdf8417f0022061d2a41b917e9a01a24da2f6edacdada8ce6491bb5d56b05350848ce10af597801] PUSHDATA(33)[02bd51003c6a6fa7c236c4704b2a6bc3c4256ba8512ae35b3d09653a2e971ec59c] 1.30 BTC  
      outpoint:818721a12db6d9b2876cced77999c0aa36295e2089e1a18f1aba6f586f906f3c:0 hash160:aa77461c3d60ed5fe10f366943e683acd0246d8d  
    out 2 PUSHDATA(33)[0233896a708d3ac3f4f871abe26b3b38f32bcb4402b3fe12046278376fbc770625] PUSHDATA(33)[037f9ebcc6412702be3c0dcca071c612a8414f6f3cbea12a81c76edf2f17f6f231] PUSHDATA(33)[028516c2b2407a985ede41676c3e5ad328b9e99cb928d7042cc79014fe68632eaf] 3 CHECKMULTISIG 0.02 BTC Spent by f81af0eda458e7109c709982a3ce1e8ea455af94b89fda373da02e6c3fb120b0  
    out DUP HASH160 PUSHDATA(20)[6c8c56fad7a3c899f425c5d0ab67b217c3e74175] EQUALVERIFY CHECKSIG 1.279693 BTC  
    fee 0.00100326 BTC/kB, 0.000307 BTC for 306 bytes  
    prps USER_PAYMENT  
 >>> SPENT:  
 1.30 BTC total value (sends 0.00 BTC and receives 1.30 BTC)  
  confidence: Appeared in best chain at height 1348778, depth 278. Source: NETWORK  
  818721a12db6d9b2876cced77999c0aa36295e2089e1a18f1aba6f586f906f3c  
  updated: 2018-07-02T00:38:02Z  
  version 2  
  time locked until block 1348692  
    in  PUSHDATA(71)[304402203bd81b7bd9ff413752e7a79104aff2b5eb3b256db318b4e5887ac36182efd7e4022073dc50b0c254ced6a8fdafff121ffbc980c8dd060c22879fdfa56934d3d5740001] PUSHDATA(33)[02c5462ac8c6e90a929f8fe32f77a5333d3d35f6d07482847c9742582e24951a97]  
      outpoint:2aef0a373f8272333f386a019d8987f66db38a2af06b33980e1ddf764ca5d67d:1  
      sequence:fffffffe  
    out DUP HASH160 PUSHDATA(20)[aa77461c3d60ed5fe10f366943e683acd0246d8d] EQUALVERIFY CHECKSIG 1.30 BTC Spent by 984d090af0afb0e371f535ba03ba6daac42ac37408b4ee7e2300403d133a1eb7  
    out DUP HASH160 PUSHDATA(20)[af65b0a6a7144413c0a55090410beb6da010582a] EQUALVERIFY CHECKSIG 30.65906828 BTC  
    prps UNKNOWN  

You can find, in transaction 984d090af0afb0e371f535ba03ba6daac42ac37408b4ee7e2300403d133a1eb7, our multisig output is spent by f81af0eda458e7109c709982a3ce1e8ea455af94b89fda373da02e6c3fb120b0. Checking corresponding transaction, we find this transaction is mined and confirmed. Eventually, we successfully moved 0.01 BTC from the multisig address to another address in the wallet -- mkrr59Mrtff3JVoDcfX3bjy4LEFTVyqQQX

You can also verify the progress via testnet explorer website.

Comments

  1. Hiiii....Thanks for sharing Great information....Nice post....Keep move on....
    Blockchain Training in Hyderabad

    ReplyDelete
  2. Nice Blog.
    I've gone through the details that you mentioned in the blog regarding Bitcoin and blockchain. The way you defined it is really great and is understandable to each and every person who is looking for the bitcoin and its trading concept. Thanks for sharing such a great article, I was looking to
    hire dedicated blockchain development company and found this blog.
    Thanks for sharing such a great blog.

    hire dedicated blockchain developers
    ethereum blockchain development

    ReplyDelete

Post a Comment

Popular posts from this blog

A trick for connecting spring security oauth2 and wso2 api manager

How to develop Tomcat-based WebSocket application on Heroku