Skip to content

Commit 53747cc

Browse files
sstonet-bast
andauthored
Use bitcoin-lib 0.46 (taproot tweak refactor) (#3225)
* Use bitcoin-lib 0.46 (taproot tweak refactor) * Update eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala Co-authored-by: Bastien Teinturier <31281497+t-bast@users.noreply.github.com>
1 parent 36822bb commit 53747cc

File tree

12 files changed

+56
-29
lines changed

12 files changed

+56
-29
lines changed

.mvn/checksums/checksums-central.sha256

Lines changed: 20 additions & 0 deletions
Large diffs are not rendered by default.

eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManager.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package fr.acinq.eclair.crypto.keymanager
1818

1919
import com.typesafe.config.ConfigFactory
2020
import fr.acinq.bitcoin.psbt.Psbt
21+
import fr.acinq.bitcoin.scalacompat.Crypto.TaprootTweak.KeyPathTweak
2122
import fr.acinq.bitcoin.scalacompat.DeterministicWallet._
2223
import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector64, Crypto, DeterministicWallet, MnemonicCode, Satoshi, Script, computeBIP84Address}
2324
import fr.acinq.eclair.TimestampSecond
@@ -225,8 +226,8 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector,
225226
} else if (pub != KotlinUtils.scala2kmp(expectedKey.xOnly)) {
226227
logger.warn(s"public key mismatch (expected=$expectedKey, actual=$pub): bitcoin core may be malicious")
227228
false
228-
} else if (txOut.publicKeyScript != KotlinUtils.scala2kmp(Script.write(Script.pay2tr(expectedKey.xOnly, None)))) {
229-
logger.warn(s"script mismatch (expected=${Script.write(Script.pay2tr(expectedKey.xOnly, None))}, actual=${txOut.publicKeyScript}): bitcoin core may be malicious")
229+
} else if (txOut.publicKeyScript != KotlinUtils.scala2kmp(Script.write(Script.pay2tr(expectedKey.xOnly, KeyPathTweak)))) {
230+
logger.warn(s"script mismatch (expected=${Script.write(Script.pay2tr(expectedKey.xOnly, KeyPathTweak))}, actual=${txOut.publicKeyScript}): bitcoin core may be malicious")
230231
false
231232
} else {
232233
true
@@ -306,7 +307,7 @@ class LocalOnChainKeyManager(override val walletName: String, seed: ByteVector,
306307
val (pub, keypath) = input.getTaprootDerivationPaths.asScala.toSeq.head
307308
val priv = fr.acinq.bitcoin.DeterministicWallet.derivePrivateKey(master.priv, keypath.keyPath).getPrivateKey
308309
require(priv.publicKey().xOnly() == pub, s"derived public key doesn't match (expected=$pub actual=${priv.publicKey().xOnly()}): bitcoin core may be malicious")
309-
val expectedScript = Script.write(Script.pay2tr(pub, None))
310+
val expectedScript = Script.write(Script.pay2tr(pub, KeyPathTweak))
310311
require(kmp2scala(input.getWitnessUtxo.publicKeyScript) == expectedScript, s"script mismatch (expected=$expectedScript, actual=${input.getWitnessUtxo.publicKeyScript}): bitcoin core may be malicious")
311312

312313
// No need to update the input, we can directly sign and finalize.

eclair-core/src/main/scala/fr/acinq/eclair/transactions/Scripts.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ object Scripts {
345345
* The key used matches the key for the matching node's main output.
346346
*/
347347
def anchor(anchorKey: PublicKey): Seq[ScriptElt] = {
348-
Script.pay2tr(anchorKey.xOnly, Some(anchorScriptTree))
348+
Script.pay2tr(anchorKey.xOnly, anchorScriptTree)
349349
}
350350

351351
/**
@@ -389,7 +389,7 @@ object Scripts {
389389
* Script used for the main balance of the owner of the commitment transaction.
390390
*/
391391
def toLocal(keys: CommitmentPublicKeys, toSelfDelay: CltvExpiryDelta): Seq[ScriptElt] = {
392-
Script.pay2tr(NUMS_POINT.xOnly, Some(toLocalScriptTree(keys, toSelfDelay).scriptTree))
392+
Script.pay2tr(NUMS_POINT.xOnly, toLocalScriptTree(keys, toSelfDelay).scriptTree)
393393
}
394394

395395
/**
@@ -417,7 +417,7 @@ object Scripts {
417417
* Script used for the main balance of the remote node in our commitment transaction.
418418
*/
419419
def toRemote(keys: CommitmentPublicKeys): Seq[ScriptElt] = {
420-
Script.pay2tr(NUMS_POINT.xOnly, Some(toRemoteScriptTree(keys)))
420+
Script.pay2tr(NUMS_POINT.xOnly, toRemoteScriptTree(keys))
421421
}
422422

423423
/**
@@ -533,7 +533,7 @@ object Scripts {
533533
* Script used for the output of pre-signed HTLC 2nd-stage transactions.
534534
*/
535535
def htlcDelayed(keys: CommitmentPublicKeys, toSelfDelay: CltvExpiryDelta): Seq[ScriptElt] = {
536-
Script.pay2tr(keys.revocationPublicKey.xOnly, Some(htlcDelayedScriptTree(keys, toSelfDelay)))
536+
Script.pay2tr(keys.revocationPublicKey.xOnly, htlcDelayedScriptTree(keys, toSelfDelay))
537537
}
538538
}
539539
}

eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package fr.acinq.eclair.transactions
1818

1919
import fr.acinq.bitcoin.SigHash._
2020
import fr.acinq.bitcoin.SigVersion._
21-
import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey, XonlyPublicKey}
21+
import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey, TaprootTweak, XonlyPublicKey}
2222
import fr.acinq.bitcoin.scalacompat.KotlinUtils._
2323
import fr.acinq.bitcoin.scalacompat._
2424
import fr.acinq.bitcoin.ScriptFlags
@@ -204,7 +204,7 @@ object Transactions {
204204
* @param scriptTree_opt the script tree must be known if there is one, even when spending via the key path.
205205
*/
206206
case class TaprootKeyPath(internalKey: XonlyPublicKey, scriptTree_opt: Option[ScriptTree]) extends Taproot {
207-
override val pubkeyScript: ByteVector = Script.write(Script.pay2tr(internalKey, scriptTree_opt))
207+
override val pubkeyScript: ByteVector = Script.write(Script.pay2tr(internalKey, scriptTree_opt.map(TaprootTweak.ScriptPathTweak(_)).getOrElse(TaprootTweak.KeyPathTweak)))
208208
}
209209
/**
210210
* @param internalKey we need the internal key, even if we don't have the private key, to spend via a script path.
@@ -214,7 +214,7 @@ object Transactions {
214214
case class TaprootScriptPath(internalKey: XonlyPublicKey, scriptTree: ScriptTree, leafHash: ByteVector32) extends Taproot {
215215
val leaf: ScriptTree.Leaf = scriptTree.findScript(leafHash).getOrElse(throw new IllegalArgumentException("script tree must contain the provided leaf"))
216216
val redeemScript: ByteVector = leaf.getScript
217-
override val pubkeyScript: ByteVector = Script.write(Script.pay2tr(internalKey, Some(scriptTree)))
217+
override val pubkeyScript: ByteVector = Script.write(Script.pay2tr(internalKey, scriptTree))
218218
}
219219
}
220220
// @formatter:on

eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferTypes.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package fr.acinq.eclair.wire.protocol
1818

1919
import fr.acinq.bitcoin.Bech32
20-
import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey, SchnorrTweak, XonlyPublicKey}
20+
import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey, XonlyPublicKey}
2121
import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, ByteVector64, Crypto, LexicographicalOrdering}
2222
import fr.acinq.eclair.crypto.Sphinx.RouteBlinding.BlindedRoute
2323
import fr.acinq.eclair.wire.protocol.CommonCodecs.varint
@@ -500,7 +500,7 @@ object OfferTypes {
500500
def signSchnorr(tag: ByteVector, msg: ByteVector32, key: PrivateKey): ByteVector64 = {
501501
val h = hash(tag, msg)
502502
// NB: we don't add auxiliary random data to keep signatures deterministic.
503-
Crypto.signSchnorr(h, key, SchnorrTweak.NoTweak)
503+
Crypto.signSchnorr(h, key, None)
504504
}
505505

506506
def verifySchnorr(tag: ByteVector, msg: ByteVector32, signature: ByteVector64, publicKey: PublicKey): Boolean = {

eclair-core/src/test/scala/fr/acinq/eclair/blockchain/DummyOnChainWallet.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package fr.acinq.eclair.blockchain
1919
import fr.acinq.bitcoin.TxIn.SEQUENCE_FINAL
2020
import fr.acinq.bitcoin.psbt.{KeyPathWithMaster, Psbt, TaprootBip32DerivationPath}
2121
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
22+
import fr.acinq.bitcoin.scalacompat.Crypto.TaprootTweak.KeyPathTweak
2223
import fr.acinq.bitcoin.scalacompat.DeterministicWallet.KeyPath
2324
import fr.acinq.bitcoin.scalacompat.{Block, ByteVector64, KotlinUtils, OutPoint, Satoshi, SatoshiLong, Script, ScriptElt, ScriptWitness, Transaction, TxId, TxIn, TxOut}
2425
import fr.acinq.eclair.TestUtils.randomTxId
@@ -48,7 +49,7 @@ class DummyOnChainWallet extends OnChainWallet with OnChainAddressCache {
4849
override def onChainBalance()(implicit ec: ExecutionContext): Future[OnChainBalance] = Future.successful(OnChainBalance(1105 sat, 561 sat))
4950

5051
override def getReceivePublicKeyScript(addressType: Option[AddressType] = None)(implicit ec: ExecutionContext): Future[Seq[ScriptElt]] = Future.successful(addressType match {
51-
case Some(AddressType.P2tr) => Script.pay2tr(dummyReceivePubkey.xOnly)
52+
case Some(AddressType.P2tr) => Script.pay2tr(dummyReceivePubkey.xOnly, KeyPathTweak)
5253
case _ => Script.pay2wpkh(dummyReceivePubkey)
5354
})
5455

@@ -90,7 +91,7 @@ class DummyOnChainWallet extends OnChainWallet with OnChainAddressCache {
9091

9192
override def doubleSpent(tx: Transaction)(implicit ec: ExecutionContext): Future[Boolean] = Future.successful(false)
9293

93-
override def getReceivePublicKeyScript(renew: Boolean): Seq[ScriptElt] = Script.pay2tr(dummyReceivePubkey.xOnly)
94+
override def getReceivePublicKeyScript(renew: Boolean): Seq[ScriptElt] = Script.pay2tr(dummyReceivePubkey.xOnly, KeyPathTweak)
9495
}
9596

9697
class SingleKeyOnChainWallet extends OnChainWallet with OnChainAddressCache {
@@ -104,7 +105,7 @@ class SingleKeyOnChainWallet extends OnChainWallet with OnChainAddressCache {
104105
private val p2wpkhScript = Script.pay2wpkh(p2wpkhPublicKey)
105106
private val bip86path = KeyPath("m/86'/1'/0'/0/0")
106107
private val p2trPublicKey = keyManager.derivePublicKey(bip86path)._1.xOnly
107-
private val p2trScript = Script.pay2tr(p2trPublicKey, None)
108+
private val p2trScript = Script.pay2tr(p2trPublicKey, KeyPathTweak)
108109

109110
// We create a new dummy input transaction for every funding request.
110111
var inputs = Seq.empty[Transaction]

eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import akka.pattern.pipe
2121
import akka.testkit.TestProbe
2222
import fr.acinq.bitcoin
2323
import fr.acinq.bitcoin.psbt.{Psbt, UpdateFailure}
24+
import fr.acinq.bitcoin.scalacompat.Crypto.TaprootTweak.KeyPathTweak
2425
import fr.acinq.bitcoin.scalacompat.Crypto.{PublicKey, der2compact}
2526
import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, BlockId, Btc, BtcDouble, Crypto, DeterministicWallet, KotlinUtils, MilliBtcDouble, MnemonicCode, OP_DROP, OP_PUSHDATA, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxId, TxIn, TxOut, addressToPublicKeyScript, computeBIP84Address, computeP2WpkhAddress}
2627
import fr.acinq.bitcoin.{Bech32, SigHash, SigVersion}
@@ -458,7 +459,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A
458459
}
459460
{
460461
// When sending to a p2tr, bitcoin core should add a p2tr change output.
461-
val pubkeyScript = Script.pay2tr(pubKey.xOnly)
462+
val pubkeyScript = Script.pay2tr(pubKey.xOnly, KeyPathTweak)
462463
val unsignedTx = Transaction(version = 2, Nil, Seq(TxOut(150_000 sat, pubkeyScript)), lockTime = 0)
463464
bitcoinClient.fundTransaction(unsignedTx, feeRate = FeeratePerByte(3 sat).perKw, changePosition = Some(1)).pipeTo(sender.ref)
464465
val tx = sender.expectMsgType[FundTransactionResponse].tx

eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/OnChainAddressRefresherSpec.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fr.acinq.eclair.blockchain.bitcoind
22

33
import akka.actor.typed.scaladsl.adapter.ClassicActorSystemOps
4+
import fr.acinq.bitcoin.scalacompat.Crypto.TaprootTweak.KeyPathTweak
45
import fr.acinq.bitcoin.scalacompat.{Script, ScriptElt}
56
import fr.acinq.eclair.blockchain.OnChainAddressGenerator
67
import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient.AddressType
@@ -14,13 +15,13 @@ import scala.concurrent.{ExecutionContext, Future}
1415
class OnChainAddressRefresherSpec extends TestKitBaseClass with AnyFunSuiteLike {
1516

1617
test("renew on-chain addresses") {
17-
val finalPubkeyScript = new AtomicReference[Seq[ScriptElt]](Script.pay2tr(randomKey().xOnlyPublicKey()))
18+
val finalPubkeyScript = new AtomicReference[Seq[ScriptElt]](Script.pay2tr(randomKey().xOnlyPublicKey(), KeyPathTweak))
1819
val renewedCount = new AtomicInteger(0)
1920
val generator = new OnChainAddressGenerator {
2021
override def getReceivePublicKeyScript(addressType: Option[AddressType] = None)(implicit ec: ExecutionContext): Future[Seq[ScriptElt]] = {
2122
renewedCount.incrementAndGet()
2223
Future.successful(addressType match {
23-
case Some(AddressType.P2tr) => Script.pay2tr(randomKey().xOnlyPublicKey())
24+
case Some(AddressType.P2tr) => Script.pay2tr(randomKey().xOnlyPublicKey(), KeyPathTweak)
2425
case _ => Script.pay2wpkh(randomKey().publicKey)
2526
})
2627
}

eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import akka.testkit.TestProbe
2323
import com.softwaremill.quicklens.{ModifyPimp, QuicklensAt}
2424
import fr.acinq.bitcoin.psbt.Psbt
2525
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
26+
import fr.acinq.bitcoin.scalacompat.Crypto.TaprootTweak.KeyPathTweak
2627
import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, ByteVector64, OP_1, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxHash, TxId, TxIn, TxOut, addressToPublicKeyScript}
2728
import fr.acinq.eclair.TestUtils.randomTxId
2829
import fr.acinq.eclair.blockchain.OnChainWallet.{FundTransactionResponse, ProcessPsbtResponse}
@@ -77,7 +78,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
7778
}
7879

7980
private def createInput(channelId: ByteVector32, serialId: UInt64, amount: Satoshi): TxAddInput = {
80-
val changeScript = Script.write(Script.pay2tr(randomKey().publicKey.xOnly))
81+
val changeScript = Script.write(Script.pay2tr(randomKey().publicKey.xOnly, KeyPathTweak))
8182
val previousTx = Transaction(2, Nil, Seq(TxOut(amount, changeScript), TxOut(amount, changeScript), TxOut(amount, changeScript)), 0)
8283
TxAddInput(channelId, serialId, Some(previousTx), 1, 0)
8384
}
@@ -856,8 +857,8 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
856857
probe.expectMsg(txA1.txId)
857858

858859
// Alice and Bob decide to splice funds out of the channel, and deduce on-chain fees from their new channel contribution.
859-
val spliceOutputsA = List(TxOut(50_000 sat, Script.pay2tr(randomKey().xOnlyPublicKey())))
860-
val spliceOutputsB = List(TxOut(30_000 sat, Script.pay2tr(randomKey().xOnlyPublicKey())))
860+
val spliceOutputsA = List(TxOut(50_000 sat, Script.pay2tr(randomKey().xOnlyPublicKey(), KeyPathTweak)))
861+
val spliceOutputsB = List(TxOut(30_000 sat, Script.pay2tr(randomKey().xOnlyPublicKey(), KeyPathTweak)))
861862
val subtractedFundingA = spliceOutputsA.map(_.amount).sum + 1_000.sat
862863
val subtractedFundingB = spliceOutputsB.map(_.amount).sum + 500.sat
863864
val (sharedInputA, sharedInputB) = fixtureParams.sharedInputs(commitmentA1, commitmentB1)
@@ -2558,7 +2559,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
25582559
TxAddOutput(params.channelId, UInt64(1), 25_000 sat, Script.write(Script.pay2sh(OP_1 :: Nil))),
25592560
TxAddOutput(params.channelId, UInt64(1), 25_000 sat, Script.write(Script.pay2wpkh(randomKey().publicKey))),
25602561
TxAddOutput(params.channelId, UInt64(1), 25_000 sat, Script.write(Script.pay2wsh(OP_1 :: Nil))),
2561-
TxAddOutput(params.channelId, UInt64(1), 25_000 sat, Script.write(Script.pay2tr(randomKey().xOnlyPublicKey()))),
2562+
TxAddOutput(params.channelId, UInt64(1), 25_000 sat, Script.write(Script.pay2tr(randomKey().xOnlyPublicKey(), KeyPathTweak))),
25622563
)
25632564
testCases.foreach { output =>
25642565
val alice = params.spawnTxBuilderAlice(wallet)
@@ -2775,7 +2776,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
27752776
bob ! Start(probe.ref)
27762777
// Alice --- tx_add_input --> Bob
27772778
// The input only includes the previous txOut which is only allowed for taproot channels.
2778-
bob ! ReceiveMessage(TxAddInput(params.channelId, UInt64(0), None, 0, 0, TlvStream(TxAddInputTlv.PrevTxOut(randomTxId(), 100_000 sat, Script.write(Script.pay2tr(randomKey().xOnlyPublicKey()))))))
2779+
bob ! ReceiveMessage(TxAddInput(params.channelId, UInt64(0), None, 0, 0, TlvStream(TxAddInputTlv.PrevTxOut(randomTxId(), 100_000 sat, Script.write(Script.pay2tr(randomKey().xOnlyPublicKey(), KeyPathTweak))))))
27792780
assert(probe.expectMsgType[RemoteFailure].cause == PreviousTxMissing(params.channelId, UInt64(0)))
27802781
}
27812782

eclair-core/src/test/scala/fr/acinq/eclair/crypto/keymanager/LocalOnChainKeyManagerSpec.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fr.acinq.eclair.crypto.keymanager
22

33
import fr.acinq.bitcoin.psbt.{KeyPathWithMaster, Psbt, TaprootBip32DerivationPath}
4+
import fr.acinq.bitcoin.scalacompat.Crypto.TaprootTweak.KeyPathTweak
45
import fr.acinq.bitcoin.scalacompat.{Block, DeterministicWallet, MnemonicCode, OutPoint, Satoshi, Script, ScriptElt, Transaction, TxIn, TxOut}
56
import fr.acinq.bitcoin.{ScriptFlags, SigHash}
67
import fr.acinq.eclair.{TimestampSecond, randomBytes32}
@@ -130,9 +131,9 @@ class LocalOnChainKeyManagerSpec extends AnyFunSuite {
130131
def getPublicKey(index: Long) = DeterministicWallet.derivePublicKey(mainPub, index).publicKey.xOnly
131132

132133
val utxos = Seq(
133-
Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(1_000_000), Script.pay2tr(getPublicKey(0), None)) :: Nil, lockTime = 0),
134-
Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(1_100_000), Script.pay2tr(getPublicKey(1), None)) :: Nil, lockTime = 0),
135-
Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(1_200_000), Script.pay2tr(getPublicKey(2), None)) :: Nil, lockTime = 0),
134+
Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(1_000_000), Script.pay2tr(getPublicKey(0), KeyPathTweak)) :: Nil, lockTime = 0),
135+
Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(1_100_000), Script.pay2tr(getPublicKey(1), KeyPathTweak)) :: Nil, lockTime = 0),
136+
Transaction(version = 2, txIn = Nil, txOut = TxOut(Satoshi(1_200_000), Script.pay2tr(getPublicKey(2), KeyPathTweak)) :: Nil, lockTime = 0),
136137
)
137138
val bip32paths = Seq(
138139
new TaprootBip32DerivationPath(java.util.List.of(), 0, new fr.acinq.bitcoin.KeyPath("m/86'/1'/0'/0/0")),
@@ -142,7 +143,7 @@ class LocalOnChainKeyManagerSpec extends AnyFunSuite {
142143

143144
val tx = Transaction(version = 2,
144145
txIn = utxos.map(tx => TxIn(OutPoint(tx, 0), Nil, fr.acinq.bitcoin.TxIn.SEQUENCE_FINAL)),
145-
txOut = TxOut(Satoshi(1000_000), Script.pay2tr(getPublicKey(0), None)) :: Nil, lockTime = 0)
146+
txOut = TxOut(Satoshi(1000_000), Script.pay2tr(getPublicKey(0), KeyPathTweak)) :: Nil, lockTime = 0)
146147

147148
val Right(psbt) = for {
148149
p0 <- new Psbt(tx).updateWitnessInput(OutPoint(utxos(0), 0), utxos(0).txOut(0), null, null, null, java.util.Map.of(), null, getPublicKey(0), java.util.Map.of(getPublicKey(0), bip32paths(0)))

0 commit comments

Comments
 (0)