feat: upgrade bdk to 1.0.0-alpha.2
This is a big change that updates some of our build infrastructure as well as upgrading the bdk dependency. It adds the simple new_no_persist constructor on the wallet as well as the blocking esplora client.
This commit is contained in:
		
							parent
							
								
									743862fb60
								
							
						
					
					
						commit
						790aee9b3b
					
				
							
								
								
									
										14
									
								
								.github/workflows/audit.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/audit.yml
									
									
									
									
										vendored
									
									
								
							@ -12,8 +12,14 @@ jobs:
 | 
			
		||||
  security_audit:
 | 
			
		||||
    name: Security audit
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
    defaults:
 | 
			
		||||
      run:
 | 
			
		||||
        working-directory: bdk-ffi
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v3
 | 
			
		||||
      - uses: actions-rs/audit-check@v1
 | 
			
		||||
        with:
 | 
			
		||||
          token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
      - name: "Check out PR branch"
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
      - name: "Run audit"
 | 
			
		||||
        run: |
 | 
			
		||||
          cargo install cargo-audit
 | 
			
		||||
          cargo-audit audit
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								.github/workflows/cont_integration.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										51
									
								
								.github/workflows/cont_integration.yml
									
									
									
									
										vendored
									
									
								
							@ -9,22 +9,26 @@ on:
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  build-test:
 | 
			
		||||
    name: Build and test
 | 
			
		||||
    name: "Build and test"
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
    defaults:
 | 
			
		||||
      run:
 | 
			
		||||
        working-directory: bdk-ffi
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        rust:
 | 
			
		||||
          - version: 1.71.0 # STABLE
 | 
			
		||||
          - version: 1.67.0
 | 
			
		||||
            clippy: true
 | 
			
		||||
          - version: 1.61.0 # MSRV
 | 
			
		||||
          # TODO 1: Should we keep this? We'll need to pin dependencies
 | 
			
		||||
          # - version: 1.61.0 # MSRV
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
      - name: "Checkout"
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
      - name: Generate cache key
 | 
			
		||||
      - name: "Generate cache key"
 | 
			
		||||
        run: echo "${{ matrix.rust.version }} ${{ matrix.features }}" | tee .cache_key
 | 
			
		||||
 | 
			
		||||
      - name: Cache
 | 
			
		||||
      - name: "Cache"
 | 
			
		||||
        uses: actions/cache@v3
 | 
			
		||||
        with:
 | 
			
		||||
          path: |
 | 
			
		||||
