Skip to content

Instantly share code, notes, and snippets.

@pierrenoizat
Last active November 16, 2020 08:47
Show Gist options
  • Save pierrenoizat/a418968f2af4eaacfbff71e7a99c47fd to your computer and use it in GitHub Desktop.
Save pierrenoizat/a418968f2af4eaacfbff71e7a99c47fd to your computer and use it in GitHub Desktop.
Generate a P2SH-P2WSH address, create a tx spending from it.
require 'bitcoin'
include Bitcoin
include Bitcoin::Builder
include Bitcoin::Protocol
include Bitcoin::Util
include Bitcoin::Secp256k1
base_factor = 100000000
mnemonic = "beyond .. satoshi"
seed = BipMnemonic.to_seed(mnemonic: mnemonic)
@btc_wallet = Bip44::Wallet.from_seed(seed, "m/44'/0")
@btc_node = @btc_wallet.sub_wallet "m/0/1"
public_key_1 = Key.new(nil,@btc_node.public_key).pub_compressed
@btc_node = @btc_wallet.sub_wallet "m/0/2"
public_key_2 = Key.new(nil,@btc_node.public_key).pub_compressed
@btc_node = @btc_wallet.sub_wallet "m/0/3"
public_key_3 = Key.new(nil,@btc_node.public_key).pub_compressed
# Compute P2SH-P2WSH address:
witness_string = "2 #{public_key_1} #{public_key_2} #{public_key_3} 3 OP_CHECKMULTISIG"
witness_script = Script.from_string(witness_string).to_payload
redeem_string = "0 #{sha256(witness_script.bth)}"
redeem_script = Script.from_string(redeem_string).to_payload
p2sh_p2wsh_address = hash160_to_p2sh_address(hash160(redeem_script.bth))
# example: 356yCBhiW9tqg5iiPDhEZ8f8t3JfqkEihA
# Build Segwit transaction spending from P2SH-P2WSH address:
utxo_txid="c57007980fabfd7c44895d8fc2c28c6ead93483b7c2bfec682ce0a3eaa4008ce"
utxo_index = 0
amount = 0.00074465 * base_factor
fee = 0.0001 * base_factor
destination_address = "12qeTKzrK7wm1V8rCjYEysAdtD5D3PxfPV"
spend_tx = build_tx do |t|
t.lock_time 0
t.input do |i|
i.prev_out utxo_txid, utxo_index, redeem_script, amount
i.sequence "ffffffff".htb
end
t.output do |o|
o.value amount-fee
o.script {|s| s.recipient destination_address }
end
end
tx = Tx.new(spend_tx.to_payload) # unsigned tx
tx.in[0].script_sig = Script.new(Script.pack_pushdata(redeem_script)).to_payload
sig_hash = tx.signature_hash_for_witness_input(0, redeem_script, amount, witness_script, Tx::SIGHASH_TYPE[:all])
@btc_node = @btc_wallet.sub_wallet "m/0/2"
sig_2 = Secp256k1.sign(sig_hash, @btc_node.private_key.htb) + [Tx::SIGHASH_TYPE[:all]].pack("C")
@btc_node = @btc_wallet.sub_wallet "m/0/3"
sig_3 = Secp256k1.sign(sig_hash, @btc_node.private_key.htb) + [Tx::SIGHASH_TYPE[:all]].pack("C")
tx.in[0].script_witness.stack << '' # init stack
tx.in[0].script_witness.stack << sig_2 << sig_3 << witness_script
tx.to_payload.bth # signed transaction
# example transaction tid: 55c7c71c63b87478cd30d401e7ca5344a2e159dc8d6990df695c7e0cb2f82783
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment