P2WSH address (multisig)

The example for 1-of-1 should only serve as an example. We don't recommend using it in the real world because it is not its intention. Instead of 1-of-1 use P2PKH!

Generate address (1-of-1)

 1import hashlib
 2
 3from buidl.ecc import PrivateKey, Signature
 4from buidl.helper import decode_base58, big_endian_to_int
 5from buidl.bech32 import decode_bech32, encode_bech32_checksum
 6from buidl.script import P2PKHScriptPubKey, RedeemScript, WitnessScript, P2WPKHScriptPubKey
 7from buidl.tx import Tx, TxIn, TxOut
 8from buidl.witness import Witness
 9
10h = hashlib.sha256(b'correct horse battery staple').digest()
11private_key = PrivateKey(secret=big_endian_to_int(h), network="signet")
12
13# Create a witnessScript. witnessScript in SegWit is equivalent to redeemScript in P2SH transaction,
14# however, while the redeemScript of a P2SH transaction is included in the ScriptSig, the 
15# WitnessScript is included in the Witness field, making P2WSH inputs cheaper to spend than P2SH 
16# inputs.
17witness_script = WitnessScript([private_key.point.sec(), 0xac])
18
19address = witness_script.address("signet")
20print('Address:', str(address))
21# outputs: tb1qgatzazqjupdalx4v28pxjlys2s3yja9gr3xuca3ugcqpery6c3sqtuzpzy

Spend from address (1-of-1)

Assuming the previously generated address has received funds, we can spend them. In order to spend them, we'll need information about the transaction id (txid) and a vector of an output (vout). You can get both from an explorer or by querying your running Bitcoin node by running listunspent along with some filters:

bitcoin-cli listunspent 1 9999999 "[\"address\"]"

Note that you must have an address in the watchlist in order to get any output. To add an address to a watchlist run importaddress:

bitcoin-cli importaddress <address> "<label>" false false

 1# we are continuing the code from above
 2
 3txid = bytes.fromhex("f24d3d8c85ded6d0fbe898a09a2c9f8a8388e4edcf139e52c8714814d85f8273")
 4vout = 0
 5
 6# Specify the amount send to your P2WSH address.
 7COIN = 100000000
 8amount = int(0.001 * COIN)
 9
10# Calculate an amount for the upcoming new UTXO. Set a high fee (5%) to bypass bitcoind minfee
11# setting on regtest.
12amount_less_fee = int(amount * 0.99)
13
14# Create the txin structure, which includes the outpoint. The scriptSig defaults to being empty as
15# is necessary for spending a P2WSH output.
16txin = TxIn(txid, vout)
17
18# Specify a destination address and create the txout.
19h160 = decode_bech32("tb1qqqlcpznqkfa65wqd48mzzghpwzefgpvtvl0a7k")[2]
20txout = TxOut(amount=amount_less_fee, script_pubkey=P2WPKHScriptPubKey(h160))
21
22tx = Tx(1, [txin], [txout], 0, network="signet", segwit=True)
23
24sig1 = tx.get_sig_segwit(0, private_key, witness_script=witness_script)
25
26tx.check_sig_segwit(
27    0,
28    private_key.point,
29    Signature.parse(sig1[:-1]),
30    witness_script=witness_script,
31)
32
33txin.witness = Witness([sig1, witness_script.raw_serialize()])
34
35print(tx.serialize().hex())
36# outputs: 0100000000010173825fd8144871c8529e13cfede488838a9f2c9aa098e8fbd0d6de858c3d4df20000000000ffffffff01b882010000000000160014003f808a60b27baa380da9f62122e170b294058b0247304402201b812e3a58b18bf83ee65db660af469708583073beaecbd4d7147757068e5ece022034a0b51dc40cdbcba1362f544a467e3dc605395f5e0029d5d2e342aea1ddfac20123210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ac00000000

Now that we have our signed and encoded transaction, we can broadcast it using sendrawtransaction:

