diff --git a/docs/_examples/taproot_coinbase.adoc b/docs/_examples/taproot_coinbase.adoc
new file mode 100644
index 0000000..faf3c9e
--- /dev/null
+++ b/docs/_examples/taproot_coinbase.adoc
@@ -0,0 +1,17 @@
+= Taproot Coinbase
+:page-layout: page
+:page-title: Taproot Coinbase
+:page-nav_order: 3
+:sourcedir: ../../
+
+To generate a coinbase transaction with a taproot script pubkey, use
+the `taproot` keyword argument and provide the internal key and
+optionally the leaves just as in a normal link:taproot.html[Taproot
+output].
+
+.Taproot coinbase
+[source,ruby]
+----
+include::{sourcedir}/lib/contracts/taproot/coinbase_with_taproot.rb[tags=coinbase]
+----
+<1> Use the taproot keyword with the `internal_key` and `leaves` arguments
diff --git a/lib/contracts/coinbase_with_descriptor.rb b/lib/contracts/coinbase_with_descriptor.rb
index 4227c4c..fbd3bc3 100644
--- a/lib/contracts/coinbase_with_descriptor.rb
+++ b/lib/contracts/coinbase_with_descriptor.rb
@@ -26,7 +26,7 @@
@coinbase_with_descriptor = get_coinbase_at 1
-# Make descripto coinbases spendable by spending to p2wkh
+# Make descriptor coinbase spendable by spending to p2wkh
extend_chain to: @alice, num_blocks: 100
assert_confirmations @coinbase_with_descriptor, confirmations: 100
diff --git a/lib/contracts/multiple_inputs.rb b/lib/contracts/multiple_inputs.rb
new file mode 100644
index 0000000..e6d80f3
--- /dev/null
+++ b/lib/contracts/multiple_inputs.rb
@@ -0,0 +1,55 @@
+# Copyright 2024 Kulpreet Singh
+#
+# This file is part of Bitcoin-DSL
+#
+# Bitcoin-DSL is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Bitcoin-DSL is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Bitcoin-DSL. If not, see .
+
+# frozen_string_literal: false
+
+# Generate new keys
+@alice = key :new
+@bob = key :new
+@carol = key :new
+
+# Seed alice with some coins
+extend_chain to: @alice
+
+# Seed bob with some coins and make coinbase spendable
+extend_chain num_blocks: 1, to: @alice
+extend_chain num_blocks: 101, to: @bob
+
+@alice_coinbase = spendable_coinbase_for @alice
+@bob_coinbase = spendable_coinbase_for @bob
+
+@multiple_inputs_tx = transaction inputs: [
+ { tx: @alice_coinbase, vout: 0, script_sig: 'sig:wpkh(@alice)' },
+ { tx: @bob_coinbase, vout: 0, script_sig: 'sig:wpkh(@bob)' }
+ ],
+ outputs: [
+ {
+ descriptor: 'wpkh(@carol)',
+ amount: 99.999.sats
+ }
+ ]
+
+# verify_signature for_transaction: @multiple_inputs_tx,
+# at_index: 0,
+# with_prevout: [@alice_coinbase, 0]
+
+assert_mempool_accept @multiple_inputs_tx
+broadcast @multiple_inputs_tx
+confirm transaction: @multiple_inputs_tx, to: @carol
+
+assert_output_is_spent transaction: @alice_coinbase, vout: 0
+assert_output_is_spent transaction: @bob_coinbase, vout: 0
diff --git a/lib/contracts/taproot/coinbase_with_taproot.rb b/lib/contracts/taproot/coinbase_with_taproot.rb
new file mode 100644
index 0000000..873fb2a
--- /dev/null
+++ b/lib/contracts/taproot/coinbase_with_taproot.rb
@@ -0,0 +1,49 @@
+# Copyright 2024 Kulpreet Singh
+#
+# This file is part of Bitcoin-DSL
+#
+# Bitcoin-DSL is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Bitcoin-DSL is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Bitcoin-DSL. If not, see .
+
+# frozen_string_literal: false
+
+@alice = key :new
+@bob = key :new
+@carol = key :new
+
+# tag::coinbase[]
+# Mine block with taproot coinbase
+extend_chain taproot: { internal_key: @bob, # <1>
+ leaves: ['pk(@carol)', 'pk(@alice)'] }
+# end::coinbase[]
+
+assert_height 1
+
+@coinbase_with_taproot = get_coinbase_at 1
+
+# Make coinbase spendable by spending to p2wkh
+extend_chain to: @alice, num_blocks: 100
+
+@spend_taproot_coinbase = transaction inputs: [
+ { tx: @coinbase_with_taproot,
+ vout: 0,
+ script_sig: { keypath: @bob },
+ sighash: :all }
+ ],
+ outputs: [
+ { descriptor: 'wpkh(@carol)',
+ amount: 49.998.sats }
+ ]
+
+broadcast @spend_taproot_coinbase
+confirm transaction: @spend_taproot_coinbase
diff --git a/lib/contracts/taproot/taproot_coinbase.rb b/lib/contracts/taproot/taproot_coinbase.rb
deleted file mode 100644
index 4640904..0000000
--- a/lib/contracts/taproot/taproot_coinbase.rb
+++ /dev/null
@@ -1 +0,0 @@
-# TODO
diff --git a/lib/dsl/broadcast.rb b/lib/dsl/broadcast.rb
index e5bdfac..bddd01f 100644
--- a/lib/dsl/broadcast.rb
+++ b/lib/dsl/broadcast.rb
@@ -19,7 +19,7 @@
# DSL module for broadcasting transactions
module Broadcast
- def extend_chain(to: nil, policy: nil, descriptor: nil, script: nil, num_blocks: 1)
+ def extend_chain(to: nil, policy: nil, descriptor: nil, script: nil, taproot: nil, num_blocks: 1)
_ = get_height # We need to seem to call getheight before generating to address
if descriptor
script_pubkey, = compile_descriptor(descriptor)
@@ -30,6 +30,9 @@ def extend_chain(to: nil, policy: nil, descriptor: nil, script: nil, num_blocks:
elsif script
script_pubkey, = compile_script_pubkey(script)
address = script_pubkey.to_addr
+ elsif taproot
+ script_pubkey, = compile_taproot(taproot)
+ address = script_pubkey.to_addr
else
to ||= key :new
address = to.to_p2wpkh
diff --git a/lib/dsl/query_node.rb b/lib/dsl/query_node.rb
index 60ecc5f..292ae5a 100644
--- a/lib/dsl/query_node.rb
+++ b/lib/dsl/query_node.rb
@@ -55,6 +55,8 @@ def get_coinbase_at(height)
block['tx'][0]
end
+ alias coinbase_at get_coinbase_at
+
# Return a spendable coinbase for a key
# If a key is provided, we use the p2wpkh address for the key
# Later on we will add options to query by a given address
diff --git a/spec/runner_spec.rb b/spec/runner_spec.rb
index d3f6500..207c4b3 100644
--- a/spec/runner_spec.rb
+++ b/spec/runner_spec.rb
@@ -35,6 +35,7 @@
it_behaves_like 'script evaluation', './lib/contracts/anchor_transactions.rb'
it_behaves_like 'script evaluation', './lib/contracts/fold_transactions.rb'
it_behaves_like 'script evaluation', './lib/contracts/multisig.rb'
+ it_behaves_like 'script evaluation', './lib/contracts/multiple_inputs.rb'
it_behaves_like 'script evaluation', './lib/contracts/simple.rb'
end
@@ -76,6 +77,7 @@
describe 'taproot transactions' do
it_behaves_like 'script evaluation', './lib/contracts/taproot/keypath_spend.rb'
it_behaves_like 'script evaluation', './lib/contracts/taproot/scriptpath_spend.rb'
+ it_behaves_like 'script evaluation', './lib/contracts/taproot/coinbase_with_taproot.rb'
end
describe 'silent payment' do