The Bitcoin protocol has built-in support for multisig addresses. A multisig address needs n out of i signatures before the coins can be withdrawn. A good example is an escrow-like service that allows safer payments by holding the buyer's coins in escrow until the terms of the sale are met.
You might want to run the Bitcoin Core client in testnet mode to play with fake coins.
The example code assumes you have the Ruby JSON-RPC wrapper to make things a little easier.
We create a BitcoinRPC instance which we'll reuse in our examples.
We'll create an address that needs 2 signatures out of 3 to withdraw the coins, but you can choose whatever combination you desire. Say we have the following 3 addresses:
Let's get started by creating a new multisig address. The first parameter defines the number of signatures needed to withdraw the coins (2 in our example):
This returns a new multisig address:
We now need to fiddle with some transactions. Addresses are an abstraction in the Bitcoin protocol, the basic units are transactions. Take a few minutes to learn why transactions are so important if you are not up to speed yet and want the following to make sense.
First, find an unspent transaction:
It lists all the unspent transactions in your Bitcoin Core client:
I took the first one in the list, but you probably want to mix and match transactions from this list to get to the bitcoin amount you need.
Create a new raw transaction for the multisig address. The
vout is the index of the input or output as a transaction can have multiple inputs and outputs:
This returns a long transaction hash:
DONE You now have a transaction of 0.006 BTC linked to the multisig address. You'll need 2 of the 3 signatures to spend these coins.
You can optionally announce the transaction to your local Bitcoin node (the Bitcoin Core client) and the network. Send the raw transaction from the previous step:
Have a look at the Bitcoin Core transactions tab. There should be a new pending transaction waiting for confirmation.
This post is open source. Did you spot a mistake? Ideas for improvements? Contribute to this post via Github. Thank you!