bitcoin-cli sendrawtransaction <transaction>

If the transaction is broadcasted successfully a transaction id will be returned. In this case it was 19e8dc2d719e14bc652bda4809007a72c17bdee6e174d4c02f570c48cad691cd.

Generate address (2-of-2)

In this example we show how to create a 2-of-2 multisig address. This means that two signatures are required in order to unlock funds.

 1import hashlib
 2
 3from buidl.ecc import PrivateKey, Signature
 4from buidl.helper import decode_base58, big_endian_to_int
 5from buidl.bech32 import decode_bech32, encode_bech32_checksum
 6from buidl.script import P2PKHScriptPubKey, RedeemScript, WitnessScript, P2WPKHScriptPubKey
 7from buidl.tx import Tx, TxIn, TxOut
 8from buidl.witness import Witness
 9
10# first key
11h = hashlib.sha256(b'correct horse battery staple first').digest()
12private_key1 = PrivateKey(secret=big_endian_to_int(h), network="signet")
13
14# second key
15h = hashlib.sha256(b'correct horse battery staple second').digest()
16private_key2 = PrivateKey(secret=big_endian_to_int(h), network="signet")
17
18# Create a witnessScript. witnessScript in SegWit is equivalent to redeemScript in P2SH transaction,
19# however, while the redeemScript of a P2SH transaction is included in the ScriptSig, the 
20# WitnessScript is included in the Witness field, making P2WSH inputs cheaper to spend than P2SH 
21# inputs.
22witness_script = WitnessScript(
23    [0x52, private_key1.point.sec(), private_key2.point.sec(), 0x52, 0xAE]
24)
25
26address = witness_script.address("signet")
27print('Address:', str(address))
28# outputs: tb1qljlyqaexx4mmhpl66e6nqdtagjaht87pghuq6p0f98a765c9uj9susmlvt

Spend from address (2-of-2)

Assuming the previously generated address has received funds, we can spend them. In order to spend them, we'll need information about the transaction id (txid) and a vector of an output (vout). You can get both from an explorer or by querying your running Bitcoin node by running listunspent along with some filters:

bitcoin-cli listunspent 1 9999999 "[\"address\"]"

Note that you must have an address in the watchlist in order to get any output. To add an address to a watchlist run importaddress:

bitcoin-cli importaddress <address> "<label>" false false

 1# we are continuing the code from above
 2
 3txid = bytes.fromhex("e810379ffa5ca20a30f2210d93517aef28d3f20e20b920190161d4f6491a0903")
 4vout = 0
 5
 6# Specify the amount send to your P2WSH address.
 7COIN = 100000000
 8amount = int(0.001 * COIN)
 9
10# Calculate an amount for the upcoming new UTXO. Set a high fee (5%) to bypass bitcoind minfee
11# setting on regtest.
12amount_less_fee = int(amount * 0.99)
13
14# Create the txin structure, which includes the outpoint. The scriptSig defaults to being empty as
15# is necessary for spending a P2WSH output.
16txin = TxIn(txid, vout)
17
18# Specify a destination address and create the txout.
19h160 = decode_bech32("tb1qwp3c26rlgzlq4axergvt04300shexn4f56q5f7")[2]
20txout = TxOut(amount=amount_less_fee, script_pubkey=P2WPKHScriptPubKey(h160))
21
22tx = Tx(1, [txin], [txout], 0, network="signet", segwit=True)
23
24sig1 = tx.get_sig_segwit(0, private_key1, witness_script=witness_script)
25sig2 = tx.get_sig_segwit(0, private_key2, witness_script=witness_script)
26
27tx.check_sig_segwit(
28    0,
29    private_key1.point,
30    Signature.parse(sig1[:-1]),
31    witness_script=witness_script,
32)
33
34tx.check_sig_segwit(
35    0,
36    private_key2.point,
37    Signature.parse(sig2[:-1]),
38    witness_script=witness_script,
39)
40
41txin.finalize_p2wsh_multisig([sig1, sig2], witness_script)
42
43print(tx.serialize().hex())
44# outputs: 0100000000010103091a49f6d461011920b9200ef2d328ef7a51930d21f2300aa25cfa9f3710e80000000000ffffffff01b882010000000000160014706385687f40be0af4d91a18b7d62f7c2f934ea90400483045022100b24100d90fdd15d3e694789106f780c4c13f4929ec5cc82445418bedac9dfc93022038f5cc4ade88b41f1398d5f1e31a9d4f9d861f67aa24dff30a6d20e509b591c801483045022100fa9f78c7769010a57aa96939b32fad0d216a1dcf3a1f44a09f0e7b29f56b773402207a795dad938599c920d864001b454ae2f44358f5ac098e913049ea7fd9925cb001475221038d19497c3922b807c91b829d6873ae5bfa2ae500f3237100265a302fdce87b052103d3a9dff5a0bb0267f19a9ee1c374901c39045fbe041c1c168d4da4ce0112595552ae00000000

