diff --git a/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt b/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt index c22341f1..6fa4ad13 100644 --- a/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt +++ b/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt @@ -153,7 +153,7 @@ data class EsploraConfig( ) /** - * Authentication mechanism for RPC connection to full node + * Authentication mechanism for RPC connection to full node. */ sealed class Auth { /** No authentication */ @@ -350,15 +350,15 @@ data class BlockTime ( * @constructor Create a BDK wallet. * * @param descriptor The main (or "external") descriptor. - * @param changeDescriptor The change (or "internal") descriptor. + * @param changeDescriptor? The change (or "internal") descriptor. * @param network The network to act on. * @param databaseConfig The database configuration. * * @sample org.bitcoindevkit.walletSample */ class Wallet( - descriptor: String, - changeDescriptor: String, + descriptor: Descriptor, + changeDescriptor: Descriptor?, network: Network, databaseConfig: DatabaseConfig, ) { @@ -550,7 +550,7 @@ class DescriptorSecretKey(network: Network, mnemonic: Mnemonic, password: String /** Return the public version of the descriptor. */ fun asPublic(): DescriptorPublicKey {} - /* Return the raw private key as bytes. */ + /** Return the raw private key as bytes. */ fun secretBytes(): List /** Return the private descriptor as a string. */ @@ -578,6 +578,62 @@ class DescriptorPublicKey(network: Network, mnemonic: String, password: String?) fun asString(): String } +/** + * A output descriptor. + * + * @param descriptor The descriptor in string format. + * @param network The network this descriptor is to be used on. + * + * @sample org.bitcoindevkit.descriptorTemplates1 + * @sample org.bitcoindevkit.descriptorTemplates2 + */ +class Descriptor(descriptor: String, network: Network) { + /** + * BIP44 template. Expands to pkh(key/44'/{0,1}'/0'/{0,1}/\*) + * Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv). + */ + fun newBip44(secretKey: DescriptorSecretKey, keychain: KeychainKind, network: Network) {} + + /** + * BIP44 public template. Expands to pkh(key/{0,1}/\*) + * This assumes that the key used has already been derived with m/44'/0'/0' for Mainnet or m/44'/1'/0' for Testnet. + * This template requires the parent fingerprint to populate correctly the metadata of PSBTs. + */ + fun newBip44Public(publicKey: DescriptorPublicKey, fingerprint: String, keychain: KeychainKind, network: Network) {} + + /** + * BIP49 template. Expands to sh(wpkh(key/49'/{0,1}'/0'/{0,1}/\*)) + * Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv). + */ + fun newBip49(secretKey: DescriptorSecretKey, keychain: KeychainKind, network: Network) {} + + /** + * BIP49 public template. Expands to sh(wpkh(key/{0,1}/\*)) + * This assumes that the key used has already been derived with m/49'/0'/0' for Mainnet or m/49'/1'/0' for Testnet. + * This template requires the parent fingerprint to populate correctly the metadata of PSBTs. + */ + fun newBip49Public(publicKey: DescriptorPublicKey, fingerprint: String, keychain: KeychainKind, network: Network) {} + + /** + * BIP84 template. Expands to wpkh(key/84'/{0,1}'/0'/{0,1}/\*) + * Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv). + */ + fun newBip84(secretKey: DescriptorSecretKey, keychain: KeychainKind, network: Network) {} + + /** + * BIP84 public template. Expands to wpkh(key/{0,1}/\*) + * This assumes that the key used has already been derived with m/84'/0'/0' for Mainnet or m/84'/1'/0' for Testnet. + * This template requires the parent fingerprint to populate correctly the metadata of PSBTs. + */ + fun newBip84Public(publicKey: DescriptorPublicKey, fingerprint: String, keychain: KeychainKind, network: Network) {} + + /** Return the public version of the output descriptor. */ + fun asString(): String {} + + /** Return the private version of the output descriptor if available, otherwise return the public version. */ + fun asStringPrivate(): String {} +} + /** * An enum describing entropy length (aka word count) in the mnemonic. */ @@ -623,7 +679,7 @@ class Script(rawOutputScript: List) * @param address The address in string format. */ class Address(address: String) { - /* Return the ScriptPubKey. */ + /** Return the ScriptPubKey. */ fun scriptPubkey(): Script } diff --git a/api-docs/kotlin/src/test/kotlin/org/bitcoindevkit/Samples.kt b/api-docs/kotlin/src/test/kotlin/org/bitcoindevkit/Samples.kt index a411eb00..8fe7dfec 100644 --- a/api-docs/kotlin/src/test/kotlin/org/bitcoindevkit/Samples.kt +++ b/api-docs/kotlin/src/test/kotlin/org/bitcoindevkit/Samples.kt @@ -243,3 +243,34 @@ fun mnemonicSample() { println(mnemonic0.asString(), mnemonic1.asString(), mnemonic2.asString()) } + +fun descriptorTemplates1() { + // Bip84 private descriptor + val recoveryPhrase: String = "scene change clap smart together mind wheel knee clip normal trial unusual" + val mnemonic = Mnemonic.fromString(recoveryPhrase) + val bip32ExtendedRootKey: DescriptorSecretKey = DescriptorSecretKey(Network.TESTNET, mnemonic, null) + val bip84ExternalDescriptor: Descriptor = Descriptor.newBip84(bip32ExtendedRootKey, KeychainKind.EXTERNAL, Network.TESTNET) +} + +fun descriptorTemplates2() { + // Bip49 public descriptor + // assume we already have the xpub for m/49'/0'/1' created on an external device that only shared the xpub with the wallet + // using the template requires the parent fingerprint to populate correctly the metadata of PSBTs, which the external device would provide + // the xpub (tpub for testnet): tpubDC65ZRvk1NDddHrVAUAZrUPJ772QXzooNYmPywYF9tMyNLYKf5wpKE7ZJvK9kvfG3FV7rCsHBNXy1LVKW95jrmC7c7z4hq7a27aD2sRrAhR + // the fingerprint: d1d04177 + val descriptorPublicKey: DescriptorPublicKey = DescriptorPublicKey.fromString("tpubDC65ZRvk1NDddHrVAUAZrUPJ772QXzooNYmPywYF9tMyNLYKf5wpKE7ZJvK9kvfG3FV7rCsHBNXy1LVKW95jrmC7c7z4hq7a27aD2sRrAhR") + val bip49PublicDescriptor: Descriptor = Descriptor.newBip49Public( + publicKey = descriptorPublicKey, + fingerprint = "d1d04177", + keychain = KeychainKind.EXTERNAL, + network = Network.TESTNET, + ) + println(bip49PublicDescriptor.asString()) // sh(wpkh([d1d04177/49'/1'/0']tpubDC65ZRvk1NDddHrVAUAZrUPJ772QXzooNYmPywYF9tMyNLYKf5wpKE7ZJvK9kvfG3FV7rCsHBNXy1LVKW95jrmC7c7z4hq7a27aD2sRrAhR/0/*))#a7lxzefl + println(bip49PublicDescriptor.asStringPrivate()) // sh(wpkh([d1d04177/49'/1'/0']tpubDC65ZRvk1NDddHrVAUAZrUPJ772QXzooNYmPywYF9tMyNLYKf5wpKE7ZJvK9kvfG3FV7rCsHBNXy1LVKW95jrmC7c7z4hq7a27aD2sRrAhR/0/*))#a7lxzefl + + // Creating it starting from the full xprv derived from a mnemonic will give you the same public descriptor + val mnemonic = Mnemonic.fromString("chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect") + val bip32ExtendedRootKey: DescriptorSecretKey = DescriptorSecretKey(Network.TESTNET, mnemonic, null) + val bip49PrivateDescriptor: Descriptor = Descriptor.newBip49(bip32ExtendedRootKey, KeychainKind.EXTERNAL, Network.TESTNET) + println(bip49PrivateDescriptor.asString()) // sh(wpkh([d1d04177/49'/1'/0']tpubDC65ZRvk1NDddHrVAUAZrUPJ772QXzooNYmPywYF9tMyNLYKf5wpKE7ZJvK9kvfG3FV7rCsHBNXy1LVKW95jrmC7c7z4hq7a27aD2sRrAhR/0/*))#a7lxzefl +} diff --git a/bdk-android/README.md b/bdk-android/README.md index 2e4b882c..b5b8e437 100644 --- a/bdk-android/README.md +++ b/bdk-android/README.md @@ -25,7 +25,7 @@ val internalDescriptor = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEm val databaseConfig = DatabaseConfig.Memory val blockchainConfig = BlockchainConfig.Electrum( - ElectrumConfig("ssl://electrum.blockstream.info:60002", null, 5u, null, 10u) + ElectrumConfig("ssl://electrum.blockstream.info:60002", null, 5u, null, 10u, true) ) val wallet = Wallet(externalDescriptor, internalDescriptor, Network.TESTNET, databaseConfig, blockchainConfig) val newAddress = wallet.getAddress(AddressIndex.LAST_UNUSED) diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/AndroidLibTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/AndroidLibTest.kt index 218318fd..bf1ccdd0 100644 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/AndroidLibTest.kt +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/AndroidLibTest.kt @@ -46,7 +46,8 @@ class AndroidLibTest { null, 5u, null, - 100u + 100u, + true, ) ) diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index 2f758534..12f86f4f 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -1697,19 +1697,18 @@ mod test { ); // when using as_string on a private key, we get the same result as when using it on a public key - // these currently fails as described in #817 - // assert_eq!( - // template_private_44.as_string(), - // template_public_44.as_string() - // ); - // assert_eq!( - // template_private_49.as_string(), - // template_public_49.as_string() - // ); - // assert_eq!( - // template_private_84.as_string(), - // template_public_84.as_string() - // ); + assert_eq!( + template_private_44.as_string(), + template_public_44.as_string() + ); + assert_eq!( + template_private_49.as_string(), + template_public_49.as_string() + ); + assert_eq!( + template_private_84.as_string(), + template_public_84.as_string() + ); } #[test] diff --git a/bdk-jvm/README.md b/bdk-jvm/README.md index 627fd6c7..3a0d5549 100644 --- a/bdk-jvm/README.md +++ b/bdk-jvm/README.md @@ -25,7 +25,7 @@ val internalDescriptor = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEm val databaseConfig = DatabaseConfig.Memory val blockchainConfig = BlockchainConfig.Electrum( - ElectrumConfig("ssl://electrum.blockstream.info:60002", null, 5u, null, 10u) + ElectrumConfig("ssl://electrum.blockstream.info:60002", null, 5u, null, 10u, true) ) val wallet = Wallet(externalDescriptor, internalDescriptor, Network.TESTNET, databaseConfig, blockchainConfig) val newAddress = wallet.getAddress(AddressIndex.LAST_UNUSED) diff --git a/bdk-python/setup.py b/bdk-python/setup.py index e4a02567..aa419bbf 100644 --- a/bdk-python/setup.py +++ b/bdk-python/setup.py @@ -18,7 +18,7 @@ import bdkpython as bdk -descriptor = "wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/0h/0h/0/*)" +descriptor = bdk.Descriptor("wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/0h/0h/0/*)", bdk.Network.TESTNET) db_config = bdk.DatabaseConfig.MEMORY() blockchain_config = bdk.BlockchainConfig.ELECTRUM( bdk.ElectrumConfig( @@ -26,7 +26,8 @@ None, 5, None, - 100 + 100, + True, ) ) blockchain = bdk.Blockchain(blockchain_config) diff --git a/bdk-python/tests/test_bdk.py b/bdk-python/tests/test_bdk.py index e546592a..27f47d3a 100644 --- a/bdk-python/tests/test_bdk.py +++ b/bdk-python/tests/test_bdk.py @@ -1,7 +1,8 @@ import bdkpython as bdk import unittest -descriptor = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)" + +descriptor = bdk.Descriptor("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)", bdk.Network.TESTNET) db_config = bdk.DatabaseConfig.MEMORY() blockchain_config = bdk.BlockchainConfig.ELECTRUM( bdk.ElectrumConfig( @@ -9,7 +10,8 @@ None, 5, None, - 100 + 100, + True, ) ) blockchain = bdk.Blockchain(blockchain_config) diff --git a/bdk-swift/README.md b/bdk-swift/README.md index 540168e5..5de436af 100644 --- a/bdk-swift/README.md +++ b/bdk-swift/README.md @@ -5,14 +5,14 @@ This project builds a Swift package that provides [Swift] language bindings for Supported target platforms are: -- MacOS, X86_64 and M1 (aarch64) +- macOS, X86_64 and M1 (aarch64) - iOS, iPhones (aarch64) - iOS simulator, X86_64 and M1 (aarch64) ## How to Use -To use the Swift language bindings for [`bdk`] in your [Xcode] iOS or MacOS project add -the github repository https://github.com/bitcoindevkit/bdk-swift and select one of the +To use the Swift language bindings for [`bdk`] in your [Xcode] iOS or macOS project add +the GitHub repository https://github.com/bitcoindevkit/bdk-swift and select one of the release versions. You may then import and use the `BitcoinDevKit` library in your Swift code. For example: @@ -40,11 +40,11 @@ swift test ## How to Build and Publish If you are a maintainer of this project or want to build and publish this project to your -own Github repository use the following steps: +own GitHub repository use the following steps: 1. If it doesn't already exist, create a new `release/0.MINOR` branch from the `master` branch. 2. Add a tag `v0.MINOR.PATCH`. -3. Run the `publish-spm` workflow on Github from the `bdk-swift` repo for version `0.MINOR.PATCH`. +3. Run the `publish-spm` workflow on GitHub from the `bdk-swift` repo for version `0.MINOR.PATCH`. [Swift]: https://developer.apple.com/swift/ [Xcode]: https://developer.apple.com/documentation/Xcode