@ -33,53 +37,56 @@ jobs:
 | 
			
		||||
            target
 | 
			
		||||
          key: ${{ runner.os }}-cargo-${{ hashFiles('.cache_key') }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
 | 
			
		||||
 | 
			
		||||
      - name: Set default toolchain
 | 
			
		||||
      - name: "Set default toolchain"
 | 
			
		||||
        run: rustup default ${{ matrix.rust.version }}
 | 
			
		||||
 | 
			
		||||
      - name: Set profile
 | 
			
		||||
      - name: "Set profile"
 | 
			
		||||
        run: rustup set profile minimal
 | 
			
		||||
 | 
			
		||||
      - name: Add clippy
 | 
			
		||||
      - name: "Add clippy"
 | 
			
		||||
        if: ${{ matrix.rust.clippy }}
 | 
			
		||||
        run: rustup component add clippy
 | 
			
		||||
 | 
			
		||||
      - name: Update toolchain
 | 
			
		||||
      - name: "Update toolchain"
 | 
			
		||||
        run: rustup update
 | 
			
		||||
 | 
			
		||||
      - name: Pin dependencies for MSRV
 | 
			
		||||
      - name: "Pin dependencies for MSRV"
 | 
			
		||||
        if: matrix.rust.version == '1.61.0'
 | 
			
		||||
        run: |
 | 
			
		||||
          cargo update -p hashlink --precise "0.8.1"
 | 
			
		||||
          cargo update -p tokio --precise "1.29.1"
 | 
			
		||||
          cargo update -p flate2 --precise "1.0.26"
 | 
			
		||||
      - name: Build
 | 
			
		||||
      - name: "Build"
 | 
			
		||||
        run: cargo build
 | 
			
		||||
 | 
			
		||||
      - name: Clippy
 | 
			
		||||
      - name: "Clippy"
 | 
			
		||||
        if: ${{ matrix.rust.clippy }}
 | 
			
		||||
        run: cargo clippy --all-targets --features "uniffi/bindgen-tests" -- -D warnings
 | 
			
		||||
 | 
			
		||||
      - name: Test
 | 
			
		||||
      - name: "Test"
 | 
			
		||||
        run: CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test --features uniffi/bindgen-tests
 | 
			
		||||
 | 
			
		||||
  fmt:
 | 
			
		||||
    name: Rust fmt
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    name: "Rust fmt"
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
    defaults:
 | 
			
		||||
      run:
 | 
			
		||||
        working-directory: bdk-ffi
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
      - name: "Checkout"
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
      - name: Set default toolchain
 | 
			
		||||
      - name: "Set default toolchain"
 | 
			
		||||
        run: rustup default nightly
 | 
			
		||||
 | 
			
		||||
      - name: Set profile
 | 
			
		||||
      - name: "Set profile"
 | 
			
		||||
        run: rustup set profile minimal
 | 
			
		||||
 | 
			
		||||
      - name: Add rustfmt
 | 
			
		||||
      - name: "Add rustfmt"
 | 
			
		||||
        run: rustup component add rustfmt
 | 
			
		||||
 | 
			
		||||
      - name: Update toolchain
 | 
			
		||||
      - name: "Update toolchain"
 | 
			
		||||
        run: rustup update
 | 
			
		||||
 | 
			
		||||
      - name: Check fmt
 | 
			
		||||
      - name: "Check fmt"
 | 
			
		||||
        run: cargo fmt --all -- --config format_code_in_doc_comments=true --check
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								.github/workflows/publish-python.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/publish-python.yaml
									
									
									
									
										vendored
									
									
								
							@ -29,6 +29,7 @@ jobs:
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          submodules: true
 | 
			
		||||
      # TODO 2: Other CI workflows use explicit Rust compiler versions, I think we should do the same here
 | 
			
		||||
      - uses: actions-rs/toolchain@v1
 | 
			
		||||
        with:
 | 
			
		||||
          toolchain: stable
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										39
									
								
								.github/workflows/test-swift.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								.github/workflows/test-swift.yaml
									
									
									
									
										vendored
									
									
								
							@ -12,44 +12,15 @@ on:
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  build:
 | 
			
		||||
    name: "Build and test"
 | 
			
		||||
    runs-on: macos-12
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
      - name: "Checkout"
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
      - name: "Set default Rust version to 1.67.0"
 | 
			
		||||
        run: rustup default 1.67.0
 | 
			
		||||
      - name: "Build Swift package"
 | 
			
		||||
        run: bash ./bdk-swift/build-local-swift.sh
 | 
			
		||||
 | 
			
		||||
      - name: Install Rust targets
 | 
			
		||||
        run: |
 | 
			
		||||
          rustup install nightly-x86_64-apple-darwin
 | 
			
		||||
          rustup component add rust-src --toolchain nightly-x86_64-apple-darwin
 | 
			
		||||
          rustup target add aarch64-apple-darwin x86_64-apple-darwin
 | 
			
		||||
 | 
			
		||||
      - name: Run bdk-ffi-bindgen
 | 
			
		||||
        working-directory: bdk-ffi
 | 
			
		||||
        run: cargo run --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format
 | 
			
		||||
 | 
			
		||||
      - name: Build bdk-ffi for x86_64-apple-darwin
 | 
			
		||||
        run: cargo build --package bdk-ffi --profile release-smaller --target x86_64-apple-darwin
 | 
			
		||||
 | 
			
		||||
      - name: Build bdk-ffi for aarch64-apple-darwin
 | 
			
		||||
        run: cargo build --package bdk-ffi --profile release-smaller --target aarch64-apple-darwin
 | 
			
		||||
 | 
			
		||||
      - name: Create lipo-macos
 | 
			
		||||
        run: |
 | 
			
		||||
          mkdir -p target/lipo-macos/release-smaller
 | 
			
		||||
          lipo target/aarch64-apple-darwin/release-smaller/libbdkffi.a target/x86_64-apple-darwin/release-smaller/libbdkffi.a -create -output target/lipo-macos/release-smaller/libbdkffi.a
 | 
			
		||||
 | 
			
		||||
      - name: Create bdkFFI.xcframework
 | 
			
		||||
        working-directory: bdk-swift
 | 
			
		||||
        run: |
 | 
			
		||||
          mv Sources/BitcoinDevKit/bdk.swift Sources/BitcoinDevKit/BitcoinDevKit.swift
 | 
			
		||||
          cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers
 | 
			
		||||
          cp ../target/lipo-macos/release-smaller/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI
 | 
			
		||||
          rm Sources/BitcoinDevKit/bdkFFI.h
 | 
			
		||||
          rm Sources/BitcoinDevkit/bdkFFI.modulemap
 | 
			
		||||
 | 
			
		||||
      - name: Run Swift tests
 | 
			
		||||
      - name: "Run Swift tests"
 | 
			
		||||
        working-directory: bdk-swift
 | 
			
		||||
        run: swift test
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								Cargo.toml
									
									
									
									
									
								
							@ -1,12 +0,0 @@
 | 
			
		||||
[workspace]
 | 
			
		||||
members = ["bdk-ffi"]
 | 
			
		||||
default-members = ["bdk-ffi"]
 | 
			
		||||
exclude = ["api-docs", "bdk-android", "bdk-jvm", "bdk-python", "bdk-swift"]
 | 
			
		||||
 | 
			
		||||
[profile.release-smaller]
 | 
			
		||||
inherits = "release"
 | 
			
		||||
opt-level = 'z'     # Optimize for size.
 | 
			
		||||
lto = true          # Enable Link Time Optimization
 | 
			
		||||
codegen-units = 1   # Reduce number of codegen units to increase optimizations.
 | 
			
		||||
panic = 'abort'     # Abort on panic
 | 
			
		||||
strip = true        # Strip symbols from binary
 | 
			
		||||
@ -18,64 +18,42 @@ import java.io.File
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(AndroidJUnit4::class)
 | 
			
		||||
class AndroidLibTest {
 | 
			
		||||
 | 
			
		||||
    private fun getTestDataDir(): String {
 | 
			
		||||
        val context = ApplicationProvider.getApplicationContext<Application>()
 | 
			
		||||
        return context.getDir("bdk-test", MODE_PRIVATE).toString()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun cleanupTestDataDir(testDataDir: String) {
 | 
			
		||||
        File(testDataDir).deleteRecursively()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class LogProgress : Progress {
 | 
			
		||||
        private val log: Logger = LoggerFactory.getLogger(AndroidLibTest::class.java)
 | 
			
		||||
 | 
			
		||||
        override fun update(progress: Float, message: String?) {
 | 
			
		||||
            log.debug("Syncing...")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val descriptor = Descriptor("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)", Network.TESTNET)
 | 
			
		||||
 | 
			
		||||
    private val databaseConfig = DatabaseConfig.Memory
 | 
			
		||||
 | 
			
		||||
    private val blockchainConfig = BlockchainConfig.Electrum(
 | 
			
		||||
        ElectrumConfig(
 | 
			
		||||
            "ssl://electrum.blockstream.info:60002",
 | 
			
		||||
            null,
 | 
			
		||||
            5u,
 | 
			
		||||
            null,
 | 
			
		||||
            100u,
 | 
			
		||||
            true,
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun memoryWalletNewAddress() {
 | 
			
		||||
        val wallet = Wallet(descriptor, null, Network.TESTNET, databaseConfig)
 | 
			
		||||
        val address = wallet.getAddress(AddressIndex.New).address.asString()
 | 
			
		||||
        assertEquals("tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e", address)
 | 
			
		||||
        @Test
 | 
			
		||||
    fun testNetwork() {
 | 
			
		||||
        val signetNetwork = Network.SIGNET
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun memoryWalletSyncGetBalance() {
 | 
			
		||||
        val wallet = Wallet(descriptor, null, Network.TESTNET, databaseConfig)
 | 
			
		||||
        val blockchain = Blockchain(blockchainConfig)
 | 
			
		||||
        wallet.sync(blockchain, LogProgress())
 | 
			
		||||
        val balance: Balance = wallet.getBalance()
 | 
			
		||||
        assertTrue(balance.total > 0u)
 | 
			
		||||
    fun testDescriptorBip86() {
 | 
			
		||||
        val mnemonic = Mnemonic(WordCount.WORDS12)
 | 
			
		||||
        val descriptorSecretKey = DescriptorSecretKey(Network.TESTNET, mnemonic, null)
 | 
			
		||||
        val descriptor = Descriptor.newBip86(descriptorSecretKey, KeychainKind.EXTERNAL, Network.TESTNET)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun sqliteWalletSyncGetBalance() {
 | 
			
		||||
        val testDataDir = getTestDataDir() + "/bdk-wallet.sqlite"
 | 
			
		||||
        val databaseConfig = DatabaseConfig.Sqlite(SqliteDbConfiguration(testDataDir))
 | 
			
		||||
        val wallet = Wallet(descriptor, null, Network.TESTNET, databaseConfig)
 | 
			
		||||
        val blockchain = Blockchain(blockchainConfig)
 | 
			
		||||
        wallet.sync(blockchain, LogProgress())
 | 
			
		||||
        val balance: Balance = wallet.getBalance()
 | 
			
		||||
        assertTrue(balance.total > 0u)
 | 
			
		||||
        cleanupTestDataDir(testDataDir)
 | 
			
		||||
    fun testUsedWallet() {
 | 
			
		||||
        val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET)
 | 
			
		||||
        val wallet = Wallet.newNoPersist(descriptor, null, Network.TESTNET)
 | 
			
		||||
        val (index, address, keychain)  = wallet.getAddress(AddressIndex.LastUnused)
 | 
			
		||||
        println("Address ${address.asString()} at index $index")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testBalance() {
 | 
			
		||||
        val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET)
 | 
			
		||||
        val wallet = Wallet.newNoPersist(descriptor, null, Network.TESTNET)
 | 
			
		||||
 | 
			
		||||
        assert(wallet.getBalance().total() == 0uL)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @Test
 | 
			
		||||
    // fun testSyncedBalance() {
 | 
			
		||||
    //     val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET)
 | 
			
		||||
    //     val wallet = Wallet.newNoPersist(descriptor, null, Network.TESTNET)
 | 
			
		||||
    //     val esploraClient = EsploraClient("https://mempool.space/testnet/api")
 | 
			
		||||
    //     // val esploraClient = EsploraClient("https://blockstream.info/testnet/api")
 | 
			
		||||
    //     val update = esploraClient.scan(wallet, 10uL, 1uL)
 | 
			
		||||
    //     wallet.applyUpdate(update)
 | 
			
		||||
    //     println("Balance: ${wallet.getBalance().total()}")
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -117,15 +117,15 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
 | 
			
		||||
            into("${project.projectDir}/../lib/src/main/jniLibs/")
 | 
			
		||||
 | 
			
		||||
            into("arm64-v8a") {
 | 
			
		||||
                from("${project.projectDir}/../../target/aarch64-linux-android/release-smaller/libbdkffi.so")
 | 
			
		||||
                from("${project.projectDir}/../../bdk-ffi/target/aarch64-linux-android/release-smaller/libbdkffi.so")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            into("x86_64") {
 | 
			
		||||
                from("${project.projectDir}/../../target/x86_64-linux-android/release-smaller/libbdkffi.so")
 | 
			
		||||
                from("${project.projectDir}/../../bdk-ffi/target/x86_64-linux-android/release-smaller/libbdkffi.so")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            into("armeabi-v7a") {
 | 
			
		||||
                from("${project.projectDir}/../../target/armv7-linux-androideabi/release-smaller/libbdkffi.so")
 | 
			
		||||
                from("${project.projectDir}/../../bdk-ffi/target/armv7-linux-androideabi/release-smaller/libbdkffi.so")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            doLast {
 | 
			
		||||
@ -137,6 +137,12 @@ internal class UniFfiAndroidPlugin : Plugin<Project> {
 | 
			
		||||
        val generateAndroidBindings by tasks.register<Exec>("generateAndroidBindings") {
 | 
			
		||||
            dependsOn(moveNativeAndroidLibs)
 | 
			
		||||
 | 
			
		||||
            // val libraryPath = "${project.projectDir}/../../bdk-ffi/target/aarch64-linux-android/release-smaller/libbdkffi.so"
 | 
			
		||||
            // workingDir("${project.projectDir}/../../bdk-ffi")
 | 
			
		||||
            // val cargoArgs: List<String> = listOf("run", "--bin", "uniffi-bindgen", "generate", "--library", libraryPath, "--language", "kotlin", "--out-dir", "../bdk-android/lib/src/main/kotlin", "--no-format")
 | 
			
		||||
 | 
			
		||||
            // The code above worked for uniffi 0.24.3 using the --library flag
 | 
			
		||||
            // The code below works for uniffi 0.23.0
 | 
			
		||||
            workingDir("${project.projectDir}/../../bdk-ffi")
 | 
			
		||||
            val cargoArgs: List<String> = listOf("run", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-android/lib/src/main/kotlin", "--no-format")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										658
									
								
								Cargo.lock → bdk-ffi/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										658
									
								
								Cargo.lock → bdk-ffi/Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,6 +1,6 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "bdk-ffi"
 | 
			
		||||
version = "0.30.0"
 | 
			
		||||
version = "1.0.0-alpha.2"
 | 
			
		||||
authors = ["Steve Myers <steve@notmandatory.org>", "Sudarsan Balaji <sudarsan.balaji@artfuldev.com>"]
 | 
			
		||||
edition = "2018"
 | 
			
		||||
license = "MIT OR Apache-2.0"
 | 
			
		||||
@ -17,12 +17,30 @@ path = "uniffi-bindgen.rs"
 | 
			
		||||
default = ["uniffi/cli"]
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
bdk = { version = "0.28.2", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled", "rpc"] }
 | 
			
		||||
uniffi = { version = "0.23.0" }
 | 
			
		||||
bdk = { version = "1.0.0-alpha.2", features = ["all-keys", "keys-bip39"] }
 | 
			
		||||
 | 
			
		||||
# TODO 22: The bdk_esplora crate uses esplora_client which uses reqwest for async. By default it uses the system
 | 
			
		||||
#          openssl library, which is creating problems for cross-compilation. I'd rather use rustls, but it's hidden
 | 
			
		||||
#          behind a feature flag. We need to look into whether openssl-sys is really required by bdk or if using rustls
 | 
			
		||||
#          would work just as well. This here is a temporary workaround which removes the async feature on the bdk_esplora crate.
 | 
			
		||||
#          See PR #1179 https://github.com/bitcoindevkit/bdk/pull/1179 for the fix in bdk.
 | 
			
		||||
# bdk = { git = "https://github.com/thunderbiscuit/bdk.git", branch = "test-rust-tls", version = "1.0.0-alpha.2", features = ["all-keys", "keys-bip39"] }
 | 
			
		||||
# bdk_esplora = { git = "https://github.com/thunderbiscuit/bdk.git", branch = "test-rust-tls", version = "0.4.0", package = "bdk_esplora", default-features = false, features = ["std", "blocking", "async-https-rustls"] }
 | 
			
		||||
 | 
			
		||||
bdk_esplora = { version = "0.4.0", default-features = false, features = ["std", "blocking"] }
 | 
			
		||||
uniffi = { version = "=0.23.0" }
 | 
			
		||||
 | 
			
		||||
[build-dependencies]
 | 
			
		||||
uniffi = { version = "0.23.0", features = ["build"] }
 | 
			
		||||
uniffi = { version = "=0.23.0", features = ["build"] }
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
uniffi = { version = "0.23.0", features = ["bindgen-tests"] }
 | 
			
		||||
uniffi = { version = "=0.23.0", features = ["bindgen-tests"] }
 | 
			
		||||
assert_matches = "1.5.0"
 | 
			
		||||
 | 
			
		||||
[profile.release-smaller]
 | 
			
		||||
inherits = "release"
 | 
			
		||||
opt-level = 'z'     # Optimize for size.
 | 
			
		||||
lto = true          # Enable Link Time Optimization
 | 
			
		||||
codegen-units = 1   # Reduce number of codegen units to increase optimizations.
 | 
			
		||||
panic = "abort"     # Abort on panic
 | 
			
		||||
strip = "debuginfo" # Partially strip symbols from binary
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,21 @@
 | 
			
		||||
namespace bdk {
 | 
			
		||||
namespace bdk {};
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// bdk crate
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
enum KeychainKind {
 | 
			
		||||
  "External",
 | 
			
		||||
  "Internal",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// bdk crate - wallet module
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
[Error]
 | 
			
		||||
enum BdkError {
 | 
			
		||||
  "InvalidU32Bytes",
 | 
			
		||||
  "Generic",
 | 
			
		||||
  "MissingCachedScripts",
 | 
			
		||||
  "ScriptDoesntHaveAddressForm",
 | 
			
		||||
  "NoRecipients",
 | 
			
		||||
  "NoUtxosSelected",
 | 
			
		||||
  "OutputBelowDustLimit",
 | 
			
		||||
@ -27,25 +35,26 @@ enum BdkError {
 | 
			
		||||
  "SpendingPolicyRequired",
 | 
			
		||||
  "InvalidPolicyPathError",
 | 
			
		||||
  "Signer",
 | 
			
		||||
  "InvalidNetwork",
 | 
			
		||||
  "InvalidProgressValue",
 | 
			
		||||
  "ProgressUpdateError",
 | 
			
		||||
  "InvalidOutpoint",
 | 
			
		||||
  "Descriptor",
 | 
			
		||||
  "Encode",
 | 
			
		||||
  "Miniscript",
 | 
			
		||||
  "MiniscriptPsbt",
 | 
			
		||||
  "Bip32",
 | 
			
		||||
  "Secp256k1",
 | 
			
		||||
  "Json",
 | 
			
		||||
  "Hex",
 | 
			
		||||
  "Psbt",
 | 
			
		||||
  "PsbtParse",
 | 
			
		||||
  "Electrum",
 | 
			
		||||
  "Esplora",
 | 
			
		||||
  "Sled",
 | 
			
		||||
  "Rusqlite",
 | 
			
		||||
  "Rpc",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Balance {
 | 
			
		||||
  u64 immature();
 | 
			
		||||
 | 
			
		||||
  u64 trusted_pending();
 | 
			
		||||
 | 
			
		||||
  u64 untrusted_pending();
 | 
			
		||||
 | 
			
		||||
  u64 confirmed();
 | 
			
		||||
 | 
			
		||||
  u64 trusted_spendable();
 | 
			
		||||
 | 
			
		||||
  u64 total();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary AddressInfo {
 | 
			
		||||
@ -59,9 +68,28 @@ interface AddressIndex {
 | 
			
		||||
  New();
 | 
			
		||||
  LastUnused();
 | 
			
		||||
  Peek(u32 index);
 | 
			
		||||
  Reset(u32 index);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Wallet {
 | 
			
		||||
  [Name=new_no_persist, Throws=BdkError]
 | 
			
		||||
  constructor(Descriptor descriptor, Descriptor? change_descriptor, Network network);
 | 
			
		||||
 | 
			
		||||
  AddressInfo get_address(AddressIndex address_index);
 | 
			
		||||
 | 
			
		||||
  Network network();
 | 
			
		||||
 | 
			
		||||
  Balance get_balance();
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  void apply_update(Update update);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Update {};
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// bdk crate - bitcoin reexports
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
enum Network {
 | 
			
		||||
  "Bitcoin",
 | 
			
		||||
  "Testnet",
 | 
			
		||||
@ -69,45 +97,6 @@ enum Network {
 | 
			
		||||
  "Regtest",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary SledDbConfiguration {
 | 
			
		||||
  string path;
 | 
			
		||||
  string tree_name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary SqliteDbConfiguration {
 | 
			
		||||
  string path;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary Balance {
 | 
			
		||||
  u64 immature;
 | 
			
		||||
  u64 trusted_pending;
 | 
			
		||||
  u64 untrusted_pending;
 | 
			
		||||
  u64 confirmed;
 | 
			
		||||
  u64 spendable;
 | 
			
		||||
  u64 total;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
[Enum]
 | 
			
		||||
interface DatabaseConfig {
 | 
			
		||||
  Memory();
 | 
			
		||||
  Sled(SledDbConfiguration config);
 | 
			
		||||
  Sqlite(SqliteDbConfiguration config);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary TransactionDetails {
 | 
			
		||||
  Transaction? transaction;
 | 
			
		||||
  u64? fee;
 | 
			
		||||
  u64 received;
 | 
			
		||||
  u64 sent;
 | 
			
		||||
  string txid;
 | 
			
		||||
  BlockTime? confirmation_time;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary BlockTime {
 | 
			
		||||
  u32 height;
 | 
			
		||||
  u64 timestamp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum WordCount {
 | 
			
		||||
  "Words12",
 | 
			
		||||
  "Words15",
 | 
			
		||||
@ -116,260 +105,20 @@ enum WordCount {
 | 
			
		||||
  "Words24",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary ElectrumConfig {
 | 
			
		||||
  string url;
 | 
			
		||||
  string? socks5;
 | 
			
		||||
  u8 retry;
 | 
			
		||||
  u8? timeout;
 | 
			
		||||
  u64 stop_gap;
 | 
			
		||||
  boolean validate_domain;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary EsploraConfig {
 | 
			
		||||
  string base_url;
 | 
			
		||||
  string? proxy;
 | 
			
		||||
  u8? concurrency;
 | 
			
		||||
  u64 stop_gap;
 | 
			
		||||
  u64? timeout;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
[Enum]
 | 
			
		||||
interface Auth {
 | 
			
		||||
  None();
 | 
			
		||||
  UserPass(string username, string password);
 | 
			
		||||
  Cookie(string file);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary RpcSyncParams {
 | 
			
		||||
    u64 start_script_count;
 | 
			
		||||
    u64 start_time;
 | 
			
		||||
    boolean force_start_time;
 | 
			
		||||
    u64 poll_rate_sec;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary RpcConfig {
 | 
			
		||||
    string url;
 | 
			
		||||
    Auth auth;
 | 
			
		||||
    Network network;
 | 
			
		||||
    string wallet_name;
 | 
			
		||||
    RpcSyncParams? sync_params;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
[Enum]
 | 
			
		||||
interface BlockchainConfig {
 | 
			
		||||
  Electrum(ElectrumConfig config);
 | 
			
		||||
  Esplora(EsploraConfig config);
 | 
			
		||||
  Rpc(RpcConfig config);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Blockchain {
 | 
			
		||||
interface Address {
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  constructor(BlockchainConfig config);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  void broadcast([ByRef] Transaction transaction);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  FeeRate estimate_fee(u64 target);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  u32 get_height();
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  string get_block_hash(u32 height);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
callback interface Progress {
 | 
			
		||||
  void update(f32 progress, string? message);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary OutPoint {
 | 
			
		||||
  string txid;
 | 
			
		||||
  u32 vout;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary TxIn {
 | 
			
		||||
  OutPoint previous_output;
 | 
			
		||||
  Script script_sig;
 | 
			
		||||
  u32 sequence;
 | 
			
		||||
  sequence<sequence<u8>> witness;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary TxOut {
 | 
			
		||||
  u64 value;
 | 
			
		||||
  Script script_pubkey;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum KeychainKind {
 | 
			
		||||
  "External",
 | 
			
		||||
  "Internal",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary LocalUtxo {
 | 
			
		||||
  OutPoint outpoint;
 | 
			
		||||
  TxOut txout;
 | 
			
		||||
  KeychainKind keychain;
 | 
			
		||||
  boolean is_spent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary ScriptAmount {
 | 
			
		||||
  Script script;
 | 
			
		||||
  u64 amount;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Wallet {
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  constructor(Descriptor descriptor, Descriptor? change_descriptor, Network network, DatabaseConfig database_config);
 | 
			
		||||
  constructor(string address, Network network);
 | 
			
		||||
 | 
			
		||||
  Network network();
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  AddressInfo get_address(AddressIndex address_index);
 | 
			
		||||
  string to_qr_uri();
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  AddressInfo get_internal_address(AddressIndex address_index);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  boolean is_mine(Script script);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  sequence<LocalUtxo> list_unspent();
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  sequence<TransactionDetails> list_transactions(boolean include_raw);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  Balance get_balance();
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  boolean sign([ByRef] PartiallySignedTransaction psbt, SignOptions? sign_options);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  void sync([ByRef] Blockchain blockchain, Progress? progress);
 | 
			
		||||
  string as_string();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface FeeRate {
 | 
			
		||||
  [Name=from_sat_per_vb]
 | 
			
		||||
  constructor(float sat_per_vb);
 | 
			
		||||
 | 
			
		||||
  float as_sat_per_vb();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary SignOptions {
 | 
			
		||||
  boolean trust_witness_utxo;
 | 
			
		||||
  u32? assume_height;
 | 
			
		||||
  boolean allow_all_sighashes;
 | 
			
		||||
  boolean remove_partial_sigs;
 | 
			
		||||
  boolean try_finalize;
 | 
			
		||||
  boolean sign_with_tap_internal_key;
 | 
			
		||||
  boolean allow_grinding;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Transaction {
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  constructor(sequence<u8> transaction_bytes);
 | 
			
		||||
 | 
			
		||||
  string txid();
 | 
			
		||||
 | 
			
		||||
  u64 weight();
 | 
			
		||||
 | 
			
		||||
  u64 size();
 | 
			
		||||
 | 
			
		||||
  u64 vsize();
 | 
			
		||||
 | 
			
		||||
  sequence<u8> serialize();
 | 
			
		||||
 | 
			
		||||
  boolean is_coin_base();
 | 
			
		||||
 | 
			
		||||
  boolean is_explicitly_rbf();
 | 
			
		||||
 | 
			
		||||
  boolean is_lock_time_enabled();
 | 
			
		||||
 | 
			
		||||
  i32 version();
 | 
			
		||||
 | 
			
		||||
  u32 lock_time();
 | 
			
		||||
 | 
			
		||||
  sequence<TxIn> input();
 | 
			
		||||
 | 
			
		||||
  sequence<TxOut> output();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface PartiallySignedTransaction {
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  constructor(string psbt_base64);
 | 
			
		||||
 | 
			
		||||
  string serialize();
 | 
			
		||||
 | 
			
		||||
  string txid();
 | 
			
		||||
 | 
			
		||||
  Transaction extract_tx();
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  PartiallySignedTransaction combine(PartiallySignedTransaction other);
 | 
			
		||||
 | 
			
		||||
  u64? fee_amount();
 | 
			
		||||
 | 
			
		||||
  FeeRate? fee_rate();
 | 
			
		||||
 | 
			
		||||
  string json_serialize();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dictionary TxBuilderResult {
 | 
			
		||||
  PartiallySignedTransaction psbt;
 | 
			
		||||
  TransactionDetails transaction_details;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface TxBuilder {
 | 
			
		||||
  constructor();
 | 
			
		||||
 | 
			
		||||
  TxBuilder add_recipient(Script script, u64 amount);
 | 
			
		||||
 | 
			
		||||
  TxBuilder add_unspendable(OutPoint unspendable);
 | 
			
		||||
 | 
			
		||||
  TxBuilder add_utxo(OutPoint outpoint);
 | 
			
		||||
 | 
			
		||||
  TxBuilder add_utxos(sequence<OutPoint> outpoints);
 | 
			
		||||
 | 
			
		||||
  TxBuilder do_not_spend_change();
 | 
			
		||||
 | 
			
		||||
  TxBuilder manually_selected_only();
 | 
			
		||||
 | 
			
		||||
  TxBuilder only_spend_change();
 | 
			
		||||
 | 
			
		||||
  TxBuilder unspendable(sequence<OutPoint> unspendable);
 | 
			
		||||
 | 
			
		||||
  TxBuilder fee_rate(float sat_per_vbyte);
 | 
			
		||||
 | 
			
		||||
  TxBuilder fee_absolute(u64 fee_amount);
 | 
			
		||||
 | 
			
		||||
  TxBuilder drain_wallet();
 | 
			
		||||
 | 
			
		||||
  TxBuilder drain_to(Script script);
 | 
			
		||||
 | 
			
		||||
  TxBuilder enable_rbf();
 | 
			
		||||
 | 
			
		||||
  TxBuilder enable_rbf_with_sequence(u32 nsequence);
 | 
			
		||||
 | 
			
		||||
  TxBuilder add_data(sequence<u8> data);
 | 
			
		||||
 | 
			
		||||
  TxBuilder set_recipients(sequence<ScriptAmount> recipients);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  TxBuilderResult finish([ByRef] Wallet wallet);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface BumpFeeTxBuilder {
 | 
			
		||||
  constructor(string txid, float new_fee_rate);
 | 
			
		||||
 | 
			
		||||
  BumpFeeTxBuilder allow_shrinking(string address);
 | 
			
		||||
 | 
			
		||||
  BumpFeeTxBuilder enable_rbf();
 | 
			
		||||
 | 
			
		||||
  BumpFeeTxBuilder enable_rbf_with_sequence(u32 nsequence);
 | 
			
		||||
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  PartiallySignedTransaction finish([ByRef] Wallet wallet);
 | 
			
		||||
};
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// bdk crate - descriptor module
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
interface Mnemonic {
 | 
			
		||||
  constructor(WordCount word_count);
 | 
			
		||||
@ -453,55 +202,10 @@ interface Descriptor {
 | 
			
		||||
  string as_string_private();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Address {
 | 
			
		||||
  [Throws=BdkError]
 | 
			
		||||
  constructor(string address);
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// bdk_esplora crate
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
  [Name=from_script, Throws=BdkError]
 | 
			
		||||
  constructor(Script script, Network network);
 | 
			
		||||
 | 
			
		||||
  Payload payload();
 | 
			
		||||
 | 
			
		||||
  Network network();
 | 
			
		||||
 | 
			
		||||
  Script script_pubkey();
 | 
			
		||||
 | 
			
		||||
  string to_qr_uri();
 | 
			
		||||
 | 
			
		||||
  string as_string();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
[Enum]
 | 
			
		||||
interface Payload {
 | 
			
		||||
  PubkeyHash(sequence<u8> pubkey_hash);
 | 
			
		||||
 | 
			
		||||
  ScriptHash(sequence<u8> script_hash);
 | 
			
		||||
 | 
			
		||||
  WitnessProgram(WitnessVersion version, sequence<u8> program);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum WitnessVersion {
 | 
			
		||||
  "V0",
 | 
			
		||||
  "V1",
 | 
			
		||||
  "V2",
 | 
			
		||||
  "V3",
 | 
			
		||||
  "V4",
 | 
			
		||||
  "V5",
 | 
			
		||||
  "V6",
 | 
			
		||||
  "V7",
 | 
			
		||||
  "V8",
 | 
			
		||||
  "V9",
 | 
			
		||||
  "V10",
 | 
			
		||||
  "V11",
 | 
			
		||||
  "V12",
 | 
			
		||||
  "V13",
 | 
			
		||||
  "V14",
 | 
			
		||||
  "V15",
 | 
			
		||||
  "V16"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Script {
 | 
			
		||||
  constructor(sequence<u8> raw_output_script);
 | 
			
		||||
 | 
			
		||||
  sequence<u8> to_bytes();
 | 
			
		||||
interface EsploraClient {
 | 
			
		||||
  constructor(string url);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,201 +0,0 @@
 | 
			
		||||
// use crate::BlockchainConfig;
 | 
			
		||||
use crate::{BdkError, Transaction};
 | 
			
		||||
use bdk::bitcoin::Network;
 | 
			
		||||
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
 | 
			
		||||
use bdk::blockchain::rpc::Auth as BdkAuth;
 | 
			
		||||
use bdk::blockchain::rpc::RpcSyncParams as BdkRpcSyncParams;
 | 
			
		||||
use bdk::blockchain::Blockchain as BdkBlockchain;
 | 
			
		||||
use bdk::blockchain::GetBlockHash;
 | 
			
		||||
use bdk::blockchain::GetHeight;
 | 
			
		||||
use bdk::blockchain::{
 | 
			
		||||
    electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig,
 | 
			
		||||
    rpc::RpcConfig as BdkRpcConfig, ConfigurableBlockchain,
 | 
			
		||||
};
 | 
			
		||||
use bdk::FeeRate;
 | 
			
		||||
use std::convert::{From, TryFrom};
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
use std::sync::{Arc, Mutex, MutexGuard};
 | 
			
		||||
 | 
			
		||||
pub(crate) struct Blockchain {
 | 
			
		||||
    inner_mutex: Mutex<AnyBlockchain>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Blockchain {
 | 
			
		||||
    pub(crate) fn new(blockchain_config: BlockchainConfig) -> Result<Self, BdkError> {
 | 
			
		||||
        let any_blockchain_config = match blockchain_config {
 | 
			
		||||
            BlockchainConfig::Electrum { config } => {
 | 
			
		||||
                AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig {
 | 
			
		||||
                    retry: config.retry,
 | 
			
		||||
                    socks5: config.socks5,
 | 
			
		||||
                    timeout: config.timeout,
 | 
			
		||||
                    url: config.url,
 | 
			
		||||
                    stop_gap: usize::try_from(config.stop_gap).unwrap(),
 | 
			
		||||
                    validate_domain: config.validate_domain,
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
            BlockchainConfig::Esplora { config } => {
 | 
			
		||||
                AnyBlockchainConfig::Esplora(EsploraBlockchainConfig {
 | 
			
		||||
                    base_url: config.base_url,
 | 
			
		||||
                    proxy: config.proxy,
 | 
			
		||||
                    concurrency: config.concurrency,
 | 
			
		||||
                    stop_gap: usize::try_from(config.stop_gap).unwrap(),
 | 
			
		||||
                    timeout: config.timeout,
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
            BlockchainConfig::Rpc { config } => AnyBlockchainConfig::Rpc(BdkRpcConfig {
 | 
			
		||||
                url: config.url,
 | 
			
		||||
                auth: config.auth.into(),
 | 
			
		||||
                network: config.network,
 | 
			
		||||
                wallet_name: config.wallet_name,
 | 
			
		||||
                sync_params: config.sync_params.map(|p| p.into()),
 | 
			
		||||
            }),
 | 
			
		||||
        };
 | 
			
		||||
        let blockchain = AnyBlockchain::from_config(&any_blockchain_config)?;
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            inner_mutex: Mutex::new(blockchain),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn get_blockchain(&self) -> MutexGuard<AnyBlockchain> {
 | 
			
		||||
        self.inner_mutex.lock().expect("blockchain")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn broadcast(&self, transaction: &Transaction) -> Result<(), BdkError> {
 | 
			
		||||
        let tx = &transaction.inner;
 | 
			
		||||
        self.get_blockchain().broadcast(tx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn estimate_fee(&self, target: u64) -> Result<Arc<FeeRate>, BdkError> {
 | 
			
		||||
        let result: Result<FeeRate, bdk::Error> =
 | 
			
		||||
            self.get_blockchain().estimate_fee(target as usize);
 | 
			
		||||
        result.map(Arc::new)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn get_height(&self) -> Result<u32, BdkError> {
 | 
			
		||||
        self.get_blockchain().get_height()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn get_block_hash(&self, height: u32) -> Result<String, BdkError> {
 | 
			
		||||
        self.get_blockchain()
 | 
			
		||||
            .get_block_hash(u64::from(height))
 | 
			
		||||
            .map(|hash| hash.to_string())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Configuration for an ElectrumBlockchain
 | 
			
		||||
pub struct ElectrumConfig {
 | 
			
		||||
    /// URL of the Electrum server (such as ElectrumX, Esplora, BWT) may start with ssl:// or tcp:// and include a port
 | 
			
		||||
    /// e.g. ssl://electrum.blockstream.info:60002
 | 
			
		||||
    pub url: String,
 | 
			
		||||
    /// URL of the socks5 proxy server or a Tor service
 | 
			
		||||
    pub socks5: Option<String>,
 | 
			
		||||
    /// Request retry count
 | 
			
		||||
    pub retry: u8,
 | 
			
		||||
    /// Request timeout (seconds)
 | 
			
		||||
    pub timeout: Option<u8>,
 | 
			
		||||
    /// Stop searching addresses for transactions after finding an unused gap of this length
 | 
			
		||||
    pub stop_gap: u64,
 | 
			
		||||
    /// Validate the domain when using SSL
 | 
			
		||||
    pub validate_domain: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Configuration for an EsploraBlockchain
 | 
			
		||||
pub struct EsploraConfig {
 | 
			
		||||
    /// Base URL of the esplora service
 | 
			
		||||
    /// e.g. https://blockstream.info/api/
 | 
			
		||||
    pub base_url: String,
 | 
			
		||||
    /// Optional URL of the proxy to use to make requests to the Esplora server
 | 
			
		||||
    /// The string should be formatted as: <protocol>://<user>:<password>@host:<port>.
 | 
			
		||||
    /// Note that the format of this value and the supported protocols change slightly between the
 | 
			
		||||
    /// sync version of esplora (using ureq) and the async version (using reqwest). For more
 | 
			
		||||
    /// details check with the documentation of the two crates. Both of them are compiled with
 | 
			
		||||
    /// the socks feature enabled.
 | 
			
		||||
    /// The proxy is ignored when targeting wasm32.
 | 
			
		||||
    pub proxy: Option<String>,
 | 
			
		||||
    /// Number of parallel requests sent to the esplora service (default: 4)
 | 
			
		||||
    pub concurrency: Option<u8>,
 | 
			
		||||
    /// Stop searching addresses for transactions after finding an unused gap of this length.
 | 
			
		||||
    pub stop_gap: u64,
 | 
			
		||||
    /// Socket timeout.
 | 
			
		||||
    pub timeout: Option<u64>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum Auth {
 | 
			
		||||
    /// No authentication
 | 
			
		||||
    None,
 | 
			
		||||
    /// Authentication with username and password, usually [Auth::Cookie] should be preferred
 | 
			
		||||
    UserPass {
 | 
			
		||||
        /// Username
 | 
			
		||||
        username: String,
 | 
			
		||||
        /// Password
 | 
			
		||||
        password: String,
 | 
			
		||||
    },
 | 
			
		||||
    /// Authentication with a cookie file
 | 
			
		||||
    Cookie {
 | 
			
		||||
        /// Cookie file
 | 
			
		||||
        file: String,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Auth> for BdkAuth {
 | 
			
		||||
    fn from(auth: Auth) -> Self {
 | 
			
		||||
        match auth {
 | 
			
		||||
            Auth::None => BdkAuth::None,
 | 
			
		||||
            Auth::UserPass { username, password } => BdkAuth::UserPass { username, password },
 | 
			
		||||
            Auth::Cookie { file } => BdkAuth::Cookie {
 | 
			
		||||
                file: PathBuf::from(file),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Sync parameters for Bitcoin Core RPC.
 | 
			
		||||
///
 | 
			
		||||
/// In general, BDK tries to sync `scriptPubKey`s cached in `Database` with
 | 
			
		||||
/// `scriptPubKey`s imported in the Bitcoin Core Wallet. These parameters are used for determining
 | 
			
		||||
/// how the `importdescriptors` RPC calls are to be made.
 | 
			
		||||
pub struct RpcSyncParams {
 | 
			
		||||
    /// The minimum number of scripts to scan for on initial sync.
 | 
			
		||||
    pub start_script_count: u64,
 | 
			
		||||
    /// Time in unix seconds in which initial sync will start scanning from (0 to start from genesis).
 | 
			
		||||
    pub start_time: u64,
 | 
			
		||||
    /// Forces every sync to use `start_time` as import timestamp.
 | 
			
		||||
    pub force_start_time: bool,
 | 
			
		||||
    /// RPC poll rate (in seconds) to get state updates.
 | 
			
		||||
    pub poll_rate_sec: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<RpcSyncParams> for BdkRpcSyncParams {
 | 
			
		||||
    fn from(params: RpcSyncParams) -> Self {
 | 
			
		||||
        BdkRpcSyncParams {
 | 
			
		||||
            start_script_count: params.start_script_count as usize,
 | 
			
		||||
            start_time: params.start_time,
 | 
			
		||||
            force_start_time: params.force_start_time,
 | 
			
		||||
            poll_rate_sec: params.poll_rate_sec,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// RpcBlockchain configuration options
 | 
			
		||||
pub struct RpcConfig {
 | 
			
		||||
    /// The bitcoin node url
 | 
			
		||||
    pub url: String,
 | 
			
		||||
    /// The bitcoin node authentication mechanism
 | 
			
		||||
    pub auth: Auth,
 | 
			
		||||
    /// The network we are using (it will be checked the bitcoin node network matches this)
 | 
			
		||||
    pub network: Network,
 | 
			
		||||
    /// The wallet name in the bitcoin node, consider using [crate::wallet::wallet_name_from_descriptor] for this
 | 
			
		||||
    pub wallet_name: String,
 | 
			
		||||
    /// Sync parameters
 | 
			
		||||
    pub sync_params: Option<RpcSyncParams>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Type that can contain any of the blockchain configurations defined by the library.
 | 
			
		||||
pub enum BlockchainConfig {
 | 
			
		||||
    /// Electrum client
 | 
			
		||||
    Electrum { config: ElectrumConfig },
 | 
			
		||||
    /// Esplora client
 | 
			
		||||
    Esplora { config: EsploraConfig },
 | 
			
		||||
    /// Bitcoin Core RPC client
 | 
			
		||||
    Rpc { config: RpcConfig },
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +0,0 @@
 | 
			
		||||
use bdk::database::any::{SledDbConfiguration, SqliteDbConfiguration};
 | 
			
		||||
 | 
			
		||||
/// Type that can contain any of the database configurations defined by the library
 | 
			
		||||
/// This allows storing a single configuration that can be loaded into an AnyDatabaseConfig
 | 
			
		||||
/// instance. Wallets that plan to offer users the ability to switch blockchain backend at runtime
 | 
			
		||||
/// will find this particularly useful.
 | 
			
		||||
pub enum DatabaseConfig {
 | 
			
		||||
    /// Memory database has no config
 | 
			
		||||
    Memory,
 | 
			
		||||
    /// Simple key-value embedded database based on sled
 | 
			
		||||
    Sled { config: SledDbConfiguration },
 | 
			
		||||
    /// Sqlite embedded database using rusqlite
 | 
			
		||||
    Sqlite { config: SqliteDbConfiguration },
 | 
			
		||||
}
 | 
			
		||||
@ -1,29 +1,32 @@
 | 
			
		||||
use crate::{BdkError, DescriptorPublicKey, DescriptorSecretKey};
 | 
			
		||||
use bdk::bitcoin::secp256k1::Secp256k1;
 | 
			
		||||
use bdk::bitcoin::util::bip32::Fingerprint;
 | 
			
		||||
use bdk::bitcoin::Network;
 | 
			
		||||
use bdk::descriptor::{ExtendedDescriptor, IntoWalletDescriptor, KeyMap};
 | 
			
		||||
use bdk::keys::{
 | 
			
		||||
    DescriptorPublicKey as BdkDescriptorPublicKey, DescriptorSecretKey as BdkDescriptorSecretKey,
 | 
			
		||||
};
 | 
			
		||||
use bdk::bitcoin::bip32::Fingerprint;
 | 
			
		||||
use bdk::bitcoin::key::Secp256k1;
 | 
			
		||||
use bdk::descriptor::{ExtendedDescriptor, IntoWalletDescriptor};
 | 
			
		||||
use bdk::keys::DescriptorPublicKey as BdkDescriptorPublicKey;
 | 
			
		||||
use bdk::keys::{DescriptorSecretKey as BdkDescriptorSecretKey, KeyMap};
 | 
			
		||||
use bdk::template::{
 | 
			
		||||
    Bip44, Bip44Public, Bip49, Bip49Public, Bip84, Bip84Public, Bip86, Bip86Public,
 | 
			
		||||
    DescriptorTemplate,
 | 
			
		||||
};
 | 
			
		||||
use bdk::Error as BdkError;
 | 
			
		||||
use bdk::KeychainKind;
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use crate::keys::DescriptorPublicKey;
 | 
			
		||||
use crate::keys::DescriptorSecretKey;
 | 
			
		||||
use crate::Network;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub(crate) struct Descriptor {
 | 
			
		||||
    pub(crate) extended_descriptor: ExtendedDescriptor,
 | 
			
		||||
    pub(crate) key_map: KeyMap,
 | 
			
		||||
pub struct Descriptor {
 | 
			
		||||
    pub extended_descriptor: ExtendedDescriptor,
 | 
			
		||||
    pub key_map: KeyMap,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Descriptor {
 | 
			
		||||
    pub(crate) fn new(descriptor: String, network: Network) -> Result<Self, BdkError> {
 | 
			
		||||
        let secp = Secp256k1::new();
 | 
			
		||||
        let (extended_descriptor, key_map) = descriptor.into_wallet_descriptor(&secp, network)?;
 | 
			
		||||
        let (extended_descriptor, key_map) =
 | 
			
		||||
            descriptor.into_wallet_descriptor(&secp, network.into())?;
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            extended_descriptor,
 | 
			
		||||
            key_map,
 | 
			
		||||
@ -38,16 +41,20 @@ impl Descriptor {
 | 
			
		||||
        let derivable_key = &secret_key.inner;
 | 
			
		||||
 | 
			
		||||
        match derivable_key {
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
 | 
			
		||||
                let derivable_key = descriptor_x_key.xkey;
 | 
			
		||||
                let (extended_descriptor, key_map, _) =
 | 
			
		||||
                    Bip44(derivable_key, keychain_kind).build(network).unwrap();
 | 
			
		||||
                let (extended_descriptor, key_map, _) = Bip44(derivable_key, keychain_kind)
 | 
			
		||||
                    .build(network.into())
 | 
			
		||||
                    .unwrap();
 | 
			
		||||
                Self {
 | 
			
		||||
                    extended_descriptor,
 | 
			
		||||
                    key_map,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorSecretKey::MultiXPrv(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -63,11 +70,14 @@ impl Descriptor {
 | 
			
		||||
        let derivable_key = &public_key.inner;
 | 
			
		||||
 | 
			
		||||
        match derivable_key {
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
 | 
			
		||||
                let derivable_key = descriptor_x_key.xkey;
 | 
			
		||||
                let (extended_descriptor, key_map, _) =
 | 
			
		||||
                    Bip44Public(derivable_key, fingerprint, keychain_kind)
 | 
			
		||||
                        .build(network)
 | 
			
		||||
                        .build(network.into())
 | 
			
		||||
                        .unwrap();
 | 
			
		||||
 | 
			
		||||
                Self {
 | 
			
		||||
@ -75,7 +85,7 @@ impl Descriptor {
 | 
			
		||||
                    key_map,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorPublicKey::MultiXPub(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -89,16 +99,20 @@ impl Descriptor {
 | 
			
		||||
        let derivable_key = &secret_key.inner;
 | 
			
		||||
 | 
			
		||||
        match derivable_key {
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
 | 
			
		||||
                let derivable_key = descriptor_x_key.xkey;
 | 
			
		||||
                let (extended_descriptor, key_map, _) =
 | 
			
		||||
                    Bip49(derivable_key, keychain_kind).build(network).unwrap();
 | 
			
		||||
                let (extended_descriptor, key_map, _) = Bip49(derivable_key, keychain_kind)
 | 
			
		||||
                    .build(network.into())
 | 
			
		||||
                    .unwrap();
 | 
			
		||||
                Self {
 | 
			
		||||
                    extended_descriptor,
 | 
			
		||||
                    key_map,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorSecretKey::MultiXPrv(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -114,11 +128,14 @@ impl Descriptor {
 | 
			
		||||
        let derivable_key = &public_key.inner;
 | 
			
		||||
 | 
			
		||||
        match derivable_key {
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
 | 
			
		||||
                let derivable_key = descriptor_x_key.xkey;
 | 
			
		||||
                let (extended_descriptor, key_map, _) =
 | 
			
		||||
                    Bip49Public(derivable_key, fingerprint, keychain_kind)
 | 
			
		||||
                        .build(network)
 | 
			
		||||
                        .build(network.into())
 | 
			
		||||
                        .unwrap();
 | 
			
		||||
 | 
			
		||||
                Self {
 | 
			
		||||
@ -126,7 +143,7 @@ impl Descriptor {
 | 
			
		||||
                    key_map,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorPublicKey::MultiXPub(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -140,16 +157,20 @@ impl Descriptor {
 | 
			
		||||
        let derivable_key = &secret_key.inner;
 | 
			
		||||
 | 
			
		||||
        match derivable_key {
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
 | 
			
		||||
                let derivable_key = descriptor_x_key.xkey;
 | 
			
		||||
                let (extended_descriptor, key_map, _) =
 | 
			
		||||
                    Bip84(derivable_key, keychain_kind).build(network).unwrap();
 | 
			
		||||
                let (extended_descriptor, key_map, _) = Bip84(derivable_key, keychain_kind)
 | 
			
		||||
                    .build(network.into())
 | 
			
		||||
                    .unwrap();
 | 
			
		||||
                Self {
 | 
			
		||||
                    extended_descriptor,
 | 
			
		||||
                    key_map,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorSecretKey::MultiXPrv(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -165,11 +186,14 @@ impl Descriptor {
 | 
			
		||||
        let derivable_key = &public_key.inner;
 | 
			
		||||
 | 
			
		||||
        match derivable_key {
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
 | 
			
		||||
                let derivable_key = descriptor_x_key.xkey;
 | 
			
		||||
                let (extended_descriptor, key_map, _) =
 | 
			
		||||
                    Bip84Public(derivable_key, fingerprint, keychain_kind)
 | 
			
		||||
                        .build(network)
 | 
			
		||||
                        .build(network.into())
 | 
			
		||||
                        .unwrap();
 | 
			
		||||
 | 
			
		||||
                Self {
 | 
			
		||||
@ -177,7 +201,7 @@ impl Descriptor {
 | 
			
		||||
                    key_map,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorPublicKey::MultiXPub(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -191,16 +215,20 @@ impl Descriptor {
 | 
			
		||||
        let derivable_key = &secret_key.inner;
 | 
			
		||||
 | 
			
		||||
        match derivable_key {
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
 | 
			
		||||
                let derivable_key = descriptor_x_key.xkey;
 | 
			
		||||
                let (extended_descriptor, key_map, _) =
 | 
			
		||||
                    Bip86(derivable_key, keychain_kind).build(network).unwrap();
 | 
			
		||||
                let (extended_descriptor, key_map, _) = Bip86(derivable_key, keychain_kind)
 | 
			
		||||
                    .build(network.into())
 | 
			
		||||
                    .unwrap();
 | 
			
		||||
                Self {
 | 
			
		||||
                    extended_descriptor,
 | 
			
		||||
                    key_map,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorSecretKey::MultiXPrv(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -216,11 +244,14 @@ impl Descriptor {
 | 
			
		||||
        let derivable_key = &public_key.inner;
 | 
			
		||||
 | 
			
		||||
        match derivable_key {
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
 | 
			
		||||
                let derivable_key = descriptor_x_key.xkey;
 | 
			
		||||
                let (extended_descriptor, key_map, _) =
 | 
			
		||||
                    Bip86Public(derivable_key, fingerprint, keychain_kind)
 | 
			
		||||
                        .build(network)
 | 
			
		||||
                        .build(network.into())
 | 
			
		||||
                        .unwrap();
 | 
			
		||||
 | 
			
		||||
                Self {
 | 
			
		||||
@ -228,7 +259,7 @@ impl Descriptor {
 | 
			
		||||
                    key_map,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorPublicKey::MultiXPub(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -245,12 +276,11 @@ impl Descriptor {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
 | 
			
		||||
// These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
 | 
			
		||||
// crate.
 | 
			
		||||
// // The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
 | 
			
		||||
// // These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
 | 
			
		||||
// // crate.
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use crate::database::DatabaseConfig;
 | 
			
		||||
    use crate::*;
 | 
			
		||||
    use assert_matches::assert_matches;
 | 
			
		||||
    use bdk::descriptor::DescriptorError::Key;
 | 
			
		||||
@ -385,26 +415,4 @@ mod test {
 | 
			
		||||
            bdk::Error::Descriptor(Key(InvalidNetwork))
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_wallet_from_descriptor() {
 | 
			
		||||
        let descriptor1 = Descriptor::new("wpkh(tprv8hwWMmPE4BVNxGdVt3HhEERZhondQvodUY7Ajyseyhudr4WabJqWKWLr4Wi2r26CDaNCQhhxEftEaNzz7dPGhWuKFU4VULesmhEfZYyBXdE/0/*)".to_string(), Network::Testnet).unwrap();
 | 
			
		||||
        let wallet1 = Wallet::new(
 | 
			
		||||
            Arc::new(Descriptor::new("wpkh(tprv8hwWMmPE4BVNxGdVt3HhEERZhondQvodUY7Ajyseyhudr4WabJqWKWLr4Wi2r26CDaNCQhhxEftEaNzz7dPGhWuKFU4VULesmhEfZYyBXdE/0/*)".to_string(), Network::Testnet).unwrap()),
 | 
			
		||||
            None,
 | 
			
		||||
            Network::Testnet,
 | 
			
		||||
            DatabaseConfig::Memory
 | 
			
		||||
        );
 | 
			
		||||
        let wallet2 = Wallet::new(
 | 
			
		||||
            Arc::new(descriptor1),
 | 
			
		||||
            None,
 | 
			
		||||
            Network::Bitcoin,
 | 
			
		||||
            DatabaseConfig::Memory,
 | 
			
		||||
        );
 | 
			
		||||
        // Creating a wallet using a Descriptor with an extended key that doesn't match the network provided in the wallet constructor will throw and InvalidNetwork Error
 | 
			
		||||
        assert!(wallet1.is_ok());
 | 
			
		||||
        assert_matches!(
 | 
			
		||||
            wallet2.unwrap_err(),
 | 
			
		||||
            bdk::Error::Descriptor(Key(InvalidNetwork))
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								bdk-ffi/src/esplora.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								bdk-ffi/src/esplora.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
use bdk_esplora::esplora_client::{BlockingClient, Builder};
 | 
			
		||||
 | 
			
		||||
pub struct EsploraClient(BlockingClient);
 | 
			
		||||
 | 
			
		||||
impl EsploraClient {
 | 
			
		||||
    pub fn new(url: String) -> Self {
 | 
			
		||||
        let client = Builder::new(url.as_str()).build_blocking().unwrap();
 | 
			
		||||
        Self(client)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // pub fn scan();
 | 
			
		||||
 | 
			
		||||
    // pub fn sync();
 | 
			
		||||
 | 
			
		||||
    // pub fn broadcast();
 | 
			
		||||
 | 
			
		||||
    // pub fn estimate_fee();
 | 
			
		||||
}
 | 
			
		||||
@ -1,21 +1,24 @@
 | 
			
		||||
use crate::BdkError;
 | 
			
		||||
 | 
			
		||||
use bdk::bitcoin::secp256k1::Secp256k1;
 | 
			
		||||
use bdk::bitcoin::util::bip32::DerivationPath as BdkDerivationPath;
 | 
			
		||||
use bdk::bitcoin::Network;
 | 
			
		||||
use bdk::descriptor::DescriptorXKey;
 | 
			
		||||
use bdk::keys::bip39::{Language, Mnemonic as BdkMnemonic, WordCount};
 | 
			
		||||
use bdk::bitcoin::bip32::DerivationPath as BdkDerivationPath;
 | 
			
		||||
use bdk::bitcoin::key::Secp256k1;
 | 
			
		||||
use bdk::bitcoin::secp256k1::rand;
 | 
			
		||||
use bdk::bitcoin::secp256k1::rand::Rng;
 | 
			
		||||
use bdk::keys::bip39::WordCount;
 | 
			
		||||
use bdk::keys::bip39::{Language, Mnemonic as BdkMnemonic};
 | 
			
		||||
use bdk::keys::{
 | 
			
		||||
    DerivableKey, DescriptorPublicKey as BdkDescriptorPublicKey,
 | 
			
		||||
    DescriptorSecretKey as BdkDescriptorSecretKey, ExtendedKey, GeneratableKey, GeneratedKey,
 | 
			
		||||
};
 | 
			
		||||
use bdk::miniscript::descriptor::{DescriptorXKey, Wildcard};
 | 
			
		||||
use bdk::miniscript::BareCtx;
 | 
			
		||||
use bdk::Error as BdkError;
 | 
			
		||||
use std::ops::Deref;
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
use std::sync::{Arc, Mutex};
 | 
			
		||||
 | 
			
		||||
/// Mnemonic phrases are a human-readable version of the private keys.
 | 
			
		||||
/// Supported number of words are 12, 15, 18, 21 and 24.
 | 
			
		||||
use crate::Network;
 | 
			
		||||
 | 
			
		||||
// /// Mnemonic phrases are a human-readable version of the private keys.
 | 
			
		||||
// /// Supported number of words are 12, 15, 18, 21 and 24.
 | 
			
		||||
pub(crate) struct Mnemonic {
 | 
			
		||||
    inner: BdkMnemonic,
 | 
			
		||||
}
 | 
			
		||||
@ -23,8 +26,13 @@ pub(crate) struct Mnemonic {
 | 
			
		||||
impl Mnemonic {
 | 
			
		||||
    /// Generates Mnemonic with a random entropy
 | 
			
		||||
    pub(crate) fn new(word_count: WordCount) -> Self {
 | 
			
		||||
        // TODO 4: I DON'T KNOW IF THIS IS A DECENT WAY TO GENERATE ENTROPY PLEASE CONFIRM
 | 
			
		||||
        let mut rng = rand::thread_rng();
 | 
			
		||||
        let mut entropy = [0u8; 32];
 | 
			
		||||
        rng.fill(&mut entropy);
 | 
			
		||||
 | 
			
		||||
        let generated_key: GeneratedKey<_, BareCtx> =
 | 
			
		||||
            BdkMnemonic::generate((word_count, Language::English)).unwrap();
 | 
			
		||||
            BdkMnemonic::generate_with_entropy((word_count, Language::English), entropy).unwrap();
 | 
			
		||||
        let mnemonic = BdkMnemonic::parse_in(Language::English, generated_key.to_string()).unwrap();
 | 
			
		||||
        Mnemonic { inner: mnemonic }
 | 
			
		||||
    }
 | 
			
		||||
@ -65,7 +73,7 @@ impl DerivationPath {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub(crate) struct DescriptorSecretKey {
 | 
			
		||||
pub struct DescriptorSecretKey {
 | 
			
		||||
    pub(crate) inner: BdkDescriptorSecretKey,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -75,9 +83,9 @@ impl DescriptorSecretKey {
 | 
			
		||||
        let xkey: ExtendedKey = (mnemonic, password).into_extended_key().unwrap();
 | 
			
		||||
        let descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
 | 
			
		||||
            origin: None,
 | 
			
		||||
            xkey: xkey.into_xprv(network).unwrap(),
 | 
			
		||||
            xkey: xkey.into_xprv(network.into()).unwrap(),
 | 
			
		||||
            derivation_path: BdkDerivationPath::master(),
 | 
			
		||||
            wildcard: bdk::descriptor::Wildcard::Unhardened,
 | 
			
		||||
            wildcard: Wildcard::Unhardened,
 | 
			
		||||
        });
 | 
			
		||||
        Self {
 | 
			
		||||
            inner: descriptor_secret_key,
 | 
			
		||||
@ -97,6 +105,9 @@ impl DescriptorSecretKey {
 | 
			
		||||
        let descriptor_secret_key = &self.inner;
 | 
			
		||||
        let path = path.inner_mutex.lock().unwrap().deref().clone();
 | 
			
		||||
        match descriptor_secret_key {
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot derive from a single key".to_string(),
 | 
			
		||||
            )),
 | 
			
		||||
            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
 | 
			
		||||
                let derived_xprv = descriptor_x_key.xkey.derive_priv(&secp, &path)?;
 | 
			
		||||
                let key_source = match descriptor_x_key.origin.clone() {
 | 
			
		||||
@ -113,8 +124,8 @@ impl DescriptorSecretKey {
 | 
			
		||||
                    inner: derived_descriptor_secret_key,
 | 
			
		||||
                }))
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot derive from a single key".to_string(),
 | 
			
		||||
            BdkDescriptorSecretKey::MultiXPrv(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot derive from a multi key".to_string(),
 | 
			
		||||
            )),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -123,6 +134,9 @@ impl DescriptorSecretKey {
 | 
			
		||||
        let descriptor_secret_key = &self.inner;
 | 
			
		||||
        let path = path.inner_mutex.lock().unwrap().deref().clone();
 | 
			
		||||
        match descriptor_secret_key {
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot extend from a single key".to_string(),
 | 
			
		||||
            )),
 | 
			
		||||
            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
 | 
			
		||||
                let extended_path = descriptor_x_key.derivation_path.extend(path);
 | 
			
		||||
                let extended_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
 | 
			
		||||
@ -135,8 +149,8 @@ impl DescriptorSecretKey {
 | 
			
		||||
                    inner: extended_descriptor_secret_key,
 | 
			
		||||
                }))
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot extend from a single key".to_string(),
 | 
			
		||||
            BdkDescriptorSecretKey::MultiXPrv(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot derive from a multi key".to_string(),
 | 
			
		||||
            )),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -153,10 +167,13 @@ impl DescriptorSecretKey {
 | 
			
		||||
    pub(crate) fn secret_bytes(&self) -> Vec<u8> {
 | 
			
		||||
        let inner = &self.inner;
 | 
			
		||||
        let secret_bytes: Vec<u8> = match inner.deref() {
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
 | 
			
		||||
                descriptor_x_key.xkey.private_key.secret_bytes().to_vec()
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorSecretKey::Single(_) => {
 | 
			
		||||
            BdkDescriptorSecretKey::MultiXPrv(_) => {
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
@ -170,7 +187,7 @@ impl DescriptorSecretKey {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub(crate) struct DescriptorPublicKey {
 | 
			
		||||
pub struct DescriptorPublicKey {
 | 
			
		||||
    pub(crate) inner: BdkDescriptorPublicKey,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -189,6 +206,9 @@ impl DescriptorPublicKey {
 | 
			
		||||
        let path = path.inner_mutex.lock().unwrap().deref().clone();
 | 
			
		||||
 | 
			
		||||
        match descriptor_public_key.deref() {
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot derive from a single key".to_string(),
 | 
			
		||||
            )),
 | 
			
		||||
            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
 | 
			
		||||
                let derived_xpub = descriptor_x_key.xkey.derive_pub(&secp, &path)?;
 | 
			
		||||
                let key_source = match descriptor_x_key.origin.clone() {
 | 
			
		||||
@ -205,8 +225,8 @@ impl DescriptorPublicKey {
 | 
			
		||||
                    inner: derived_descriptor_public_key,
 | 
			
		||||
                }))
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot derive from a single key".to_string(),
 | 
			
		||||
            BdkDescriptorPublicKey::MultiXPub(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot derive from a multi xpub".to_string(),
 | 
			
		||||
            )),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -215,6 +235,9 @@ impl DescriptorPublicKey {
 | 
			
		||||
        let descriptor_public_key = &self.inner;
 | 
			
		||||
        let path = path.inner_mutex.lock().unwrap().deref().clone();
 | 
			
		||||
        match descriptor_public_key.deref() {
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot extend from a single key".to_string(),
 | 
			
		||||
            )),
 | 
			
		||||
            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
 | 
			
		||||
                let extended_path = descriptor_x_key.derivation_path.extend(path);
 | 
			
		||||
                let extended_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
 | 
			
		||||
@ -227,8 +250,8 @@ impl DescriptorPublicKey {
 | 
			
		||||
                    inner: extended_descriptor_public_key,
 | 
			
		||||
                }))
 | 
			
		||||
            }
 | 
			
		||||
            BdkDescriptorPublicKey::Single(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot extend from a single key".to_string(),
 | 
			
		||||
            BdkDescriptorPublicKey::MultiXPub(_) => Err(BdkError::Generic(
 | 
			
		||||
                "Cannot derive from a multi xpub".to_string(),
 | 
			
		||||
            )),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -237,21 +260,21 @@ impl DescriptorPublicKey {
 | 
			
		||||
        self.inner.to_string()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
 | 
			
		||||
// These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
 | 
			
		||||
// crate.
 | 
			
		||||
//
 | 
			
		||||
// // The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
 | 
			
		||||
// // These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
 | 
			
		||||
// // crate.
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use crate::keys::{DerivationPath, DescriptorPublicKey, DescriptorSecretKey, Mnemonic};
 | 
			
		||||
    use crate::BdkError;
 | 
			
		||||
    use bdk::bitcoin::hashes::hex::ToHex;
 | 
			
		||||
    // use bdk::bitcoin::hashes::hex::ToHex;
 | 
			
		||||
    use bdk::bitcoin::Network;
 | 
			
		||||
    use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
    fn get_inner() -> DescriptorSecretKey {
 | 
			
		||||
        let mnemonic = Mnemonic::from_string("chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect".to_string()).unwrap();
 | 
			
		||||
        DescriptorSecretKey::new(Network::Testnet, Arc::new(mnemonic), None)
 | 
			
		||||
        DescriptorSecretKey::new(Network::Testnet.into(), Arc::new(mnemonic), None)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn derive_dsk(
 | 
			
		||||
@ -359,13 +382,16 @@ mod test {
 | 
			
		||||
        assert!(derived_dpk.is_err());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_retrieve_master_secret_key() {
 | 
			
		||||
        let master_dpk = get_inner();
 | 
			
		||||
        let master_private_key = master_dpk.secret_bytes().to_hex();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            master_private_key,
 | 
			
		||||
            "e93315d6ce401eb4db803a56232f0ed3e69b053774e6047df54f1bd00e5ea936"
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    // TODO 7: It appears that the to_hex() method is not available anymore.
 | 
			
		||||
    //       Look into the correct way to pull the hex out of the DescriptorSecretKey.
 | 
			
		||||
    //       Note: ToHex was removed in bitcoin_hashes 0.12.0
 | 
			
		||||
    // #[test]
 | 
			
		||||
    // fn test_retrieve_master_secret_key() {
 | 
			
		||||
    //     let master_dpk = get_inner();
 | 
			
		||||
    //     let master_private_key = master_dpk.secret_bytes().to_hex();
 | 
			
		||||
    //     assert_eq!(
 | 
			
		||||
    //         master_private_key,
 | 
			
		||||
    //         "e93315d6ce401eb4db803a56232f0ed3e69b053774e6047df54f1bd00e5ea936"
 | 
			
		||||
    //     )
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,52 +1,73 @@
 | 
			
		||||
mod blockchain;
 | 
			
		||||
mod database;
 | 
			
		||||
mod descriptor;
 | 
			
		||||
mod esplora;
 | 
			
		||||
mod keys;
 | 
			
		||||
mod psbt;
 | 
			
		||||
mod wallet;
 | 
			
		||||
 | 
			
		||||
use crate::blockchain::{
 | 
			
		||||
    Auth, Blockchain, BlockchainConfig, ElectrumConfig, EsploraConfig, RpcConfig, RpcSyncParams,
 | 
			
		||||
};
 | 
			
		||||
use crate::database::DatabaseConfig;
 | 
			
		||||
use crate::descriptor::Descriptor;
 | 
			
		||||
use crate::keys::DerivationPath;
 | 
			
		||||
use crate::keys::{DescriptorPublicKey, DescriptorSecretKey, Mnemonic};
 | 
			
		||||
use crate::psbt::PartiallySignedTransaction;
 | 
			
		||||
use crate::wallet::SignOptions;
 | 
			
		||||
use crate::wallet::{BumpFeeTxBuilder, TxBuilder, Wallet};
 | 
			
		||||
use bdk::bitcoin::blockdata::script::Script as BdkScript;
 | 
			
		||||
use bdk::bitcoin::blockdata::transaction::TxIn as BdkTxIn;
 | 
			
		||||
use bdk::bitcoin::blockdata::transaction::TxOut as BdkTxOut;
 | 
			
		||||
use bdk::bitcoin::consensus::Decodable;
 | 
			
		||||
use bdk::bitcoin::psbt::serialize::Serialize;
 | 
			
		||||
use bdk::bitcoin::util::address::{Payload as BdkPayload, WitnessVersion};
 | 
			
		||||
use bdk::bitcoin::{
 | 
			
		||||
    Address as BdkAddress, Network, OutPoint as BdkOutPoint, Transaction as BdkTransaction, Txid,
 | 
			
		||||
};
 | 
			
		||||
use bdk::blockchain::Progress as BdkProgress;
 | 
			
		||||
use bdk::database::any::{SledDbConfiguration, SqliteDbConfiguration};
 | 
			
		||||
use bdk::keys::bip39::WordCount;
 | 
			
		||||
use bdk::bitcoin::address::{NetworkChecked, NetworkUnchecked};
 | 
			
		||||
use bdk::bitcoin::Address as BdkAddress;
 | 
			
		||||
use bdk::bitcoin::Network as BdkNetwork;
 | 
			
		||||
use bdk::wallet::AddressIndex as BdkAddressIndex;
 | 
			
		||||
use bdk::wallet::AddressInfo as BdkAddressInfo;
 | 
			
		||||
use bdk::LocalUtxo as BdkLocalUtxo;
 | 
			
		||||
use bdk::TransactionDetails as BdkTransactionDetails;
 | 
			
		||||
use bdk::{Balance as BdkBalance, BlockTime, Error as BdkError, FeeRate, KeychainKind};
 | 
			
		||||
use std::convert::From;
 | 
			
		||||
use std::fmt;
 | 
			
		||||
use std::fmt::Debug;
 | 
			
		||||
use std::io::Cursor;
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
use bdk::wallet::Balance as BdkBalance;
 | 
			
		||||
use bdk::Error as BdkError;
 | 
			
		||||
use bdk::KeychainKind;
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
// TODO 6: Why are these imports required?
 | 
			
		||||
use crate::descriptor::Descriptor;
 | 
			
		||||
use crate::esplora::EsploraClient;
 | 
			
		||||
use crate::keys::DerivationPath;
 | 
			
		||||
use crate::keys::DescriptorPublicKey;
 | 
			
		||||
use crate::keys::DescriptorSecretKey;
 | 
			
		||||
use crate::keys::Mnemonic;
 | 
			
		||||
use crate::wallet::Update;
 | 
			
		||||
use crate::wallet::Wallet;
 | 
			
		||||
use bdk::keys::bip39::WordCount;
 | 
			
		||||
// use bdk_esplora::EsploraExt;
 | 
			
		||||
 | 
			
		||||
uniffi::include_scaffolding!("bdk");
 | 
			
		||||
 | 
			
		||||
/// A output script and an amount of satoshis.
 | 
			
		||||
pub struct ScriptAmount {
 | 
			
		||||
    pub script: Arc<Script>,
 | 
			
		||||
    pub amount: u64,
 | 
			
		||||
pub enum Network {
 | 
			
		||||
    /// Mainnet Bitcoin.
 | 
			
		||||
    Bitcoin,
 | 
			
		||||
    /// Bitcoin's testnet network.
 | 
			
		||||
    Testnet,
 | 
			
		||||
    /// Bitcoin's signet network.
 | 
			
		||||
    Signet,
 | 
			
		||||
    /// Bitcoin's regtest network.
 | 
			
		||||
    Regtest,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Network> for BdkNetwork {
 | 
			
		||||
    fn from(network: Network) -> Self {
 | 
			
		||||
        match network {
 | 
			
		||||
            Network::Bitcoin => BdkNetwork::Bitcoin,
 | 
			
		||||
            Network::Testnet => BdkNetwork::Testnet,
 | 
			
		||||
            Network::Signet => BdkNetwork::Signet,
 | 
			
		||||
            Network::Regtest => BdkNetwork::Regtest,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<BdkNetwork> for Network {
 | 
			
		||||
    fn from(network: BdkNetwork) -> Self {
 | 
			
		||||
        match network {
 | 
			
		||||
            BdkNetwork::Bitcoin => Network::Bitcoin,
 | 
			
		||||
            BdkNetwork::Testnet => Network::Testnet,
 | 
			
		||||
            BdkNetwork::Signet => Network::Signet,
 | 
			
		||||
            BdkNetwork::Regtest => Network::Regtest,
 | 
			
		||||
            _ => panic!("Network {} not supported", network),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// /// A output script and an amount of satoshis.
 | 
			
		||||
// pub struct ScriptAmount {
 | 
			
		||||
//     pub script: Arc<Script>,
 | 
			
		||||
//     pub amount: u64,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
/// A derived address and the index it was found at.
 | 
			
		||||
pub struct AddressInfo {
 | 
			
		||||
    /// Child index of this address.
 | 
			
		||||
@ -61,7 +82,7 @@ impl From<BdkAddressInfo> for AddressInfo {
 | 
			
		||||
    fn from(address_info: BdkAddressInfo) -> Self {
 | 
			
		||||
        AddressInfo {
 | 
			
		||||
            index: address_info.index,
 | 
			
		||||
            address: Arc::new(Address::from(address_info.address)),
 | 
			
		||||
            address: Arc::new(address_info.address.into()),
 | 
			
		||||
            keychain: address_info.keychain,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -84,14 +105,6 @@ pub enum AddressIndex {
 | 
			
		||||
    /// Use with caution, if an index is given that is less than the current descriptor index
 | 
			
		||||
    /// then the returned address may have already been used.
 | 
			
		||||
    Peek { index: u32 },
 | 
			
		||||
    /// Return the address for a specific descriptor index and reset the current descriptor index
 | 
			
		||||
    /// used by `AddressIndex::New` and `AddressIndex::LastUsed` to this value.
 | 
			
		||||
    /// Use with caution, if an index is given that is less than the current descriptor index
 | 
			
		||||
    /// then the returned address and subsequent addresses returned by calls to `AddressIndex::New`
 | 
			
		||||
    /// and `AddressIndex::LastUsed` may have already been used. Also if the index is reset to a
 | 
			
		||||
    /// value earlier than the [`Blockchain`] stop_gap (default is 20) then a
 | 
			
		||||
    /// larger stop_gap should be used to monitor for all possibly used addresses.
 | 
			
		||||
    Reset { index: u32 },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<AddressIndex> for BdkAddressIndex {
 | 
			
		||||
@ -100,301 +113,350 @@ impl From<AddressIndex> for BdkAddressIndex {
 | 
			
		||||
            AddressIndex::New => BdkAddressIndex::New,
 | 
			
		||||
            AddressIndex::LastUnused => BdkAddressIndex::LastUnused,
 | 
			
		||||
            AddressIndex::Peek { index } => BdkAddressIndex::Peek(index),
 | 
			
		||||
            AddressIndex::Reset { index } => BdkAddressIndex::Reset(index),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A wallet transaction
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
 | 
			
		||||
pub struct TransactionDetails {
 | 
			
		||||
    pub transaction: Option<Arc<Transaction>>,
 | 
			
		||||
    /// Transaction id.
 | 
			
		||||
    pub txid: String,
 | 
			
		||||
    /// Received value (sats)
 | 
			
		||||
    /// Sum of owned outputs of this transaction.
 | 
			
		||||
    pub received: u64,
 | 
			
		||||
    /// Sent value (sats)
 | 
			
		||||
    /// Sum of owned inputs of this transaction.
 | 
			
		||||
    pub sent: u64,
 | 
			
		||||
    /// Fee value (sats) if confirmed.
 | 
			
		||||
    /// The availability of the fee depends on the backend. It's never None with an Electrum
 | 
			
		||||
    /// Server backend, but it could be None with a Bitcoin RPC node without txindex that receive
 | 
			
		||||
    /// funds while offline.
 | 
			
		||||
    pub fee: Option<u64>,
 | 
			
		||||
    /// If the transaction is confirmed, contains height and timestamp of the block containing the
 | 
			
		||||
    /// transaction, unconfirmed transaction contains `None`.
 | 
			
		||||
    pub confirmation_time: Option<BlockTime>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<BdkTransactionDetails> for TransactionDetails {
 | 
			
		||||
    fn from(tx_details: BdkTransactionDetails) -> Self {
 | 
			
		||||
        let optional_tx: Option<Arc<Transaction>> =
 | 
			
		||||
            tx_details.transaction.map(|tx| Arc::new(tx.into()));
 | 
			
		||||
 | 
			
		||||
        TransactionDetails {
 | 
			
		||||
            transaction: optional_tx,
 | 
			
		||||
            fee: tx_details.fee,
 | 
			
		||||
            txid: tx_details.txid.to_string(),
 | 
			
		||||
            received: tx_details.received,
 | 
			
		||||
            sent: tx_details.sent,
 | 
			
		||||
            confirmation_time: tx_details.confirmation_time,
 | 
			
		||||
// TODO 9: Peek is not correctly implemented
 | 
			
		||||
impl From<&AddressIndex> for BdkAddressIndex {
 | 
			
		||||
    fn from(address_index: &AddressIndex) -> Self {
 | 
			
		||||
        match address_index {
 | 
			
		||||
            AddressIndex::New => BdkAddressIndex::New,
 | 
			
		||||
            AddressIndex::LastUnused => BdkAddressIndex::LastUnused,
 | 
			
		||||
            AddressIndex::Peek { index } => BdkAddressIndex::Peek(*index),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A reference to a transaction output.
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 | 
			
		||||
pub struct OutPoint {
 | 
			
		||||
    /// The referenced transaction's txid.
 | 
			
		||||
    txid: String,
 | 
			
		||||
    /// The index of the referenced output in its transaction's vout.
 | 
			
		||||
    vout: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&OutPoint> for BdkOutPoint {
 | 
			
		||||
    fn from(outpoint: &OutPoint) -> Self {
 | 
			
		||||
        BdkOutPoint {
 | 
			
		||||
            txid: Txid::from_str(&outpoint.txid).unwrap(),
 | 
			
		||||
            vout: outpoint.vout,
 | 
			
		||||
impl From<BdkAddressIndex> for AddressIndex {
 | 
			
		||||
    fn from(address_index: BdkAddressIndex) -> Self {
 | 
			
		||||
        match address_index {
 | 
			
		||||
            BdkAddressIndex::New => AddressIndex::New,
 | 
			
		||||
            BdkAddressIndex::LastUnused => AddressIndex::LastUnused,
 | 
			
		||||
            _ => panic!("Mmmm not working"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&BdkAddressIndex> for AddressIndex {
 | 
			
		||||
    fn from(address_index: &BdkAddressIndex) -> Self {
 | 
			
		||||
        match address_index {
 | 
			
		||||
            BdkAddressIndex::New => AddressIndex::New,
 | 
			
		||||
            BdkAddressIndex::LastUnused => AddressIndex::LastUnused,
 | 
			
		||||
            _ => panic!("Mmmm not working"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// /// A wallet transaction
 | 
			
		||||
// #[derive(Debug, Clone, PartialEq, Eq, Default)]
 | 
			
		||||
// pub struct TransactionDetails {
 | 
			
		||||
//     pub transaction: Option<Arc<Transaction>>,
 | 
			
		||||
//     /// Transaction id.
 | 
			
		||||
//     pub txid: String,
 | 
			
		||||
//     /// Received value (sats)
 | 
			
		||||
//     /// Sum of owned outputs of this transaction.
 | 
			
		||||
//     pub received: u64,
 | 
			
		||||
//     /// Sent value (sats)
 | 
			
		||||
//     /// Sum of owned inputs of this transaction.
 | 
			
		||||
//     pub sent: u64,
 | 
			
		||||
//     /// Fee value (sats) if confirmed.
 | 
			
		||||
//     /// The availability of the fee depends on the backend. It's never None with an Electrum
 | 
			
		||||
//     /// Server backend, but it could be None with a Bitcoin RPC node without txindex that receive
 | 
			
		||||
//     /// funds while offline.
 | 
			
		||||
//     pub fee: Option<u64>,
 | 
			
		||||
//     /// If the transaction is confirmed, contains height and timestamp of the block containing the
 | 
			
		||||
//     /// transaction, unconfirmed transaction contains `None`.
 | 
			
		||||
//     pub confirmation_time: Option<BlockTime>,
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// impl From<BdkTransactionDetails> for TransactionDetails {
 | 
			
		||||
//     fn from(tx_details: BdkTransactionDetails) -> Self {
 | 
			
		||||
//         let optional_tx: Option<Arc<Transaction>> =
 | 
			
		||||
//             tx_details.transaction.map(|tx| Arc::new(tx.into()));
 | 
			
		||||
//
 | 
			
		||||
//         TransactionDetails {
 | 
			
		||||
//             transaction: optional_tx,
 | 
			
		||||
//             fee: tx_details.fee,
 | 
			
		||||
//             txid: tx_details.txid.to_string(),
 | 
			
		||||
//             received: tx_details.received,
 | 
			
		||||
//             sent: tx_details.sent,
 | 
			
		||||
//             confirmation_time: tx_details.confirmation_time,
 | 
			
		||||
//         }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// /// A reference to a transaction output.
 | 
			
		||||
// #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 | 
			
		||||
// pub struct OutPoint {
 | 
			
		||||
//     /// The referenced transaction's txid.
 | 
			
		||||
//     txid: String,
 | 
			
		||||
//     /// The index of the referenced output in its transaction's vout.
 | 
			
		||||
//     vout: u32,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl From<&OutPoint> for BdkOutPoint {
 | 
			
		||||
//     fn from(outpoint: &OutPoint) -> Self {
 | 
			
		||||
//         BdkOutPoint {
 | 
			
		||||
//             txid: Txid::from_str(&outpoint.txid).unwrap(),
 | 
			
		||||
//             vout: outpoint.vout,
 | 
			
		||||
//         }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
pub struct Balance {
 | 
			
		||||
    // All coinbase outputs not yet matured
 | 
			
		||||
    pub immature: u64,
 | 
			
		||||
    /// Unconfirmed UTXOs generated by a wallet tx
 | 
			
		||||
    pub trusted_pending: u64,
 | 
			
		||||
    /// Unconfirmed UTXOs received from an external wallet
 | 
			
		||||
    pub untrusted_pending: u64,
 | 
			
		||||
    /// Confirmed and immediately spendable balance
 | 
			
		||||
    pub confirmed: u64,
 | 
			
		||||
    /// Get sum of trusted_pending and confirmed coins
 | 
			
		||||
    pub spendable: u64,
 | 
			
		||||
    /// Get the whole balance visible to the wallet
 | 
			
		||||
    pub total: u64,
 | 
			
		||||
    pub inner: BdkBalance,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<BdkBalance> for Balance {
 | 
			
		||||
    fn from(bdk_balance: BdkBalance) -> Self {
 | 
			
		||||
        Balance {
 | 
			
		||||
            immature: bdk_balance.immature,
 | 
			
		||||
            trusted_pending: bdk_balance.trusted_pending,
 | 
			
		||||
            untrusted_pending: bdk_balance.untrusted_pending,
 | 
			
		||||
            confirmed: bdk_balance.confirmed,
 | 
			
		||||
            spendable: bdk_balance.get_spendable(),
 | 
			
		||||
            total: bdk_balance.get_total(),
 | 
			
		||||
        }
 | 
			
		||||
impl Balance {
 | 
			
		||||
    /// All coinbase outputs not yet matured.
 | 
			
		||||
    fn immature(&self) -> u64 {
 | 
			
		||||
        self.inner.immature
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Unconfirmed UTXOs generated by a wallet tx.
 | 
			
		||||
    fn trusted_pending(&self) -> u64 {
 | 
			
		||||
        self.inner.trusted_pending
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Unconfirmed UTXOs received from an external wallet.
 | 
			
		||||
    fn untrusted_pending(&self) -> u64 {
 | 
			
		||||
        self.inner.untrusted_pending
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Confirmed and immediately spendable balance.
 | 
			
		||||
    fn confirmed(&self) -> u64 {
 | 
			
		||||
        self.inner.confirmed
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get sum of trusted_pending and confirmed coins.
 | 
			
		||||
    fn trusted_spendable(&self) -> u64 {
 | 
			
		||||
        self.inner.trusted_spendable()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the whole balance visible to the wallet.
 | 
			
		||||
    fn total(&self) -> u64 {
 | 
			
		||||
        self.inner.total()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A transaction output, which defines new coins to be created from old ones.
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct TxOut {
 | 
			
		||||
    /// The value of the output, in satoshis.
 | 
			
		||||
    value: u64,
 | 
			
		||||
    /// The address of the output.
 | 
			
		||||
    script_pubkey: Arc<Script>,
 | 
			
		||||
}
 | 
			
		||||
// impl From<BdkBalance> for Balance {
 | 
			
		||||
//     fn from(bdk_balance: BdkBalance) -> Self {
 | 
			
		||||
//         Balance { inner: bdk_balance }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
impl From<&BdkTxOut> for TxOut {
 | 
			
		||||
    fn from(tx_out: &BdkTxOut) -> Self {
 | 
			
		||||
        TxOut {
 | 
			
		||||
            value: tx_out.value,
 | 
			
		||||
            script_pubkey: Arc::new(Script {
 | 
			
		||||
                inner: tx_out.script_pubkey.clone(),
 | 
			
		||||
            }),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
// /// A transaction output, which defines new coins to be created from old ones.
 | 
			
		||||
// #[derive(Debug, Clone)]
 | 
			
		||||
// pub struct TxOut {
 | 
			
		||||
//     /// The value of the output, in satoshis.
 | 
			
		||||
//     value: u64,
 | 
			
		||||
//     /// The address of the output.
 | 
			
		||||
//     script_pubkey: Arc<Script>,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl From<&BdkTxOut> for TxOut {
 | 
			
		||||
//     fn from(tx_out: &BdkTxOut) -> Self {
 | 
			
		||||
//         TxOut {
 | 
			
		||||
//             value: tx_out.value,
 | 
			
		||||
//             script_pubkey: Arc::new(Script {
 | 
			
		||||
//                 inner: tx_out.script_pubkey.clone(),
 | 
			
		||||
//             }),
 | 
			
		||||
//         }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// pub struct LocalUtxo {
 | 
			
		||||
//     outpoint: OutPoint,
 | 
			
		||||
//     txout: TxOut,
 | 
			
		||||
//     keychain: KeychainKind,
 | 
			
		||||
//     is_spent: bool,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl From<BdkLocalUtxo> for LocalUtxo {
 | 
			
		||||
//     fn from(local_utxo: BdkLocalUtxo) -> Self {
 | 
			
		||||
//         LocalUtxo {
 | 
			
		||||
//             outpoint: OutPoint {
 | 
			
		||||
//                 txid: local_utxo.outpoint.txid.to_string(),
 | 
			
		||||
//                 vout: local_utxo.outpoint.vout,
 | 
			
		||||
//             },
 | 
			
		||||
//             txout: TxOut {
 | 
			
		||||
//                 value: local_utxo.txout.value,
 | 
			
		||||
//                 script_pubkey: Arc::new(Script {
 | 
			
		||||
//                     inner: local_utxo.txout.script_pubkey,
 | 
			
		||||
//                 }),
 | 
			
		||||
//             },
 | 
			
		||||
//             keychain: local_utxo.keychain,
 | 
			
		||||
//             is_spent: local_utxo.is_spent,
 | 
			
		||||
//         }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// /// Trait that logs at level INFO every update received (if any).
 | 
			
		||||
// pub trait Progress: Send + Sync + 'static {
 | 
			
		||||
//     /// Send a new progress update. The progress value should be in the range 0.0 - 100.0, and the message value is an
 | 
			
		||||
//     /// optional text message that can be displayed to the user.
 | 
			
		||||
//     fn update(&self, progress: f32, message: Option<String>);
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// struct ProgressHolder {
 | 
			
		||||
//     progress: Box<dyn Progress>,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl BdkProgress for ProgressHolder {
 | 
			
		||||
//     fn update(&self, progress: f32, message: Option<String>) -> Result<(), BdkError> {
 | 
			
		||||
//         self.progress.update(progress, message);
 | 
			
		||||
//         Ok(())
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl Debug for ProgressHolder {
 | 
			
		||||
//     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
//         f.debug_struct("ProgressHolder").finish_non_exhaustive()
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// #[derive(Debug, Clone)]
 | 
			
		||||
// pub struct TxIn {
 | 
			
		||||
//     pub previous_output: OutPoint,
 | 
			
		||||
//     pub script_sig: Arc<Script>,
 | 
			
		||||
//     pub sequence: u32,
 | 
			
		||||
//     pub witness: Vec<Vec<u8>>,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl From<&BdkTxIn> for TxIn {
 | 
			
		||||
//     fn from(tx_in: &BdkTxIn) -> Self {
 | 
			
		||||
//         TxIn {
 | 
			
		||||
//             previous_output: OutPoint {
 | 
			
		||||
//                 txid: tx_in.previous_output.txid.to_string(),
 | 
			
		||||
//                 vout: tx_in.previous_output.vout,
 | 
			
		||||
//             },
 | 
			
		||||
//             script_sig: Arc::new(Script {
 | 
			
		||||
//                 inner: tx_in.script_sig.clone(),
 | 
			
		||||
//             }),
 | 
			
		||||
//             sequence: tx_in.sequence.0,
 | 
			
		||||
//             witness: tx_in.witness.to_vec(),
 | 
			
		||||
//         }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// /// A Bitcoin transaction.
 | 
			
		||||
// #[derive(Debug, Clone, PartialEq, Eq)]
 | 
			
		||||
// pub struct Transaction {
 | 
			
		||||
//     inner: BdkTransaction,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl Transaction {
 | 
			
		||||
//     fn new(transaction_bytes: Vec<u8>) -> Result<Self, BdkError> {
 | 
			
		||||
//         let mut decoder = Cursor::new(transaction_bytes);
 | 
			
		||||
//         let tx: BdkTransaction = BdkTransaction::consensus_decode(&mut decoder)?;
 | 
			
		||||
//         Ok(Transaction { inner: tx })
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn txid(&self) -> String {
 | 
			
		||||
//         self.inner.txid().to_string()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn weight(&self) -> u64 {
 | 
			
		||||
//         self.inner.weight() as u64
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn size(&self) -> u64 {
 | 
			
		||||
//         self.inner.size() as u64
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn vsize(&self) -> u64 {
 | 
			
		||||
//         self.inner.vsize() as u64
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn serialize(&self) -> Vec<u8> {
 | 
			
		||||
//         self.inner.serialize()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn is_coin_base(&self) -> bool {
 | 
			
		||||
//         self.inner.is_coin_base()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn is_explicitly_rbf(&self) -> bool {
 | 
			
		||||
//         self.inner.is_explicitly_rbf()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn is_lock_time_enabled(&self) -> bool {
 | 
			
		||||
//         self.inner.is_lock_time_enabled()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn version(&self) -> i32 {
 | 
			
		||||
//         self.inner.version
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn lock_time(&self) -> u32 {
 | 
			
		||||
//         self.inner.lock_time.0
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn input(&self) -> Vec<TxIn> {
 | 
			
		||||
//         self.inner.input.iter().map(|x| x.into()).collect()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn output(&self) -> Vec<TxOut> {
 | 
			
		||||
//         self.inner.output.iter().map(|x| x.into()).collect()
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
pub struct LocalUtxo {
 | 
			
		||||
    outpoint: OutPoint,
 | 
			
		||||
    txout: TxOut,
 | 
			
		||||
    keychain: KeychainKind,
 | 
			
		||||
    is_spent: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<BdkLocalUtxo> for LocalUtxo {
 | 
			
		||||
    fn from(local_utxo: BdkLocalUtxo) -> Self {
 | 
			
		||||
        LocalUtxo {
 | 
			
		||||
            outpoint: OutPoint {
 | 
			
		||||
                txid: local_utxo.outpoint.txid.to_string(),
 | 
			
		||||
                vout: local_utxo.outpoint.vout,
 | 
			
		||||
            },
 | 
			
		||||
            txout: TxOut {
 | 
			
		||||
                value: local_utxo.txout.value,
 | 
			
		||||
                script_pubkey: Arc::new(Script {
 | 
			
		||||
                    inner: local_utxo.txout.script_pubkey,
 | 
			
		||||
                }),
 | 
			
		||||
            },
 | 
			
		||||
            keychain: local_utxo.keychain,
 | 
			
		||||
            is_spent: local_utxo.is_spent,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Trait that logs at level INFO every update received (if any).
 | 
			
		||||
pub trait Progress: Send + Sync + 'static {
 | 
			
		||||
    /// Send a new progress update. The progress value should be in the range 0.0 - 100.0, and the message value is an
 | 
			
		||||
    /// optional text message that can be displayed to the user.
 | 
			
		||||
    fn update(&self, progress: f32, message: Option<String>);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ProgressHolder {
 | 
			
		||||
    progress: Box<dyn Progress>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl BdkProgress for ProgressHolder {
 | 
			
		||||
    fn update(&self, progress: f32, message: Option<String>) -> Result<(), BdkError> {
 | 
			
		||||
        self.progress.update(progress, message);
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Debug for ProgressHolder {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        f.debug_struct("ProgressHolder").finish_non_exhaustive()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct TxIn {
 | 
			
		||||
    pub previous_output: OutPoint,
 | 
			
		||||
    pub script_sig: Arc<Script>,
 | 
			
		||||
    pub sequence: u32,
 | 
			
		||||
    pub witness: Vec<Vec<u8>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&BdkTxIn> for TxIn {
 | 
			
		||||
    fn from(tx_in: &BdkTxIn) -> Self {
 | 
			
		||||
        TxIn {
 | 
			
		||||
            previous_output: OutPoint {
 | 
			
		||||
                txid: tx_in.previous_output.txid.to_string(),
 | 
			
		||||
                vout: tx_in.previous_output.vout,
 | 
			
		||||
            },
 | 
			
		||||
            script_sig: Arc::new(Script {
 | 
			
		||||
                inner: tx_in.script_sig.clone(),
 | 
			
		||||
            }),
 | 
			
		||||
            sequence: tx_in.sequence.0,
 | 
			
		||||
            witness: tx_in.witness.to_vec(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A Bitcoin transaction.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq)]
 | 
			
		||||
pub struct Transaction {
 | 
			
		||||
    inner: BdkTransaction,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Transaction {
 | 
			
		||||
    fn new(transaction_bytes: Vec<u8>) -> Result<Self, BdkError> {
 | 
			
		||||
        let mut decoder = Cursor::new(transaction_bytes);
 | 
			
		||||
        let tx: BdkTransaction = BdkTransaction::consensus_decode(&mut decoder)?;
 | 
			
		||||
        Ok(Transaction { inner: tx })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn txid(&self) -> String {
 | 
			
		||||
        self.inner.txid().to_string()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn weight(&self) -> u64 {
 | 
			
		||||
        self.inner.weight() as u64
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn size(&self) -> u64 {
 | 
			
		||||
        self.inner.size() as u64
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn vsize(&self) -> u64 {
 | 
			
		||||
        self.inner.vsize() as u64
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn serialize(&self) -> Vec<u8> {
 | 
			
		||||
        self.inner.serialize()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_coin_base(&self) -> bool {
 | 
			
		||||
        self.inner.is_coin_base()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_explicitly_rbf(&self) -> bool {
 | 
			
		||||
        self.inner.is_explicitly_rbf()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_lock_time_enabled(&self) -> bool {
 | 
			
		||||
        self.inner.is_lock_time_enabled()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn version(&self) -> i32 {
 | 
			
		||||
        self.inner.version
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn lock_time(&self) -> u32 {
 | 
			
		||||
        self.inner.lock_time.0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn input(&self) -> Vec<TxIn> {
 | 
			
		||||
        self.inner.input.iter().map(|x| x.into()).collect()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn output(&self) -> Vec<TxOut> {
 | 
			
		||||
        self.inner.output.iter().map(|x| x.into()).collect()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<BdkTransaction> for Transaction {
 | 
			
		||||
    fn from(tx: BdkTransaction) -> Self {
 | 
			
		||||
        Transaction { inner: tx }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
// impl From<BdkTransaction> for Transaction {
 | 
			
		||||
//     fn from(tx: BdkTransaction) -> Self {
 | 
			
		||||
//         Transaction { inner: tx }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
/// A Bitcoin address.
 | 
			
		||||
#[derive(Debug, PartialEq, Eq)]
 | 
			
		||||
pub struct Address {
 | 
			
		||||
    inner: BdkAddress,
 | 
			
		||||
    inner: BdkAddress<NetworkChecked>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Address {
 | 
			
		||||
    fn new(address: String) -> Result<Self, BdkError> {
 | 
			
		||||
        BdkAddress::from_str(address.as_str())
 | 
			
		||||
            .map(|a| Address { inner: a })
 | 
			
		||||
            .map_err(|e| BdkError::Generic(e.to_string()))
 | 
			
		||||
    fn new(address: String, network: Network) -> Result<Self, BdkError> {
 | 
			
		||||
        Ok(Address {
 | 
			
		||||
            inner: address
 | 
			
		||||
                .parse::<bdk::bitcoin::Address<NetworkUnchecked>>()
 | 
			
		||||
                .unwrap() // TODO 11: Handle error correctly by rethrowing it as a BdkError
 | 
			
		||||
                .require_network(network.into())
 | 
			
		||||
                .map_err(|e| BdkError::Generic(e.to_string()))?,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// alternative constructor
 | 
			
		||||
    fn from_script(script: Arc<Script>, network: Network) -> Result<Self, BdkError> {
 | 
			
		||||
        BdkAddress::from_script(&script.inner, network)
 | 
			
		||||
            .map(|a| Address { inner: a })
 | 
			
		||||
            .map_err(|e| BdkError::Generic(e.to_string()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn payload(&self) -> Payload {
 | 
			
		||||
        match &self.inner.payload.clone() {
 | 
			
		||||
            BdkPayload::PubkeyHash(pubkey_hash) => Payload::PubkeyHash {
 | 
			
		||||
                pubkey_hash: pubkey_hash.to_vec(),
 | 
			
		||||
            },
 | 
			
		||||
            BdkPayload::ScriptHash(script_hash) => Payload::ScriptHash {
 | 
			
		||||
                script_hash: script_hash.to_vec(),
 | 
			
		||||
            },
 | 
			
		||||
            BdkPayload::WitnessProgram { version, program } => Payload::WitnessProgram {
 | 
			
		||||
                version: *version,
 | 
			
		||||
                program: program.clone(),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // fn from_script(script: Arc<Script>, network: Network) -> Result<Self, BdkError> {
 | 
			
		||||
    //     BdkAddress::from_script(&script.inner, network)
 | 
			
		||||
    //         .map(|a| Address { inner: a })
 | 
			
		||||
    //         .map_err(|e| BdkError::Generic(e.to_string()))
 | 
			
		||||
    // }
 | 
			
		||||
    //
 | 
			
		||||
    // fn payload(&self) -> Payload {
 | 
			
		||||
    //     match &self.inner.payload.clone() {
 | 
			
		||||
    //         BdkPayload::PubkeyHash(pubkey_hash) => Payload::PubkeyHash {
 | 
			
		||||
    //             pubkey_hash: pubkey_hash.to_vec(),
 | 
			
		||||
    //         },
 | 
			
		||||
    //         BdkPayload::ScriptHash(script_hash) => Payload::ScriptHash {
 | 
			
		||||
    //             script_hash: script_hash.to_vec(),
 | 
			
		||||
    //         },
 | 
			
		||||
    //         BdkPayload::WitnessProgram { version, program } => Payload::WitnessProgram {
 | 
			
		||||
    //             version: *version,
 | 
			
		||||
    //             program: program.clone(),
 | 
			
		||||
    //         },
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    fn network(&self) -> Network {
 | 
			
		||||
        self.inner.network
 | 
			
		||||
        self.inner.network.into()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn script_pubkey(&self) -> Arc<Script> {
 | 
			
		||||
        Arc::new(Script {
 | 
			
		||||
            inner: self.inner.script_pubkey(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    // fn script_pubkey(&self) -> Arc<Script> {
 | 
			
		||||
    //     Arc::new(Script {
 | 
			
		||||
    //         inner: self.inner.script_pubkey(),
 | 
			
		||||
    //     })
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    fn to_qr_uri(&self) -> String {
 | 
			
		||||
        self.inner.to_qr_uri()
 | 
			
		||||
@ -411,91 +473,97 @@ impl From<BdkAddress> for Address {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The method used to produce an address.
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Payload {
 | 
			
		||||
    /// P2PKH address.
 | 
			
		||||
    PubkeyHash { pubkey_hash: Vec<u8> },
 | 
			
		||||
    /// P2SH address.
 | 
			
		||||
    ScriptHash { script_hash: Vec<u8> },
 | 
			
		||||
    /// Segwit address.
 | 
			
		||||
    WitnessProgram {
 | 
			
		||||
        /// The witness program version.
 | 
			
		||||
        version: WitnessVersion,
 | 
			
		||||
        /// The witness program.
 | 
			
		||||
        program: Vec<u8>,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A Bitcoin script.
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, Eq)]
 | 
			
		||||
pub struct Script {
 | 
			
		||||
    inner: BdkScript,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Script {
 | 
			
		||||
    fn new(raw_output_script: Vec<u8>) -> Self {
 | 
			
		||||
        let script: BdkScript = BdkScript::from(raw_output_script);
 | 
			
		||||
        Script { inner: script }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn to_bytes(&self) -> Vec<u8> {
 | 
			
		||||
        self.inner.to_bytes()
 | 
			
		||||
impl From<Address> for BdkAddress {
 | 
			
		||||
    fn from(address: Address) -> Self {
 | 
			
		||||
        address.inner
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<BdkScript> for Script {
 | 
			
		||||
    fn from(bdk_script: BdkScript) -> Self {
 | 
			
		||||
        Script { inner: bdk_script }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
enum RbfValue {
 | 
			
		||||
    Default,
 | 
			
		||||
    Value(u32),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The result after calling the TxBuilder finish() function. Contains unsigned PSBT and
 | 
			
		||||
/// transaction details.
 | 
			
		||||
pub struct TxBuilderResult {
 | 
			
		||||
    pub(crate) psbt: Arc<PartiallySignedTransaction>,
 | 
			
		||||
    pub transaction_details: TransactionDetails,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);
 | 
			
		||||
 | 
			
		||||
// The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
 | 
			
		||||
// These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
 | 
			
		||||
// crate.
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use super::Transaction;
 | 
			
		||||
    use crate::Network::Regtest;
 | 
			
		||||
    use crate::{Address, Payload};
 | 
			
		||||
    use assert_matches::assert_matches;
 | 
			
		||||
    use bdk::bitcoin::hashes::hex::FromHex;
 | 
			
		||||
    use bdk::bitcoin::util::address::WitnessVersion;
 | 
			
		||||
 | 
			
		||||
    // Verify that bdk-ffi Transaction can be created from valid bytes and serialized back into the same bytes.
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_transaction_serde() {
 | 
			
		||||
        let test_tx_bytes = Vec::from_hex("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700").unwrap();
 | 
			
		||||
        let new_tx_from_bytes = Transaction::new(test_tx_bytes.clone()).unwrap();
 | 
			
		||||
        let serialized_tx_to_bytes = new_tx_from_bytes.serialize();
 | 
			
		||||
        assert_eq!(test_tx_bytes, serialized_tx_to_bytes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Verify that bdk-ffi Address.payload includes expected WitnessProgram variant, version and program bytes.
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_address_witness_program() {
 | 
			
		||||
        let address =
 | 
			
		||||
            Address::new("bcrt1qqjn9gky9mkrm3c28e5e87t5akd3twg6xezp0tv".to_string()).unwrap();
 | 
			
		||||
        let payload = address.payload();
 | 
			
		||||
        assert_matches!(payload, Payload::WitnessProgram { version, program } => {
 | 
			
		||||
            assert_eq!(version,WitnessVersion::V0);
 | 
			
		||||
            assert_eq!(program, Vec::from_hex("04a6545885dd87b8e147cd327f2e9db362b72346").unwrap());
 | 
			
		||||
        });
 | 
			
		||||
        assert_eq!(address.network(), Regtest);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
// /// The method used to produce an address.
 | 
			
		||||
// #[derive(Debug)]
 | 
			
		||||
// pub enum Payload {
 | 
			
		||||
//     /// P2PKH address.
 | 
			
		||||
//     PubkeyHash { pubkey_hash: Vec<u8> },
 | 
			
		||||
//     /// P2SH address.
 | 
			
		||||
//     ScriptHash { script_hash: Vec<u8> },
 | 
			
		||||
//     /// Segwit address.
 | 
			
		||||
//     WitnessProgram {
 | 
			
		||||
//         /// The witness program version.
 | 
			
		||||
//         version: WitnessVersion,
 | 
			
		||||
//         /// The witness program.
 | 
			
		||||
//         program: Vec<u8>,
 | 
			
		||||
//     },
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// /// A Bitcoin script.
 | 
			
		||||
// #[derive(Clone, Debug, PartialEq, Eq)]
 | 
			
		||||
// pub struct Script {
 | 
			
		||||
//     inner: BdkScript,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl Script {
 | 
			
		||||
//     fn new(raw_output_script: Vec<u8>) -> Self {
 | 
			
		||||
//         let script: BdkScript = BdkScript::from(raw_output_script);
 | 
			
		||||
//         Script { inner: script }
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     fn to_bytes(&self) -> Vec<u8> {
 | 
			
		||||
//         self.inner.to_bytes()
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl From<BdkScript> for Script {
 | 
			
		||||
//     fn from(bdk_script: BdkScript) -> Self {
 | 
			
		||||
//         Script { inner: bdk_script }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// #[derive(Clone, Debug)]
 | 
			
		||||
// enum RbfValue {
 | 
			
		||||
//     Default,
 | 
			
		||||
//     Value(u32),
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// /// The result after calling the TxBuilder finish() function. Contains unsigned PSBT and
 | 
			
		||||
// /// transaction details.
 | 
			
		||||
// pub struct TxBuilderResult {
 | 
			
		||||
//     pub(crate) psbt: Arc<PartiallySignedTransaction>,
 | 
			
		||||
//     pub transaction_details: TransactionDetails,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);
 | 
			
		||||
//
 | 
			
		||||
// // The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
 | 
			
		||||
// // These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
 | 
			
		||||
// // crate.
 | 
			
		||||
// #[cfg(test)]
 | 
			
		||||
// mod test {
 | 
			
		||||
//     use super::Transaction;
 | 
			
		||||
//     use crate::Network::Regtest;
 | 
			
		||||
//     use crate::{Address, Payload};
 | 
			
		||||
//     use assert_matches::assert_matches;
 | 
			
		||||
//     use bdk::bitcoin::hashes::hex::FromHex;
 | 
			
		||||
//     use bdk::bitcoin::util::address::WitnessVersion;
 | 
			
		||||
//
 | 
			
		||||
//     // Verify that bdk-ffi Transaction can be created from valid bytes and serialized back into the same bytes.
 | 
			
		||||
//     #[test]
 | 
			
		||||
//     fn test_transaction_serde() {
 | 
			
		||||
//         let test_tx_bytes = Vec::from_hex("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700").unwrap();
 | 
			
		||||
//         let new_tx_from_bytes = Transaction::new(test_tx_bytes.clone()).unwrap();
 | 
			
		||||
//         let serialized_tx_to_bytes = new_tx_from_bytes.serialize();
 | 
			
		||||
//         assert_eq!(test_tx_bytes, serialized_tx_to_bytes);
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     // Verify that bdk-ffi Address.payload includes expected WitnessProgram variant, version and program bytes.
 | 
			
		||||
//     #[test]
 | 
			
		||||
//     fn test_address_witness_program() {
 | 
			
		||||
//         let address =
 | 
			
		||||
//             Address::new("bcrt1qqjn9gky9mkrm3c28e5e87t5akd3twg6xezp0tv".to_string()).unwrap();
 | 
			
		||||
//         let payload = address.payload();
 | 
			
		||||
//         assert_matches!(payload, Payload::WitnessProgram { version, program } => {
 | 
			
		||||
//             assert_eq!(version,WitnessVersion::V0);
 | 
			
		||||
//             assert_eq!(program, Vec::from_hex("04a6545885dd87b8e147cd327f2e9db362b72346").unwrap());
 | 
			
		||||
//         });
 | 
			
		||||
//         assert_eq!(address.network(), Regtest);
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
@ -1,119 +1,119 @@
 | 
			
		||||
use bdk::bitcoin::hashes::hex::ToHex;
 | 
			
		||||
use bdk::bitcoin::util::psbt::PartiallySignedTransaction as BdkPartiallySignedTransaction;
 | 
			
		||||
use bdk::bitcoincore_rpc::jsonrpc::serde_json;
 | 
			
		||||
use bdk::psbt::PsbtUtils;
 | 
			
		||||
use std::ops::Deref;
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
use std::sync::{Arc, Mutex};
 | 
			
		||||
 | 
			
		||||
use crate::{BdkError, FeeRate, Transaction};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub(crate) struct PartiallySignedTransaction {
 | 
			
		||||
    pub(crate) inner: Mutex<BdkPartiallySignedTransaction>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartiallySignedTransaction {
 | 
			
		||||
    pub(crate) fn new(psbt_base64: String) -> Result<Self, BdkError> {
 | 
			
		||||
        let psbt: BdkPartiallySignedTransaction =
 | 
			
		||||
            BdkPartiallySignedTransaction::from_str(&psbt_base64)?;
 | 
			
		||||
        Ok(PartiallySignedTransaction {
 | 
			
		||||
            inner: Mutex::new(psbt),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn serialize(&self) -> String {
 | 
			
		||||
        let psbt = self.inner.lock().unwrap().clone();
 | 
			
		||||
        psbt.to_string()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn txid(&self) -> String {
 | 
			
		||||
        let tx = self.inner.lock().unwrap().clone().extract_tx();
 | 
			
		||||
        let txid = tx.txid();
 | 
			
		||||
        txid.to_hex()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Return the transaction.
 | 
			
		||||
    pub(crate) fn extract_tx(&self) -> Arc<Transaction> {
 | 
			
		||||
        let tx = self.inner.lock().unwrap().clone().extract_tx();
 | 
			
		||||
        Arc::new(tx.into())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Combines this PartiallySignedTransaction with other PSBT as described by BIP 174.
 | 
			
		||||
    ///
 | 
			
		||||
    /// In accordance with BIP 174 this function is commutative i.e., `A.combine(B) == B.combine(A)`
 | 
			
		||||
    pub(crate) fn combine(
 | 
			
		||||
        &self,
 | 
			
		||||
        other: Arc<PartiallySignedTransaction>,
 | 
			
		||||
    ) -> Result<Arc<PartiallySignedTransaction>, BdkError> {
 | 
			
		||||
        let other_psbt = other.inner.lock().unwrap().clone();
 | 
			
		||||
        let mut original_psbt = self.inner.lock().unwrap().clone();
 | 
			
		||||
 | 
			
		||||
        original_psbt.combine(other_psbt)?;
 | 
			
		||||
        Ok(Arc::new(PartiallySignedTransaction {
 | 
			
		||||
            inner: Mutex::new(original_psbt),
 | 
			
		||||
        }))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// The total transaction fee amount, sum of input amounts minus sum of output amounts, in Sats.
 | 
			
		||||
    /// If the PSBT is missing a TxOut for an input returns None.
 | 
			
		||||
    pub(crate) fn fee_amount(&self) -> Option<u64> {
 | 
			
		||||
        self.inner.lock().unwrap().fee_amount()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// The transaction's fee rate. This value will only be accurate if calculated AFTER the
 | 
			
		||||
    /// `PartiallySignedTransaction` is finalized and all witness/signature data is added to the
 | 
			
		||||
    /// transaction.
 | 
			
		||||
    /// If the PSBT is missing a TxOut for an input returns None.
 | 
			
		||||
    pub(crate) fn fee_rate(&self) -> Option<Arc<FeeRate>> {
 | 
			
		||||
        self.inner.lock().unwrap().fee_rate().map(Arc::new)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Serialize the PSBT data structure as a String of JSON.
 | 
			
		||||
    pub(crate) fn json_serialize(&self) -> String {
 | 
			
		||||
        let psbt = self.inner.lock().unwrap();
 | 
			
		||||
        serde_json::to_string(psbt.deref()).unwrap()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
 | 
			
		||||
// These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
 | 
			
		||||
// crate.
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use crate::wallet::{TxBuilder, Wallet};
 | 
			
		||||
    use bdk::wallet::get_funded_wallet;
 | 
			
		||||
    use std::sync::Mutex;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_psbt_fee() {
 | 
			
		||||
        let test_wpkh = "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)";
 | 
			
		||||
        let (funded_wallet, _, _) = get_funded_wallet(test_wpkh);
 | 
			
		||||
        let test_wallet = Wallet {
 | 
			
		||||
            inner_mutex: Mutex::new(funded_wallet),
 | 
			
		||||
        };
 | 
			
		||||
        let drain_to_address = "tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt".to_string();
 | 
			
		||||
        let drain_to_script = crate::Address::new(drain_to_address)
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .script_pubkey();
 | 
			
		||||
 | 
			
		||||
        let tx_builder = TxBuilder::new()
 | 
			
		||||
            .fee_rate(2.0)
 | 
			
		||||
            .drain_wallet()
 | 
			
		||||
            .drain_to(drain_to_script.clone());
 | 
			
		||||
        //dbg!(&tx_builder);
 | 
			
		||||
        assert!(tx_builder.drain_wallet);
 | 
			
		||||
        assert_eq!(tx_builder.drain_to, Some(drain_to_script.inner.clone()));
 | 
			
		||||
 | 
			
		||||
        let tx_builder_result = tx_builder.finish(&test_wallet).unwrap();
 | 
			
		||||
 | 
			
		||||
        assert!(tx_builder_result.psbt.fee_rate().is_some());
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            tx_builder_result.psbt.fee_rate().unwrap().as_sat_per_vb(),
 | 
			
		||||
            2.682927
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        assert!(tx_builder_result.psbt.fee_amount().is_some());
 | 
			
		||||
        assert_eq!(tx_builder_result.psbt.fee_amount().unwrap(), 220);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
// use bdk::bitcoin::hashes::hex::ToHex;
 | 
			
		||||
// use bdk::bitcoin::util::psbt::PartiallySignedTransaction as BdkPartiallySignedTransaction;
 | 
			
		||||
// use bdk::bitcoincore_rpc::jsonrpc::serde_json;
 | 
			
		||||
// use bdk::psbt::PsbtUtils;
 | 
			
		||||
// use std::ops::Deref;
 | 
			
		||||
// use std::str::FromStr;
 | 
			
		||||
// use std::sync::{Arc, Mutex};
 | 
			
		||||
//
 | 
			
		||||
// use crate::{BdkError, FeeRate, Transaction};
 | 
			
		||||
//
 | 
			
		||||
// #[derive(Debug)]
 | 
			
		||||
// pub(crate) struct PartiallySignedTransaction {
 | 
			
		||||
//     pub(crate) inner: Mutex<BdkPartiallySignedTransaction>,
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// impl PartiallySignedTransaction {
 | 
			
		||||
//     pub(crate) fn new(psbt_base64: String) -> Result<Self, BdkError> {
 | 
			
		||||
//         let psbt: BdkPartiallySignedTransaction =
 | 
			
		||||
//             BdkPartiallySignedTransaction::from_str(&psbt_base64)?;
 | 
			
		||||
//         Ok(PartiallySignedTransaction {
 | 
			
		||||
//             inner: Mutex::new(psbt),
 | 
			
		||||
//         })
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     pub(crate) fn serialize(&self) -> String {
 | 
			
		||||
//         let psbt = self.inner.lock().unwrap().clone();
 | 
			
		||||
//         psbt.to_string()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     pub(crate) fn txid(&self) -> String {
 | 
			
		||||
//         let tx = self.inner.lock().unwrap().clone().extract_tx();
 | 
			
		||||
//         let txid = tx.txid();
 | 
			
		||||
//         txid.to_hex()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     /// Return the transaction.
 | 
			
		||||
//     pub(crate) fn extract_tx(&self) -> Arc<Transaction> {
 | 
			
		||||
//         let tx = self.inner.lock().unwrap().clone().extract_tx();
 | 
			
		||||
//         Arc::new(tx.into())
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     /// Combines this PartiallySignedTransaction with other PSBT as described by BIP 174.
 | 
			
		||||
//     ///
 | 
			
		||||
//     /// In accordance with BIP 174 this function is commutative i.e., `A.combine(B) == B.combine(A)`
 | 
			
		||||
//     pub(crate) fn combine(
 | 
			
		||||
//         &self,
 | 
			
		||||
//         other: Arc<PartiallySignedTransaction>,
 | 
			
		||||
//     ) -> Result<Arc<PartiallySignedTransaction>, BdkError> {
 | 
			
		||||
//         let other_psbt = other.inner.lock().unwrap().clone();
 | 
			
		||||
//         let mut original_psbt = self.inner.lock().unwrap().clone();
 | 
			
		||||
//
 | 
			
		||||
//         original_psbt.combine(other_psbt)?;
 | 
			
		||||
//         Ok(Arc::new(PartiallySignedTransaction {
 | 
			
		||||
//             inner: Mutex::new(original_psbt),
 | 
			
		||||
//         }))
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     /// The total transaction fee amount, sum of input amounts minus sum of output amounts, in Sats.
 | 
			
		||||
//     /// If the PSBT is missing a TxOut for an input returns None.
 | 
			
		||||
//     pub(crate) fn fee_amount(&self) -> Option<u64> {
 | 
			
		||||
//         self.inner.lock().unwrap().fee_amount()
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     /// The transaction's fee rate. This value will only be accurate if calculated AFTER the
 | 
			
		||||
//     /// `PartiallySignedTransaction` is finalized and all witness/signature data is added to the
 | 
			
		||||
//     /// transaction.
 | 
			
		||||
//     /// If the PSBT is missing a TxOut for an input returns None.
 | 
			
		||||
//     pub(crate) fn fee_rate(&self) -> Option<Arc<FeeRate>> {
 | 
			
		||||
//         self.inner.lock().unwrap().fee_rate().map(Arc::new)
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     /// Serialize the PSBT data structure as a String of JSON.
 | 
			
		||||
//     pub(crate) fn json_serialize(&self) -> String {
 | 
			
		||||
//         let psbt = self.inner.lock().unwrap();
 | 
			
		||||
//         serde_json::to_string(psbt.deref()).unwrap()
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// // The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
 | 
			
		||||
// // These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
 | 
			
		||||
// // crate.
 | 
			
		||||
// #[cfg(test)]
 | 
			
		||||
// mod test {
 | 
			
		||||
//     use crate::wallet::{TxBuilder, Wallet};
 | 
			
		||||
//     use bdk::wallet::get_funded_wallet;
 | 
			
		||||
//     use std::sync::Mutex;
 | 
			
		||||
//
 | 
			
		||||
//     #[test]
 | 
			
		||||
//     fn test_psbt_fee() {
 | 
			
		||||
//         let test_wpkh = "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)";
 | 
			
		||||
//         let (funded_wallet, _, _) = get_funded_wallet(test_wpkh);
 | 
			
		||||
//         let test_wallet = Wallet {
 | 
			
		||||
//             inner_mutex: Mutex::new(funded_wallet),
 | 
			
		||||
//         };
 | 
			
		||||
//         let drain_to_address = "tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt".to_string();
 | 
			
		||||
//         let drain_to_script = crate::Address::new(drain_to_address)
 | 
			
		||||
//             .unwrap()
 | 
			
		||||
//             .script_pubkey();
 | 
			
		||||
//
 | 
			
		||||
//         let tx_builder = TxBuilder::new()
 | 
			
		||||
//             .fee_rate(2.0)
 | 
			
		||||
//             .drain_wallet()
 | 
			
		||||
//             .drain_to(drain_to_script.clone());
 | 
			
		||||
//         //dbg!(&tx_builder);
 | 
			
		||||
//         assert!(tx_builder.drain_wallet);
 | 
			
		||||
//         assert_eq!(tx_builder.drain_to, Some(drain_to_script.inner.clone()));
 | 
			
		||||
//
 | 
			
		||||
//         let tx_builder_result = tx_builder.finish(&test_wallet).unwrap();
 | 
			
		||||
//
 | 
			
		||||
//         assert!(tx_builder_result.psbt.fee_rate().is_some());
 | 
			
		||||
//         assert_eq!(
 | 
			
		||||
//             tx_builder_result.psbt.fee_rate().unwrap().as_sat_per_vb(),
 | 
			
		||||
//             2.682927
 | 
			
		||||
//         );
 | 
			
		||||
//
 | 
			
		||||
//         assert!(tx_builder_result.psbt.fee_amount().is_some());
 | 
			
		||||
//         assert_eq!(tx_builder_result.psbt.fee_amount().unwrap(), 220);
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -7,67 +7,43 @@ import org.slf4j.LoggerFactory
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.nio.file.Files
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Library test, which will execute on linux host.
 | 
			
		||||
 */
 | 
			
		||||
class JvmLibTest {
 | 
			
		||||
 | 
			
		||||
    private fun getTestDataDir(): String {
 | 
			
		||||
        return Files.createTempDirectory("bdk-test").toString()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun cleanupTestDataDir(testDataDir: String) {
 | 
			
		||||
        File(testDataDir).deleteRecursively()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class LogProgress : Progress {
 | 
			
		||||
        private val log: Logger = LoggerFactory.getLogger(JvmLibTest::class.java)
 | 
			
		||||
 | 
			
		||||
        override fun update(progress: Float, message: String?) {
 | 
			
		||||
            log.debug("Syncing...")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val descriptor = Descriptor("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)", Network.TESTNET)
 | 
			
		||||
 | 
			
		||||
    private val databaseConfig = DatabaseConfig.Memory
 | 
			
		||||
 | 
			
		||||
    private val blockchainConfig = BlockchainConfig.Electrum(
 | 
			
		||||
        ElectrumConfig(
 | 
			
		||||
            "ssl://electrum.blockstream.info:60002",
 | 
			
		||||
            null,
 | 
			
		||||
            5u,
 | 
			
		||||
            null,
 | 
			
		||||
            100u,
 | 
			
		||||
            true,
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
class WalletTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    fun memoryWalletNewAddress() {
 | 
			
		||||
        val wallet = Wallet(descriptor, null, Network.TESTNET, databaseConfig)
 | 
			
		||||
        val address = wallet.getAddress(AddressIndex.New).address.asString()
 | 
			
		||||
        assertEquals("tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e", address)
 | 
			
		||||
    fun testNetwork() {
 | 
			
		||||
        val signetNetwork = Network.SIGNET
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun memoryWalletSyncGetBalance() {
 | 
			
		||||
        val wallet = Wallet(descriptor, null, Network.TESTNET, databaseConfig)
 | 
			
		||||
        val blockchain = Blockchain(blockchainConfig)
 | 
			
		||||
        wallet.sync(blockchain, LogProgress())
 | 
			
		||||
        val balance: Balance = wallet.getBalance()
 | 
			
		||||
        assertTrue(balance.total > 0u)
 | 
			
		||||
    fun testDescriptorBip86() {
 | 
			
		||||
        val mnemonic = Mnemonic(WordCount.WORDS12)
 | 
			
		||||
        val descriptorSecretKey = DescriptorSecretKey(Network.TESTNET, mnemonic, null)
 | 
			
		||||
        val descriptor = Descriptor.newBip86(descriptorSecretKey, KeychainKind.EXTERNAL, Network.TESTNET)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun sqliteWalletSyncGetBalance() {
 | 
			
		||||
        val testDataDir = getTestDataDir() + "/bdk-wallet.sqlite"
 | 
			
		||||
        val databaseConfig = DatabaseConfig.Sqlite(SqliteDbConfiguration(testDataDir))
 | 
			
		||||
        val wallet = Wallet(descriptor, null, Network.TESTNET, databaseConfig)
 | 
			
		||||
        val blockchain = Blockchain(blockchainConfig)
 | 
			
		||||
        wallet.sync(blockchain, LogProgress())
 | 
			
		||||
        val balance: Balance = wallet.getBalance()
 | 
			
		||||
        assertTrue(balance.total > 0u)
 | 
			
		||||
        cleanupTestDataDir(testDataDir)
 | 
			
		||||
    fun testUsedWallet() {
 | 
			
		||||
        val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET)
 | 
			
		||||
        val wallet = Wallet.newNoPersist(descriptor, null, Network.TESTNET)
 | 
			
		||||
        val (index, address, keychain)  = wallet.getAddress(AddressIndex.LastUnused)
 | 
			
		||||
        println("Address ${address.asString()} at index $index")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testBalance() {
 | 
			
		||||
        val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET)
 | 
			
		||||
        val wallet = Wallet.newNoPersist(descriptor, null, Network.TESTNET)
 | 
			
		||||
 | 
			
		||||
        assert(wallet.getBalance().total() == 0uL)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @Test
 | 
			
		||||
    // fun testSyncedBalance() {
 | 
			
		||||
    //     val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET)
 | 
			
		||||
    //     val wallet = Wallet.newNoPersist(descriptor, null, Network.TESTNET, WalletType.MEMORY)
 | 
			
		||||
    //     val esploraClient = EsploraClient("https://mempool.space/testnet/api")
 | 
			
		||||
    //     // val esploraClient = EsploraClient("https://blockstream.info/testnet/api")
 | 
			
		||||
    //     val update = esploraClient.scan(wallet, 10uL, 1uL)
 | 
			
		||||
    //     wallet.applyUpdate(update)
 | 
			
		||||
    //     println("Balance: ${wallet.getBalance().total()}")
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,8 @@ import org.gradle.kotlin.dsl.getValue
 | 
			
		||||
import org.gradle.kotlin.dsl.provideDelegate
 | 
			
		||||
import org.gradle.kotlin.dsl.register
 | 
			
		||||
 | 
			
		||||
// TODO 18: Migrate hard coded strings to constants all in the same location so they're at least easy
 | 
			
		||||
//          to find and reason about.
 | 
			
		||||
internal class UniFfiJvmPlugin : Plugin<Project> {
 | 
			
		||||
    override fun apply(target: Project): Unit = target.run {
 | 
			
		||||
 | 
			
		||||
@ -95,7 +97,7 @@ internal class UniFfiJvmPlugin : Plugin<Project> {
 | 
			
		||||
                doFirst {
 | 
			
		||||
                    copy {
 | 
			
		||||
                        with(it) {
 | 
			
		||||
                            from("${project.projectDir}/../../target/${this.targetDir}/release-smaller/${libName}.${this.ext}")
 | 
			
		||||
                            from("${project.projectDir}/../../bdk-ffi/target/${this.targetDir}/release-smaller/${libName}.${this.ext}")
 | 
			
		||||
                            into("${project.projectDir}/../../bdk-jvm/lib/src/main/resources/${this.resDir}/")
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@ -108,9 +110,22 @@ internal class UniFfiJvmPlugin : Plugin<Project> {
 | 
			
		||||
 | 
			
		||||
            dependsOn(moveNativeJvmLibs)
 | 
			
		||||
 | 
			
		||||
            workingDir("${project.projectDir}/../../bdk-ffi")
 | 
			
		||||
            val cargoArgs: List<String> = listOf("run", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-jvm/lib/src/main/kotlin", "--no-format")
 | 
			
		||||
            // TODO 2: Is the Windows name the correct one?
 | 
			
		||||
            // TODO 3: This will not work on mac Intel (x86_64 architecture)
 | 
			
		||||
            // val libraryPath = when (operatingSystem) {
 | 
			
		||||
            //     OS.LINUX   -> "./target/x86_64-unknown-linux-gnu/release-smaller/libbdkffi.so"
 | 
			
		||||
            //     OS.MAC     -> "./target/aarch64-apple-darwin/release-smaller/libbdkffi.dylib"
 | 
			
		||||
            //     OS.WINDOWS -> "./target/x86_64-pc-windows-msvc/release-smaller/bdkffi.dll"
 | 
			
		||||
            //     else       -> throw Exception("Unsupported OS")
 | 
			
		||||
            // }
 | 
			
		||||
 | 
			
		||||
            // workingDir("${project.projectDir}/../../bdk-ffi/")
 | 
			
		||||
            // val cargoArgs: List<String> = listOf("run", "--bin", "uniffi-bindgen", "generate", "--library", libraryPath, "--language", "kotlin", "--out-dir", "../bdk-jvm/lib/src/main/kotlin/", "--no-format")
 | 
			
		||||
 | 
			
		||||
            // The code above was for the migration to uniffi 0.24.3 using the --library flag
 | 
			
		||||
            // The code below works with uniffi 0.23.0
 | 
			
		||||
            workingDir("${project.projectDir}/../../bdk-ffi/")
 | 
			
		||||
            val cargoArgs: List<String> = listOf("run", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-jvm/lib/src/main/kotlin", "--no-format")
 | 
			
		||||
            executable("cargo")
 | 
			
		||||
            args(cargoArgs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,6 @@ rustup default 1.67.0
 | 
			
		||||
cargo build --profile release-smaller
 | 
			
		||||
 | 
			
		||||
echo "Copying linux libbdkffi.so..."
 | 
			
		||||
cp ../target/release-smaller/libbdkffi.so ../bdk-python/src/bdkpython/libbdkffi.so
 | 
			
		||||
cp ./target/release-smaller/libbdkffi.so ../bdk-python/src/bdkpython/libbdkffi.so
 | 
			
		||||
 | 
			
		||||
echo "All done!"
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,6 @@ rustup target add aarch64-apple-darwin
 | 
			
		||||
cargo build --profile release-smaller --target aarch64-apple-darwin
 | 
			
		||||
 | 
			
		||||
echo "Copying libraries libbdkffi.dylib..."
 | 
			
		||||
cp ../target/aarch64-apple-darwin/release-smaller/libbdkffi.dylib ../bdk-python/src/bdkpython/libbdkffi.dylib
 | 
			
		||||
cp ./target/aarch64-apple-darwin/release-smaller/libbdkffi.dylib ../bdk-python/src/bdkpython/libbdkffi.dylib
 | 
			
		||||
 | 
			
		||||
echo "All done!"
 | 
			
		||||
 | 
			
		||||
@ -9,10 +9,11 @@ cd ../bdk-ffi/
 | 
			
		||||
cargo run --bin uniffi-bindgen generate src/bdk.udl --language python --out-dir ../bdk-python/src/bdkpython/ --no-format
 | 
			
		||||
 | 
			
		||||
echo "Generating native binaries..."
 | 
			
		||||
rustup default 1.67.0
 | 
			
		||||
rustup target add x86_64-apple-darwin
 | 
			
		||||
cargo build --profile release-smaller --target x86_64-apple-darwin
 | 
			
		||||
 | 
			
		||||
echo "Copying libraries libbdkffi.dylib..."
 | 
			
		||||
cp ../target/x86_64-apple-darwin/release-smaller/libbdkffi.dylib ../bdk-python/src/bdkpython/libbdkffi.dylib
 | 
			
		||||
cp ./target/x86_64-apple-darwin/release-smaller/libbdkffi.dylib ../bdk-python/src/bdkpython/libbdkffi.dylib
 | 
			
		||||
 | 
			
		||||
echo "All done!"
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,6 @@ rustup target add x86_64-pc-windows-msvc
 | 
			
		||||
cargo build --profile release-smaller --target x86_64-pc-windows-msvc
 | 
			
		||||
 | 
			
		||||
echo "Copying libraries bdkffi.dll..."
 | 
			
		||||
cp ../target/x86_64-pc-windows-msvc/release-smaller/bdkffi.dll ../bdk-python/src/bdkpython/bdkffi.dll
 | 
			
		||||
cp ./target/x86_64-pc-windows-msvc/release-smaller/bdkffi.dll ../bdk-python/src/bdkpython/bdkffi.dll
 | 
			
		||||
 | 
			
		||||
echo "All done!"
 | 
			
		||||
 | 
			
		||||
@ -3,61 +3,19 @@ import unittest
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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(
 | 
			
		||||
        "ssl://electrum.blockstream.info:60002",
 | 
			
		||||
        None,
 | 
			
		||||
        5,
 | 
			
		||||
        None,
 | 
			
		||||
        100,
 | 
			
		||||
        True,
 | 
			
		||||
    )
 | 
			
		||||
)
 | 
			
		||||
blockchain = bdk.Blockchain(blockchain_config)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestSimpleBip84Wallet(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_address_bip84_testnet(self):
 | 
			
		||||
        wallet = bdk.Wallet(
 | 
			
		||||
        wallet = bdk.Wallet.new_no_persist(
 | 
			
		||||
            descriptor=descriptor,
 | 
			
		||||
            change_descriptor=None,
 | 
			
		||||
            network=bdk.Network.TESTNET,
 | 
			
		||||
            database_config=db_config
 | 
			
		||||
        )
 | 
			
		||||
        address_info = wallet.get_address(bdk.AddressIndex.LAST_UNUSED())
 | 
			
		||||
        address = address_info.address.as_string()
 | 
			
		||||
        # print(f"New address is {address}")
 | 
			
		||||
        assert address == "tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e", f"Wrong address {address}, should be tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e"
 | 
			
		||||
 | 
			
		||||
    def test_wallet_balance(self):
 | 
			
		||||
        wallet = bdk.Wallet(
 | 
			
		||||
            descriptor=descriptor,
 | 
			
		||||
            change_descriptor=None,
 | 
			
		||||
            network=bdk.Network.TESTNET,
 | 
			
		||||
            database_config=db_config,
 | 
			
		||||
        )
 | 
			
		||||
        wallet.sync(blockchain, None)
 | 
			
		||||
        balance = wallet.get_balance()
 | 
			
		||||
        # print(f"Balance is {balance.total} sat")
 | 
			
		||||
        assert balance.total > 0, "Balance is 0, send testnet coins to tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e"
 | 
			
		||||
 | 
			
		||||
    def test_output_address_from_script_pubkey(self):
 | 
			
		||||
        wallet = bdk.Wallet(
 | 
			
		||||
            descriptor=descriptor,
 | 
			
		||||
            change_descriptor=None,
 | 
			
		||||
            network=bdk.Network.TESTNET,
 | 
			
		||||
            database_config=db_config,
 | 
			
		||||
        )
 | 
			
		||||
        wallet.sync(blockchain, None)
 | 
			
		||||
        first_tx = list(wallet.list_transactions(True))[0]
 | 
			
		||||
        assert first_tx.txid == '35d3de8dd429ec4c9684168c1fbb9a4fb6db6f2ce89be214a024657a73ef4908'
 | 
			
		||||
        
 | 
			
		||||
        output1, output2 = list(first_tx.transaction.output())
 | 
			
		||||
        
 | 
			
		||||
        assert bdk.Address.from_script(output1.script_pubkey, bdk.Network.TESTNET).as_string() == 'tb1qw6ly2te8k9vy2mwj3g6gx82hj7hc8f5q3vry8t'
 | 
			
		||||
        assert bdk.Address.from_script(output2.script_pubkey, bdk.Network.TESTNET).as_string() == 'tb1qzsvpnmme78yl60j7ldh9aqvhvxr4mz7mjpmh22'
 | 
			
		||||
        
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    unittest.main()
 | 
			
		||||
 | 
			
		||||
@ -7,9 +7,27 @@ final class BitcoinDevKitTests: XCTestCase {
 | 
			
		||||
            descriptor: "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
 | 
			
		||||
            network: Network.regtest
 | 
			
		||||
        )
 | 
			
		||||
        let databaseConfig = DatabaseConfig.memory
 | 
			
		||||
        let wallet = try Wallet.init(descriptor: desc, changeDescriptor: nil, network: Network.regtest, databaseConfig: databaseConfig)
 | 
			
		||||
        let addressInfo = try wallet.getAddress(addressIndex: AddressIndex.new)
 | 
			
		||||
        XCTAssertEqual(addressInfo.address.asString(), "bcrt1qzg4mckdh50nwdm9hkzq06528rsu73hjxytqkxs")
 | 
			
		||||
        let wallet = try Wallet.newNoPersist(descriptor: desc, changeDescriptor: nil, network: .testnet)
 | 
			
		||||
        let addressInfo = wallet.getAddress(addressIndex: AddressIndex.lastUnused)
 | 
			
		||||
        XCTAssertEqual(addressInfo.address.asString(), "tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//     func testConnectedWalletBalance() throws {
 | 
			
		||||
//         let descriptor = try Descriptor(
 | 
			
		||||
//             descriptor: "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)",
 | 
			
		||||
//             network: Network.testnet
 | 
			
		||||
//         )
 | 
			
		||||
//         let wallet = try Wallet.newNoPersist(
 | 
			
		||||
//             descriptor: descriptor,
 | 
			
		||||
//             changeDescriptor: nil,
 | 
			
		||||
//             network: .testnet
 | 
			
		||||
//         )
 | 
			
		||||
//
 | 
			
		||||
//         let esploraClient = EsploraClient(url: "https://mempool.space/testnet/api")
 | 
			
		||||
//         // val esploraClient = EsploraClient("https://blockstream.info/testnet/api")
 | 
			
		||||
//         let update = try esploraClient.scan(wallet: wallet, stopGap: 10, parallelRequests: 1)
 | 
			
		||||
//         try wallet.applyUpdate(update: update)
 | 
			
		||||
//
 | 
			
		||||
//         print("Balance: \(wallet.getBalance().total())")
 | 
			
		||||
//     }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
# This script builds local swift-bdk Swift language bindings and corresponding bdkFFI.xcframework.
 | 
			
		||||
# The results of this script can be used for locally testing your SPM package adding a local package
 | 
			
		||||
# to your application pointing at the bdk-swift directory.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# Run the script from the repo root directory, ie: ./bdk-swift/build-local-swift.sh
 | 
			
		||||
 | 
			
		||||
rustup install nightly-2023-04-10
 | 
			
		||||
@ -14,7 +14,6 @@ rustup target add aarch64-apple-darwin x86_64-apple-darwin
 | 
			
		||||
pushd bdk-ffi
 | 
			
		||||
mkdir -p Sources/BitcoinDevKit
 | 
			
		||||
cargo run --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format
 | 
			
		||||
popd
 | 
			
		||||
 | 
			
		||||
cargo build --package bdk-ffi --profile release-smaller --target x86_64-apple-darwin
 | 
			
		||||
cargo build --package bdk-ffi --profile release-smaller --target aarch64-apple-darwin
 | 
			
		||||
@ -27,14 +26,15 @@ lipo target/aarch64-apple-ios-sim/release-smaller/libbdkffi.a target/x86_64-appl
 | 
			
		||||
mkdir -p target/lipo-macos/release-smaller
 | 
			
		||||
lipo target/aarch64-apple-darwin/release-smaller/libbdkffi.a target/x86_64-apple-darwin/release-smaller/libbdkffi.a -create -output target/lipo-macos/release-smaller/libbdkffi.a
 | 
			
		||||
 | 
			
		||||
popd
 | 
			
		||||
pushd bdk-swift
 | 
			
		||||
mv Sources/BitcoinDevKit/bdk.swift Sources/BitcoinDevKit/BitcoinDevKit.swift
 | 
			
		||||
cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/ios-arm64/bdkFFI.framework/Headers
 | 
			
		||||
cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/Headers
 | 
			
		||||
cp Sources/BitcoinDevKit/bdkFFI.h bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/Headers
 | 
			
		||||
cp ../target/aarch64-apple-ios/release-smaller/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI
 | 
			
		||||
cp ../target/lipo-ios-sim/release-smaller/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI
 | 
			
		||||
cp ../target/lipo-macos/release-smaller/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI
 | 
			
		||||
cp ../bdk-ffi/target/aarch64-apple-ios/release-smaller/libbdkffi.a bdkFFI.xcframework/ios-arm64/bdkFFI.framework/bdkFFI
 | 
			
		||||
cp ../bdk-ffi/target/lipo-ios-sim/release-smaller/libbdkffi.a bdkFFI.xcframework/ios-arm64_x86_64-simulator/bdkFFI.framework/bdkFFI
 | 
			
		||||
cp ../bdk-ffi/target/lipo-macos/release-smaller/libbdkffi.a bdkFFI.xcframework/macos-arm64_x86_64/bdkFFI.framework/bdkFFI
 | 
			
		||||
rm Sources/BitcoinDevKit/bdkFFI.h
 | 
			
		||||
rm Sources/BitcoinDevKit/bdkFFI.modulemap
 | 
			
		||||
#rm bdkFFI.xcframework.zip || true
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user