diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt index 1ff6a446..40cd8916 100644 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt @@ -27,4 +27,34 @@ class LiveTxBuilderTest { println(psbt.serialize()) assertTrue(psbt.serialize().startsWith("cHNi"), "PSBT should start with 'cHNi'") } + + @Test + fun complexTxBuilder() { + val externalDescriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET) + val changeDescriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/1/*)", Network.TESTNET) + val wallet = Wallet.newNoPersist(externalDescriptor, changeDescriptor, Network.TESTNET) + val esploraClient = EsploraClient("https://mempool.space/testnet/api") + val update = esploraClient.scan(wallet, 10uL, 1uL) + wallet.applyUpdate(update) + println("Balance: ${wallet.getBalance().total}") + + assert(wallet.getBalance().total > 0uL) + + val recipient1: Address = Address("tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", Network.TESTNET) + val recipient2: Address = Address("tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6", Network.TESTNET) + val allRecipients: List = listOf( + ScriptAmount(recipient1.scriptPubkey(), 4200uL), + ScriptAmount(recipient2.scriptPubkey(), 4200uL), + ) + + val psbt: PartiallySignedTransaction = TxBuilder() + .setRecipients(allRecipients) + .feeRate(4.0f) + .changePolicy(ChangeSpendPolicy.CHANGE_FORBIDDEN) + .enableRbf() + .finish(wallet) + + wallet.sign(psbt) + assertTrue(psbt.serialize().startsWith("cHNi"), "PSBT should start with 'cHNi'") + } } diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index 3ac91ed2..e1414214 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -118,7 +118,7 @@ interface TxBuilder { TxBuilder add_recipient(Script script, u64 amount); - TxBuilder set_recipients(sequence script_amount); + TxBuilder set_recipients(sequence recipients); TxBuilder add_unspendable(OutPoint unspendable); diff --git a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt index d99f5597..1cea5d9e 100644 --- a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt +++ b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt @@ -1,7 +1,6 @@ package org.bitcoindevkit import kotlin.test.Test -import kotlin.test.assertEquals import kotlin.test.assertTrue class LiveTxBuilderTest { @@ -26,4 +25,34 @@ class LiveTxBuilderTest { assertTrue(psbt.serialize().startsWith("cHNi"), "PSBT should start with 'cHNi'") } + + @Test + fun complexTxBuilder() { + val externalDescriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET) + val changeDescriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/1/*)", Network.TESTNET) + val wallet = Wallet.newNoPersist(externalDescriptor, changeDescriptor, Network.TESTNET) + val esploraClient = EsploraClient("https://mempool.space/testnet/api") + val update = esploraClient.scan(wallet, 10uL, 1uL) + wallet.applyUpdate(update) + println("Balance: ${wallet.getBalance().total}") + + assert(wallet.getBalance().total > 0uL) + + val recipient1: Address = Address("tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", Network.TESTNET) + val recipient2: Address = Address("tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6", Network.TESTNET) + val allRecipients: List = listOf( + ScriptAmount(recipient1.scriptPubkey(), 4200uL), + ScriptAmount(recipient2.scriptPubkey(), 4200uL), + ) + + val psbt: PartiallySignedTransaction = TxBuilder() + .setRecipients(allRecipients) + .feeRate(4.0f) + .changePolicy(ChangeSpendPolicy.CHANGE_FORBIDDEN) + .enableRbf() + .finish(wallet) + + wallet.sign(psbt) + assertTrue(psbt.serialize().startsWith("cHNi"), "PSBT should start with 'cHNi'") + } } diff --git a/bdk-python/tests/test_live_tx_builder.py b/bdk-python/tests/test_live_tx_builder.py index 8416513d..1802c99d 100644 --- a/bdk-python/tests/test_live_tx_builder.py +++ b/bdk-python/tests/test_live_tx_builder.py @@ -33,6 +33,48 @@ def test_tx_builder(self): self.assertTrue(psbt.serialize().startswith("cHNi"), "The PSBT should start with cHNi") - + def complex_tx_builder(self): + descriptor: bdk.Descriptor = bdk.Descriptor( + "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)", + bdk.Network.TESTNET + ) + change_descriptor: bdk.Descriptor = bdk.Descriptor( + "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)", + bdk.Network.TESTNET + ) + wallet: bdk.Wallet = bdk.Wallet.new_no_persist( + descriptor, + change_descriptor, + bdk.Network.TESTNET + ) + esploraClient: bdk.EsploraClient = bdk.EsploraClient(url = "https://mempool.space/testnet/api") + update = esploraClient.scan( + wallet = wallet, + stop_gap = 10, + parallel_requests = 1 + ) + wallet.apply_update(update) + + self.assertGreater(wallet.get_balance().total, 0) + + recipient1 = bdk.Address( + address = "tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", + network = bdk.Network.TESTNET + ) + recipient2 = bdk.Address( + address = "tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6", + network = bdk.Network.TESTNET + ) + all_recipients = list( + bdk.ScriptAmount(recipient1.script_pubkey, 4200), + bdk.ScriptAmount(recipient2.script_pubkey, 4200) + ) + + psbt: bdk.PartiallySignedTransaction = bdk.TxBuilder().set_recipients(all_recipients).fee_rate(4.0).change_policy(bdk.ChangeSpendPolicy.CHANGE_FORBIDDEN).enable_rbf().finish(wallet) + wallet.sign(psbt) + + self.assertTrue(psbt.serialize().startswith("cHNi"), "The PSBT should start with cHNi") + + if __name__ == '__main__': unittest.main() diff --git a/bdk-python/tests/test_live_wallet.py b/bdk-python/tests/test_live_wallet.py index cb3b5461..922fada0 100644 --- a/bdk-python/tests/test_live_wallet.py +++ b/bdk-python/tests/test_live_wallet.py @@ -41,7 +41,7 @@ def test_broadcast_transaction(self): ) wallet.apply_update(update) - self.assertGreater(wallet.get_balance().total(), 0) + self.assertGreater(wallet.get_balance().total, 0) recipient = bdk.Address( address = "tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", diff --git a/bdk-swift/Tests/BitcoinDevKitTests/LiveTxBuilderTests.swift b/bdk-swift/Tests/BitcoinDevKitTests/LiveTxBuilderTests.swift index d325d8b4..12d1606b 100644 --- a/bdk-swift/Tests/BitcoinDevKitTests/LiveTxBuilderTests.swift +++ b/bdk-swift/Tests/BitcoinDevKitTests/LiveTxBuilderTests.swift @@ -31,4 +31,47 @@ final class LiveTxBuilderTests: XCTestCase { print(psbt.serialize()) XCTAssertTrue(psbt.serialize().hasPrefix("cHNi"), "PSBT should start with cHNI") } + + func testComplexTxBuilder() throws { + let descriptor = try Descriptor( + descriptor: "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", + network: Network.testnet + ) + let changeDescriptor = try Descriptor( + descriptor: "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/1/*)", + network: Network.testnet + ) + let wallet = try Wallet.newNoPersist( + descriptor: descriptor, + changeDescriptor: changeDescriptor, + network: .testnet + ) + let esploraClient = EsploraClient(url: "https://mempool.space/testnet/api") + let update = try esploraClient.scan( + wallet: wallet, + stopGap: 10, + parallelRequests: 1 + ) + try wallet.applyUpdate(update: update) + + XCTAssertGreaterThan(wallet.getBalance().total, UInt64(0), "Wallet must have positive balance, please add funds") + + let recipient1: Address = try Address(address: "tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", network: .testnet) + let recipient2: Address = try Address(address: "tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6", network: .testnet) + let allRecipients: [ScriptAmount] = [ + ScriptAmount(script: recipient1.scriptPubkey(), amount: 4200), + ScriptAmount(script: recipient2.scriptPubkey(), amount: 4200) + ] + + let psbt: PartiallySignedTransaction = try TxBuilder() + .setRecipients(recipients: allRecipients) + .feeRate(satPerVbyte: 4.0) + .changePolicy(changePolicy: ChangeSpendPolicy.changeForbidden) + .enableRbf() + .finish(wallet: wallet) + + try! wallet.sign(psbt: psbt) + + XCTAssertTrue(psbt.serialize().hasPrefix("cHNi"), "PSBT should start with cHNI") + } }