Now that we have our signed and encoded transaction, we can broadcast it using sendrawtransaction:

bitcoin-cli sendrawtransaction <transaction>

If the transaction is broadcasted successfully a transaction id will be returned. In this case it was 6064651b405e0e1d6b5cdc0056c3deda11af3593ca64d43b1cd4abff45b7376b.

Generate address (1-of-3)

In this example we show how to create a 1-of-3 multisig address. This means that one out of three signatures can unlock and spend bitcoins.

 1import hashlib
 2
 3from buidl.ecc import PrivateKey, Signature
 4from buidl.helper import decode_base58, big_endian_to_int
 5from buidl.bech32 import decode_bech32, encode_bech32_checksum
 6from buidl.script import P2PKHScriptPubKey, RedeemScript, WitnessScript, P2WPKHScriptPubKey
 7from buidl.tx import Tx, TxIn, TxOut
 8from buidl.witness import Witness
 9
10# first key
11h = hashlib.sha256(b'correct horse battery staple first').digest()
12private_key1 = PrivateKey(secret=big_endian_to_int(h), network="signet")
13
14# second key
15h = hashlib.sha256(b'correct horse battery staple second').digest()
16private_key2 = PrivateKey(secret=big_endian_to_int(h), network="signet")
17
18# third key
19h = hashlib.sha256(b'correct horse battery staple third').digest()
20private_key3 = PrivateKey(secret=big_endian_to_int(h), network="signet")
21
22# Create a witnessScript. witnessScript in SegWit is equivalent to redeemScript in P2SH transaction,
23# however, while the redeemScript of a P2SH transaction is included in the ScriptSig, the 
24# WitnessScript is included in the Witness field, making P2WSH inputs cheaper to spend than P2SH 
25# inputs.
26witness_script = WitnessScript(
27    [0x51, private_key1.point.sec(), private_key2.point.sec(), private_key3.point.sec(), 0x53, 0xAE]
28)
29
30address = witness_script.address("signet")
31print('Address:', str(address))
32# outputs: tb1qywycrgq9mvh7lm607hfz2nr99juda6v7ks5gvdtg6qz4l6f80nsqu9wr4h

Spend from address (1-of-3)

Assuming the previously generated address has received funds, we can spend them. In order to spend them, we'll need information about the transaction id (txid) and a vector of an output (vout). You can get both from an explorer or by querying your running Bitcoin node by running listunspent along with some filters:

bitcoin-cli listunspent 1 9999999 "[\"address\"]"

Note that you must have an address in the watchlist in order to get any output. To add an address to a watchlist run importaddress:

bitcoin-cli importaddress <address> "<label>" false false

 1# we are continuing the code from above
 2
 3txid = bytes.fromhex("430f7f5ef675a910786f335cabff19d6661910ea365097c6fa1d72e97803ea81")
 4vout = 0
 5
 6# Specify the amount send to your P2WSH address.
 7COIN = 100000000
 8amount = int(0.001 * COIN)
 9
10# Calculate an amount for the upcoming new UTXO. Set a high fee (5%) to bypass bitcoind minfee
11# setting on regtest.
12amount_less_fee = int(amount * 0.99)
13
14# Create the txin structure, which includes the outpoint. The scriptSig defaults to being empty as
15# is necessary for spending a P2WSH output.
16txin = TxIn(txid, vout)
17
18# Specify a destination address and create the txout.
19h160 = decode_bech32("tb1qwp3c26rlgzlq4axergvt04300shexn4f56q5f7")[2]
20txout = TxOut(amount=amount_less_fee, script_pubkey=P2WPKHScriptPubKey(h160))
21
22tx = Tx(1, [txin], [txout], 0, network="signet", segwit=True)
23
24sig2 = tx.get_sig_segwit(0, private_key2, witness_script=witness_script)
25
26tx.check_sig_segwit(
27    0,
28    private_key2.point,
29    Signature.parse(sig2[:-1]),
30    witness_script=witness_script,
31)
32
33txin.finalize_p2wsh_multisig([sig2], witness_script)
34
35print(tx.serialize().hex())
36# outputs: 0100000000010181ea0378e9721dfac6975036ea101966d619ffab5c336f7810a975f65e7f0f430000000000ffffffff01b882010000000000160014706385687f40be0af4d91a18b7d62f7c2f934ea90300473044022036d2596a339e9205d8916d457aeba40332abce8a8435fdb428b1d1b93a8b1af202202fddec53a106e0f8d2d788f83206a3e2e9b9abacf74f0cc16c4458be9c6b89f501695121038d19497c3922b807c91b829d6873ae5bfa2ae500f3237100265a302fdce87b052103d3a9dff5a0bb0267f19a9ee1c374901c39045fbe041c1c168d4da4ce01125955210228769768e3083e084dd5c03b6077d51b7e7a22bd66fc99ff481dcf9b6b80d03053ae00000000

Now that we have our signed and encoded transaction, we can broadcast it using sendrawtransaction:

bitcoin-cli sendrawtransaction <transaction>

If the transaction is broadcasted successfully a transaction id will be returned. In this case it was 3fbd9fe43c30c9af8852f6eaf3e0f1158079195e9b9eea51576445f6c8098fdb.

Generate address (2-of-3)

In this example we show how to create a 2-of-3 multisig address. This means that two out of three signatures can unlock and spend bitcoins.

 1import hashlib
 2
 3from buidl.ecc import PrivateKey, Signature
 4from buidl.helper import decode_base58, big_endian_to_int
 5from buidl.bech32 import decode_bech32, encode_bech32_checksum
 6from buidl.script import P2PKHScriptPubKey, RedeemScript, WitnessScript, P2WPKHScriptPubKey
 7from buidl.tx import Tx, TxIn, TxOut
 8from buidl.witness import Witness
 9
10# first key
11h = hashlib.sha256(b'correct horse battery staple first').digest()
12private_key1 = PrivateKey(secret=big_endian_to_int(h), network="signet")
13
14# second key
15h = hashlib.sha256(b'correct horse battery staple second').digest()
16private_key2 = PrivateKey(secret=big_endian_to_int(h), network="signet")
17
18# third key
19h = hashlib.sha256(b'correct horse battery staple third').digest()
20private_key3 = PrivateKey(secret=big_endian_to_int(h), network="signet")
21
22# Create a witnessScript. witnessScript in SegWit is equivalent to redeemScript in P2SH transaction,
23# however, while the redeemScript of a P2SH transaction is included in the ScriptSig, the 
24# WitnessScript is included in the Witness field, making P2WSH inputs cheaper to spend than P2SH 
25# inputs.
26witness_script = WitnessScript(
27    [0x52, private_key1.point.sec(), private_key2.point.sec(), private_key3.point.sec(), 0x53, 0xAE]
28)
29
30address = witness_script.address("signet")
31print('Address:', str(address))
32# outputs: tb1q3xlhms84s9vakaa3ds6pzh849mkddvfqmkp43unxyac4stkyyssseuv3rk

