Last active
February 3, 2022 17:00
-
-
Save pierrenoizat/16ba9e5b7455c6fe9358840ce38e0021 to your computer and use it in GitHub Desktop.
Build a Segwit transaction spending a Segwit native P2WPKH utxo and another (standard) transaction funding a native P2WPKH Segwit address
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'bitcoin' | |
require 'money-tree' | |
require 'bip44' | |
require 'bech32' | |
include Bitcoin | |
include Bitcoin::Builder | |
include Bitcoin::Protocol | |
include Bitcoin::Util | |
include Bitcoin::Secp256k1 | |
include Bech32 | |
base_factor = 100000000 | |
mnemonic = "beyond .. satoshi" # enter your own passphrase here | |
seed = BipMnemonic.to_seed(mnemonic: mnemonic) | |
@btc_wallet = Bip44::Wallet.from_seed(seed, "m/44'/0") | |
i=2 | |
@btc_node = @btc_wallet.sub_wallet "m/0/#{i}" | |
destination_address = "12qeTKzrK7wm1V8rCjYEysAdtD5D3PxfPV" | |
public_key = Key.new(nil,@btc_node.public_key).pub_compressed | |
script_pubkey = Script.from_string("#{Script::OP_0} " + "#{hash160(public_key)}").to_payload # to spend a Segwit input | |
native_p2wpkh_address = SegwitAddr.new | |
native_p2wpkh_address.hrp = 'bc' # hrp = human-readable part | |
native_p2wpkh_address.script_pubkey = script_pubkey.bth | |
address = native_p2wpkh_address.addr # P2WPKH native Segwit address: must be funded ! | |
utxo_txid = "03e60e4671588c2dc94415ab21a95960e19ebe9316c5ee25a706ccba25535e36" | |
utxo_index = 0 | |
amount = 0.00075135 * base_factor | |
fee = 0.0001 * base_factor | |
# sent_amount = 0.0005 * base_factor | |
# change = amount - sent_amount - fee | |
sent_amount = amount - fee | |
# Segwit transaction to spend the native Segwit address: | |
tx = build_tx do |t| | |
t.lock_time 0 | |
t.input do |i| | |
i.prev_out utxo_txid, utxo_index, script_pubkey, amount | |
i.sequence "ffffffff".htb | |
end | |
t.output do |o| | |
o.value sent_amount | |
o.script {|s| s.recipient destination_address } | |
end | |
# t.output do |o| | |
# o.value change | |
# o.script { |s| s.recipient change_address } | |
# end | |
end | |
tx.to_payload.bth # unsigned tx | |
sig_hash = tx.signature_hash_for_witness_input(0, script_pubkey, amount) | |
sig = Secp256k1.sign(sig_hash, @btc_node.private_key.htb) | |
tx.in[0].script_witness.stack << sig + [Tx::SIGHASH_TYPE[:all]].pack("C") | |
tx.in[0].script_witness.stack << public_key.htb | |
puts tx.to_payload.unpack('H*')[0] # signed tx (in hex) | |
puts tx.hash | |
destination_address = "bc1q2xdndlad2njdd6vsnvqhhyu9l4dan2sm4dhrml" | |
utxo_txid = "b2e85846105077e0eadaa570ba5962872f6bf22ef43ab50c58571f8cb39a3ce1" | |
utxo_index = 1 | |
amount = 0.00073192 * base_factor | |
fee = 0.0001 * base_factor | |
sent_amount = amount - fee | |
public_key = Key.new(nil,@btc_node.public_key).pub | |
# puts Key.new(nil,@btc_node.public_key).addr # standard (legacy) uncompressed address being spent | |
script_pubkey = Script.to_hash160_script(hash160(public_key)) # to spend a standard utxo | |
# Standard transaction to fund the native Segwit address: | |
tx = build_tx do |t| | |
t.input do |i| | |
i.prev_out utxo_txid | |
i.prev_out_index utxo_index | |
end | |
t.output do |o| | |
o.value sent_amount | |
o.script {|s| s.recipient destination_address } | |
end | |
end | |
tx.to_payload.bth # unsigned tx | |
sig_hash = tx.signature_hash_for_input(0, script_pubkey) | |
sig = Secp256k1.sign(sig_hash, @btc_node.private_key.htb) | |
tx.in[0].script_sig = Script.to_signature_pubkey_script(sig, public_key.htb) | |
puts tx.to_payload.unpack('H*')[0] # signed tx (in hex) | |
puts tx.hash |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This gist is using the remarkable bech32 gem from Shigeyuki Azuchi : [email protected]:azuchi/bech32rb.git