Spend from address (2-of-3)

Assuming the previously generated address has received funds, we can spend them. In order to spend them, we'll need information about the transaction id (txid) and a vector of an output (vout). You can get both from an explorer or by querying your running Bitcoin node by running listunspent along with some filters:

bitcoin-cli listunspent 1 9999999 "[\"address\"]"

Note that you must have an address in the watchlist in order to get any output. To add an address to a watchlist run importaddress:

bitcoin-cli importaddress <address> "<label>" false false

 1# we are continuing the code from above
 2
 3txid = bytes.fromhex("271ec7372f58eda37ab686a1ad08cd1cac0188b51bcc29d40f8bc5aa06b4db85")
 4vout = 0
 5
 6# Specify the amount send to your P2WSH address.
 7COIN = 100000000
 8amount = int(0.001 * COIN)
 9
10# Calculate an amount for the upcoming new UTXO. Set a high fee (5%) to bypass bitcoind minfee
11# setting on regtest.
12amount_less_fee = int(amount * 0.99)
13
14# Create the txin structure, which includes the outpoint. The scriptSig defaults to being empty as
15# is necessary for spending a P2WSH output.
16txin = TxIn(txid, vout)
17
18# Specify a destination address and create the txout.
19h160 = decode_bech32("tb1qwp3c26rlgzlq4axergvt04300shexn4f56q5f7")[2]
20txout = TxOut(amount=amount_less_fee, script_pubkey=P2WPKHScriptPubKey(h160))
21
22tx = Tx(1, [txin], [txout], 0, network="signet", segwit=True)
23
24sig2 = tx.get_sig_segwit(0, private_key2, witness_script=witness_script)
25sig3 = tx.get_sig_segwit(0, private_key3, witness_script=witness_script)
26
27tx.check_sig_segwit(
28    0,
29    private_key2.point,
30    Signature.parse(sig2[:-1]),
31    witness_script=witness_script,
32)
33tx.check_sig_segwit(
34    0,
35    private_key3.point,
36    Signature.parse(sig3[:-1]),
37    witness_script=witness_script,
38)
39
40
41txin.finalize_p2wsh_multisig([sig2, sig3], witness_script)
42
43print(tx.serialize().hex())
44# outputs: 0100000000010185dbb406aac58b0fd429cc1bb58801ac1ccd08ada186b67aa3ed582f37c71e270000000000ffffffff01b882010000000000160014706385687f40be0af4d91a18b7d62f7c2f934ea904004730440220378efe62e2d47d3a0301a71a4f50263f62d8b6ffd42638a4f1f12ff54b1a653b02204998939a432ddd60a60b5d5051d9abbd282520ad1d9a56852cb83bbb32013abf014830450221008ea8d8ed0bdb1c69390af52786bfe3a5702cf48bf804484b5782eb50f39c23d1022020eaee9a54d8e7bfa2fee5a4ef4a86bad6049c8a8de42ea5ae35c00b98623b3e01695221038d19497c3922b807c91b829d6873ae5bfa2ae500f3237100265a302fdce87b052103d3a9dff5a0bb0267f19a9ee1c374901c39045fbe041c1c168d4da4ce01125955210228769768e3083e084dd5c03b6077d51b7e7a22bd66fc99ff481dcf9b6b80d03053ae00000000

Now that we have our signed and encoded transaction, we can broadcast it using sendrawtransaction:

bitcoin-cli sendrawtransaction <transaction>

If the transaction is broadcasted successfully a transaction id will be returned. In this case it was 056b104250da42463ef8b203ae5967a4193057a449c575f1d5d74f9cbb238dd2.