Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6e9a62628 | ||
|
|
f76f3234b4 | ||
|
|
cc3736809a | ||
|
|
4fc9fb916b | ||
|
|
12f4784b85 | ||
|
|
58e75d1a1d | ||
|
|
89d58db02a | ||
|
|
cda682b634 | ||
|
|
939a88214a | ||
|
|
1bbd85378a | ||
|
|
f3c6d97d81 | ||
|
|
d17ea4b90c | ||
|
|
76fa9b9521 | ||
|
|
cafa8dacab | ||
|
|
c039281ffc | ||
|
|
1f0b053872 | ||
|
|
97f1011748 | ||
|
|
edfcde1cc6 | ||
|
|
15c0dac622 | ||
|
|
a99e022756 | ||
|
|
672131ca0f | ||
|
|
72f90f1d63 | ||
|
|
5240cd895e | ||
|
|
55462fb426 | ||
|
|
9188dec2f2 | ||
|
|
a9a01950ee | ||
|
|
39cc3b3bfa | ||
|
|
c08fe99ad6 | ||
|
|
d53eb793ea |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,9 +2,6 @@ target
|
||||
build
|
||||
Cargo.lock
|
||||
/bindings/bdk-kotlin/local.properties
|
||||
/bindings/bdk-swift
|
||||
/bindings/bdk-swift.swiftdoc
|
||||
/bindings/bdk-swift.swiftsourceinfo
|
||||
.gradle
|
||||
wallet_db
|
||||
bdk_ffi_test
|
||||
|
||||
35
CHANGELOG.md
Normal file
35
CHANGELOG.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.4.0]
|
||||
|
||||
- Add dual license MIT and Apache 2.0
|
||||
- Add sqlite database support
|
||||
- Fix memory database configuration enum, remove junk field
|
||||
|
||||
## [v0.3.1]
|
||||
|
||||
- Remove hard coded sync progress value (was always returning 21.0)
|
||||
|
||||
## [v0.3.0]
|
||||
|
||||
- Move bdk-kotlin bindings and ios example to separate repos
|
||||
- Add bin to generate Python bindings
|
||||
- Add `PartiallySignedBitcoinTransaction::deserialize` function as named constructor to decode from a string per [BIP 0174]
|
||||
- Add `PartiallySignedBitcoinTransaction::serialize` function to encode to a string per [BIP 0174]
|
||||
- Remove `PartiallySignedBitcoinTransaction.details` struct field
|
||||
|
||||
[BIP 0174]:https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#encoding
|
||||
|
||||
## [v0.2.0]
|
||||
|
||||
[unreleased]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.4.0...HEAD
|
||||
[v0.4.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.3.1...v0.4.0
|
||||
[v0.3.1]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.3.0...v0.3.1
|
||||
[v0.3.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.2.0...v0.3.0
|
||||
[v0.2.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.0.0...v0.2.0
|
||||
23
Cargo.toml
23
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bdk-ffi"
|
||||
version = "0.1.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Steve Myers <steve@notmandatory.org>", "Sudarsan Balaji <sudarsan.balaji@artfuldev.com>"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -10,10 +10,23 @@ crate-type = ["staticlib", "cdylib"]
|
||||
name = "bdkffi"
|
||||
|
||||
[dependencies]
|
||||
bdk = { version = "0.13", features = ["all-keys", "use-esplora-ureq"] }
|
||||
uniffi_macros = "0.14.1"
|
||||
uniffi = "0.14.1"
|
||||
bdk = { version = "0.14", features = ["all-keys", "use-esplora-ureq", "sqlite"] }
|
||||
|
||||
# TODO remove when bdk "sqlite-bundled" feature added
|
||||
rusqlite = { version = "0.25.3", features = ["bundled"] }
|
||||
|
||||
uniffi_macros = { version = "0.16.0", features = ["builtin-bindgen"] }
|
||||
uniffi = { version = "0.16.0", features = ["builtin-bindgen"] }
|
||||
thiserror = "1.0"
|
||||
anyhow = "=1.0.45" # remove after upgrading to next version of uniffi
|
||||
|
||||
uniffi_bindgen = { version = "0.16.0", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
uniffi_build = "0.14.1"
|
||||
uniffi_build = { version = "0.16.0", features = ["builtin-bindgen"] }
|
||||
|
||||
[features]
|
||||
generate-python = ["uniffi_bindgen"]
|
||||
|
||||
[[bin]]
|
||||
name = "generate"
|
||||
|
||||
14
LICENSE
Normal file
14
LICENSE
Normal file
@@ -0,0 +1,14 @@
|
||||
This software is licensed under [Apache 2.0](LICENSE-APACHE) or
|
||||
[MIT](LICENSE-MIT), at your option.
|
||||
|
||||
Some files retain their own copyright notice, however, for full authorship
|
||||
information, see version control history.
|
||||
|
||||
Except as otherwise noted in individual files, all files in this repository are
|
||||
licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
http://opensource.org/licenses/MIT>, at your option.
|
||||
|
||||
You may not use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of this software or any files in this repository except in
|
||||
accordance with one or both of these licenses.
|
||||
201
LICENSE-APACHE
Normal file
201
LICENSE-APACHE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
16
LICENSE-MIT
Normal file
16
LICENSE-MIT
Normal file
@@ -0,0 +1,16 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
105
README.md
105
README.md
@@ -1,89 +1,42 @@
|
||||
# Foreign language bindings for BDK (bdk-ffi)
|
||||
# Native language bindings for BDK
|
||||
|
||||
This repository contains source code for generating foreign language bindings
|
||||
for the rust library bdk for the Bitcoin Dev Kit (BDK) project.
|
||||
This repository contains source code for generating native language bindings for the rust based
|
||||
[bdk] library which is the central artifact of the [Bitcoin Dev Kit] project.
|
||||
|
||||
Each supported language has it's own repository that includes this project as a [git submodule].
|
||||
The rust code in this project is a wrapper around the [bdk] library to expose it's APIs in a
|
||||
uniform way using the [mozilla/uniffi-rs] bindings generator for each supported target language.
|
||||
|
||||
## Supported target languages and platforms
|
||||
|
||||
| Language | Platform | Status |
|
||||
| --- | --- | --- |
|
||||
| Kotlin | JVM | WIP |
|
||||
| Kotlin | Android | WIP |
|
||||
| Swift | iOS | WIP |
|
||||
The below repositories include instructions for using, building, and publishing the native
|
||||
language binding for [bdk] supported by this project.
|
||||
|
||||
| Language | Platform | Repository |
|
||||
| -------- | ------------ | ------------ |
|
||||
| Kotlin | jvm | [bdk-kotlin] |
|
||||
| Kotlin | android | [bdk-kotlin] |
|
||||
| Swift | iOS, macOS | [bdk-swift] |
|
||||
| Python | linux, macOS | [bdk-python] |
|
||||
|
||||
## Getting Started (User)
|
||||
[bdk]: https://github.com/bitcoindevkit/bdk
|
||||
[Bitcoin Dev Kit]: https://github.com/bitcoindevkit
|
||||
[git submodule]: https://git-scm.com/book/en/v2/Git-Tools-Submodules
|
||||
[uniffi-rs]: https://github.com/mozilla/uniffi-rs
|
||||
|
||||
If you just want to consume the language bindings:
|
||||
[bdk-kotlin]: https://github.com/bitcoindevkit/bdk-kotlin
|
||||
[bdk-swift]: https://github.com/bitcoindevkit/bdk-swift
|
||||
[bdk-python]: https://github.com/thunderbiscuit/bdk-python
|
||||
|
||||
### Kotlin (JVM)
|
||||
## Contributing
|
||||
|
||||
Just add the dependency `org.bitcoindevkit:bdk-jvm:0.1.1`. The package is `org.bitcoindevkit.bdk`.
|
||||
### Install uniffi-bindgen cli tool
|
||||
|
||||
### Kotlin (Android)
|
||||
Install the uniffi-bindgen binary on your system using:
|
||||
|
||||
Just add the dependency `org.bitcoindevkit:bdk-android:0.1.1`. The package is `org.bitcoindevkit.bdk`.
|
||||
`cargo install uniffi_bindgen`
|
||||
|
||||
## Getting Started (Developer)
|
||||
|
||||
This project uses rust. A basic knowledge of the rust ecosystem is helpful.
|
||||
|
||||
### General
|
||||
1. Install `uniffi-bindgen`
|
||||
```sh
|
||||
cargo install uniffi_bindgen
|
||||
```
|
||||
1. See the [UniFFI User Guide](https://mozilla.github.io/uniffi-rs/) for more info
|
||||
|
||||
### Kotlin Bindings for JVM (OSX / Linux)
|
||||
|
||||
1. Install required targets
|
||||
```sh
|
||||
rustup target add x86_64-apple-darwin x86_64-unknown-linux-gnu
|
||||
```
|
||||
1. Build kotlin (JVM) bindings
|
||||
```sh
|
||||
./build.sh -k
|
||||
```
|
||||
1. Generated kotlin bindings are available at `/bindings/bdk-kotlin/`
|
||||
1. A demo app is available at `/bindings/bdk-kotlin/demo/`. It uses stdin for
|
||||
inputs and can be run from gradle.
|
||||
```sh
|
||||
cd bindings/bdk-kotlin
|
||||
./gradlew :demo:run
|
||||
```
|
||||
|
||||
### Kotlin bindings for Android
|
||||
|
||||
1. Install required targets
|
||||
```sh
|
||||
rustup target add x86_64-linux-android aarch64-linux-android
|
||||
armv7-linux-androideabi i686-linux-android
|
||||
```
|
||||
1. Install Android SDK and Build-Tools for API level 30+
|
||||
1. Setup `$ANDROID_NDK_HOME` and `$ANDROID_SDK_ROOT` path variables (which are
|
||||
required by the build scripts)
|
||||
1. Build kotlin (Android) bindings
|
||||
```sh
|
||||
./build.sh -a
|
||||
```
|
||||
2. A demo android app is available at [notmandatory/bdk-sample-app](https://github.com/notmandatory/bitcoindevkit-android-sample-app/tree/upgrade-to-bdk-ffi/)
|
||||
|
||||
### Swift bindings for iOS
|
||||
|
||||
1. Install the latest version of xcode, download and install the advanced tools.
|
||||
1. Ensure Swift is installed
|
||||
1. Install required targets
|
||||
```sh
|
||||
rustup target add aarch64-apple-ios x86_64-apple-ios
|
||||
```
|
||||
1. Build swift (iOS) bindings
|
||||
```sh
|
||||
./build.sh -s
|
||||
```
|
||||
1. Example iOS app can be found in `/examples/iOS` which can be run by xcode.
|
||||
|
||||
## Notes
|
||||
The version must be the same as the `uniffi` dependency in `Cargo.toml`.
|
||||
|
||||
### Adding new structs and functions
|
||||
|
||||
@@ -109,4 +62,6 @@ See the [UniFFI User Guide](https://mozilla.github.io/uniffi-rs/)
|
||||
|
||||
## Thanks
|
||||
|
||||
This project is made possible thanks to the wonderful work on [mozilla/uniffi-rs](https://github.com/mozilla/uniffi-rs)
|
||||
This project is made possible thanks to the wonderful work by the [mozilla/uniffi-rs] team.
|
||||
|
||||
[mozilla/uniffi-rs]: https://github.com/mozilla/uniffi-rs
|
||||
|
||||
145
build.sh
145
build.sh
@@ -1,145 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
# functions
|
||||
|
||||
## help
|
||||
help()
|
||||
{
|
||||
# Display Help
|
||||
echo "Build bdk-ffi and related libraries."
|
||||
echo
|
||||
echo "Syntax: build [-a|h|k|s]"
|
||||
echo "options:"
|
||||
echo "-a Android."
|
||||
echo "-h Print this Help."
|
||||
echo "-k Kotlin."
|
||||
echo "-s Swift."
|
||||
echo
|
||||
}
|
||||
|
||||
## rust
|
||||
build_rust() {
|
||||
echo "Build Rust library"
|
||||
cargo fmt
|
||||
cargo build
|
||||
cargo test
|
||||
}
|
||||
|
||||
## copy to bdk-bdk-kotlin
|
||||
copy_lib_kotlin() {
|
||||
echo -n "Copy "
|
||||
case $OS in
|
||||
"Darwin")
|
||||
echo -n "darwin "
|
||||
mkdir -p bindings/bdk-kotlin/jvm/src/main/resources/darwin-x86-64
|
||||
cp target/debug/libbdkffi.dylib bindings/bdk-kotlin/jvm/src/main/resources/darwin-x86-64
|
||||
;;
|
||||
"Linux")
|
||||
echo -n "linux "
|
||||
mkdir -p bindings/bdk-kotlin/jvm/src/main/resources/linux-x86-64
|
||||
cp target/debug/libbdkffi.so bindings/bdk-kotlin/jvm/src/main/resources/linux-x86-64
|
||||
;;
|
||||
esac
|
||||
echo "libs to kotlin sub-project"
|
||||
}
|
||||
|
||||
## bdk-bdk-kotlin jar
|
||||
build_kotlin() {
|
||||
copy_lib_kotlin
|
||||
uniffi-bindgen generate src/bdk.udl --no-format --out-dir bindings/bdk-kotlin/jvm/src/main/kotlin --language kotlin
|
||||
}
|
||||
|
||||
## bdk swift
|
||||
build_swift() {
|
||||
uniffi-bindgen generate src/bdk.udl --no-format --out-dir bindings/bdk-swift/ --language swift
|
||||
swiftc -module-name bdk -emit-library -o libbdkffi.dylib -emit-module -emit-module-path ./bindings/bdk-swift/ -parse-as-library -L ./target/debug/ -lbdkffi -Xcc -fmodule-map-file=./bindings/bdk-swift/bdkFFI.modulemap ./bindings/bdk-swift/bdk.swift
|
||||
TARGETDIR=target
|
||||
RELDIR=debug
|
||||
STATIC_LIB_NAME=libbdkffi.a
|
||||
|
||||
# We can't use cargo lipo because we can't link to universal libraries :(
|
||||
# https://github.com/rust-lang/rust/issues/55235
|
||||
LIBS_ARCHS=("x86_64" "arm64")
|
||||
IOS_TRIPLES=("x86_64-apple-ios" "aarch64-apple-ios")
|
||||
for i in "${!LIBS_ARCHS[@]}"; do
|
||||
cargo build --target "${IOS_TRIPLES[${i}]}"
|
||||
done
|
||||
|
||||
UNIVERSAL_BINARY=./${TARGETDIR}/ios/universal/${RELDIR}/${STATIC_LIB_NAME}
|
||||
NEED_LIPO=
|
||||
|
||||
# if the universal binary doesnt exist, or if it's older than the static libs,
|
||||
# we need to run `lipo` again.
|
||||
if [[ ! -f "${UNIVERSAL_BINARY}" ]]; then
|
||||
NEED_LIPO=1
|
||||
elif [[ "$(stat -f "%m" "./${TARGETDIR}/x86_64-apple-ios/${RELDIR}/${STATIC_LIB_NAME}")" -gt "$(stat -f "%m" "${UNIVERSAL_BINARY}")" ]]; then
|
||||
NEED_LIPO=1
|
||||
elif [[ "$(stat -f "%m" "./${TARGETDIR}/aarch64-apple-ios/${RELDIR}/${STATIC_LIB_NAME}")" -gt "$(stat -f "%m" "${UNIVERSAL_BINARY}")" ]]; then
|
||||
NEED_LIPO=1
|
||||
fi
|
||||
if [[ "${NEED_LIPO}" = "1" ]]; then
|
||||
mkdir -p "${TARGETDIR}/ios/universal/${RELDIR}"
|
||||
lipo -create -output "${UNIVERSAL_BINARY}" \
|
||||
"${TARGETDIR}/x86_64-apple-ios/${RELDIR}/${STATIC_LIB_NAME}" \
|
||||
"${TARGETDIR}/aarch64-apple-ios/${RELDIR}/${STATIC_LIB_NAME}"
|
||||
fi
|
||||
}
|
||||
|
||||
## rust android
|
||||
build_android() {
|
||||
build_kotlin
|
||||
|
||||
# If ANDROID_NDK_HOME is not set then set it to github actions default
|
||||
[ -z "$ANDROID_NDK_HOME" ] && export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle
|
||||
|
||||
# Update this line accordingly if you are not building *from* darwin-x86_64 or linux-x86_64
|
||||
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/`uname | tr '[:upper:]' '[:lower:]'`-x86_64/bin
|
||||
|
||||
# Required for 'ring' dependency to cross-compile to Android platform, must be at least 21
|
||||
export CFLAGS="-D__ANDROID_API__=21"
|
||||
|
||||
# IMPORTANT: make sure every target is not a substring of a different one. We check for them with grep later on
|
||||
BUILD_TARGETS="${BUILD_TARGETS:-aarch64,x86_64,i686}"
|
||||
|
||||
mkdir -p bindings/bdk-kotlin/android/src/main/jniLibs/ bindings/bdk-kotlin/android/src/main/jniLibs/arm64-v8a bindings/bdk-kotlin/android/src/main/jniLibs/x86_64 bindings/bdk-kotlin/android/src/main/jniLibs/x86
|
||||
|
||||
if echo $BUILD_TARGETS | grep "aarch64"; then
|
||||
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="aarch64-linux-android21-clang" CC="aarch64-linux-android21-clang" cargo build --target=aarch64-linux-android
|
||||
cp target/aarch64-linux-android/debug/libbdkffi.so bindings/bdk-kotlin/android/src/main/jniLibs/arm64-v8a
|
||||
fi
|
||||
if echo $BUILD_TARGETS | grep "x86_64"; then
|
||||
CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="x86_64-linux-android21-clang" CC="x86_64-linux-android21-clang" cargo build --target=x86_64-linux-android
|
||||
cp target/x86_64-linux-android/debug/libbdkffi.so bindings/bdk-kotlin/android/src/main/jniLibs/x86_64
|
||||
fi
|
||||
if echo $BUILD_TARGETS | grep "i686"; then
|
||||
CARGO_TARGET_I686_LINUX_ANDROID_LINKER="i686-linux-android21-clang" CC="i686-linux-android21-clang" cargo build --target=i686-linux-android
|
||||
cp target/i686-linux-android/debug/libbdkffi.so bindings/bdk-kotlin/android/src/main/jniLibs/x86
|
||||
fi
|
||||
|
||||
# copy sources
|
||||
cp -R bindings/bdk-kotlin/jvm/src/main/kotlin bindings/bdk-kotlin/android/src/main
|
||||
|
||||
# bdk-kotlin aar
|
||||
(cd bindings/bdk-kotlin && ./gradlew :android:build)
|
||||
}
|
||||
|
||||
OS=$(uname)
|
||||
|
||||
if [ "$1" == "-h" ]
|
||||
then
|
||||
help
|
||||
else
|
||||
build_rust
|
||||
|
||||
while [ -n "$1" ]; do # while loop starts
|
||||
case "$1" in
|
||||
-a) build_android ;;
|
||||
-k) build_kotlin ;;
|
||||
-s) build_swift ;;
|
||||
-h) help ;;
|
||||
*) echo "Option $1 not recognized" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
fi
|
||||
44
src/bdk.udl
44
src/bdk.udl
@@ -1,6 +1,6 @@
|
||||
namespace bdk {
|
||||
[Throws=BdkError]
|
||||
ExtendedKeyInfo generate_extended_key(Network network, MnemonicType mnemonic_type, string? password);
|
||||
ExtendedKeyInfo generate_extended_key(Network network, WordCount word_count, string? password);
|
||||
[Throws=BdkError]
|
||||
ExtendedKeyInfo restore_extended_key(Network network, string mnemonic, string? password);
|
||||
};
|
||||
@@ -46,6 +46,7 @@ enum BdkError {
|
||||
"Electrum",
|
||||
"Esplora",
|
||||
"Sled",
|
||||
"Rusqlite",
|
||||
};
|
||||
|
||||
enum Network {
|
||||
@@ -60,20 +61,25 @@ dictionary SledDbConfiguration {
|
||||
string tree_name;
|
||||
};
|
||||
|
||||
dictionary SqliteDbConfiguration {
|
||||
string path;
|
||||
};
|
||||
|
||||
[Enum]
|
||||
interface DatabaseConfig {
|
||||
Memory(string junk);
|
||||
Memory();
|
||||
Sled(SledDbConfiguration config);
|
||||
Sqlite(SqliteDbConfiguration config);
|
||||
};
|
||||
|
||||
dictionary TransactionDetails {
|
||||
u64? fees;
|
||||
u64 received;
|
||||
u64 sent;
|
||||
string id;
|
||||
string txid;
|
||||
};
|
||||
|
||||
dictionary Confirmation {
|
||||
dictionary BlockTime {
|
||||
u32 height;
|
||||
u64 timestamp;
|
||||
};
|
||||
@@ -81,22 +87,7 @@ dictionary Confirmation {
|
||||
[Enum]
|
||||
interface Transaction {
|
||||
Unconfirmed(TransactionDetails details);
|
||||
Confirmed(TransactionDetails details, Confirmation confirmation);
|
||||
};
|
||||
|
||||
interface OfflineWallet {
|
||||
[Throws=BdkError]
|
||||
constructor(string descriptor, Network network, DatabaseConfig database_config);
|
||||
|
||||
// OfflineWalletOperations
|
||||
string get_new_address();
|
||||
string get_last_unused_address();
|
||||
[Throws=BdkError]
|
||||
u64 get_balance();
|
||||
[Throws=BdkError]
|
||||
void sign([ByRef] PartiallySignedBitcoinTransaction psbt);
|
||||
[Throws=BdkError]
|
||||
sequence<Transaction> get_transactions();
|
||||
Confirmed(TransactionDetails details, BlockTime confirmation);
|
||||
};
|
||||
|
||||
dictionary ElectrumConfig {
|
||||
@@ -125,11 +116,9 @@ callback interface BdkProgress {
|
||||
void update(f32 progress, string? message);
|
||||
};
|
||||
|
||||
interface OnlineWallet {
|
||||
interface Wallet {
|
||||
[Throws=BdkError]
|
||||
constructor(string descriptor, string? change_descriptor, Network network, DatabaseConfig database_config, BlockchainConfig blockchain_config);
|
||||
|
||||
// OfflineWalletOperations
|
||||
string get_new_address();
|
||||
string get_last_unused_address();
|
||||
[Throws=BdkError]
|
||||
@@ -138,8 +127,6 @@ interface OnlineWallet {
|
||||
void sign([ByRef] PartiallySignedBitcoinTransaction psbt);
|
||||
[Throws=BdkError]
|
||||
sequence<Transaction> get_transactions();
|
||||
|
||||
// OnlineWalletInterface
|
||||
Network get_network();
|
||||
[Throws=BdkError]
|
||||
void sync(BdkProgress progress_update, u32? max_address_param);
|
||||
@@ -149,7 +136,10 @@ interface OnlineWallet {
|
||||
|
||||
interface PartiallySignedBitcoinTransaction {
|
||||
[Throws=BdkError]
|
||||
constructor([ByRef] OnlineWallet wallet, string recipient, u64 amount, float? fee_rate);
|
||||
constructor([ByRef] Wallet wallet, string recipient, u64 amount, float? fee_rate);
|
||||
[Name=deserialize,Throws=BdkError]
|
||||
constructor(string psbt_base64);
|
||||
string serialize();
|
||||
};
|
||||
|
||||
dictionary ExtendedKeyInfo {
|
||||
@@ -158,7 +148,7 @@ dictionary ExtendedKeyInfo {
|
||||
string fingerprint;
|
||||
};
|
||||
|
||||
enum MnemonicType {
|
||||
enum WordCount {
|
||||
"Words12",
|
||||
"Words15",
|
||||
"Words18",
|
||||
|
||||
67
src/bin/generate.rs
Normal file
67
src/bin/generate.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
pub const BDK_UDL: &str = "src/bdk.udl";
|
||||
|
||||
#[cfg(feature = "generate-python")]
|
||||
fn fixup_python_lib_path<O: AsRef<std::path::Path>>(
|
||||
out_dir: O,
|
||||
lib_name: &str,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
|
||||
const LOAD_INDIRECT_DEF: &str = "def loadIndirect():";
|
||||
|
||||
let bindings_file = out_dir.as_ref().join("bdk.py");
|
||||
let mut data = fs::read_to_string(&bindings_file)?;
|
||||
|
||||
let pos = data.find(LOAD_INDIRECT_DEF).expect(&format!(
|
||||
"loadIndirect not found in `{}`",
|
||||
bindings_file.display()
|
||||
));
|
||||
let range = pos..pos + LOAD_INDIRECT_DEF.len();
|
||||
|
||||
let replacement = format!(
|
||||
r#"
|
||||
def loadIndirect():
|
||||
import glob
|
||||
return getattr(ctypes.cdll, glob.glob(os.path.join(os.path.dirname(os.path.abspath(__file__)), '{}.*'))[0])
|
||||
|
||||
def _loadIndirectOld():"#,
|
||||
lib_name
|
||||
);
|
||||
data.replace_range(range, &replacement);
|
||||
|
||||
let mut file = fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&bindings_file)?;
|
||||
file.write(data.as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "generate-python")]
|
||||
fn generate_python() -> Result<(), Box<dyn std::error::Error>> {
|
||||
use std::env;
|
||||
|
||||
let out_path = env::var("GENERATE_PYTHON_BINDINGS_OUT")
|
||||
.map_err(|_| String::from("`GENERATE_PYTHON_BINDINGS_OUT` env variable missing"))?;
|
||||
uniffi_bindgen::generate_bindings(
|
||||
&format!("{}/{}", env!("CARGO_MANIFEST_DIR"), BDK_UDL),
|
||||
None,
|
||||
vec!["python"],
|
||||
Some(&out_path),
|
||||
false,
|
||||
)?;
|
||||
|
||||
if let Some(name) = env::var("GENERATE_PYTHON_BINDINGS_FIXUP_LIB_PATH").ok() {
|
||||
fixup_python_lib_path(&out_path, &name)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
#[cfg(feature = "generate-python")]
|
||||
generate_python()?;
|
||||
Ok(())
|
||||
}
|
||||
130
src/lib.rs
130
src/lib.rs
@@ -6,13 +6,13 @@ use bdk::blockchain::Progress;
|
||||
use bdk::blockchain::{
|
||||
electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain,
|
||||
};
|
||||
use bdk::database::any::{AnyDatabase, SledDbConfiguration};
|
||||
use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration};
|
||||
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
|
||||
use bdk::keys::bip39::{Language, Mnemonic, MnemonicType};
|
||||
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
|
||||
use bdk::keys::{DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey};
|
||||
use bdk::miniscript::BareCtx;
|
||||
use bdk::wallet::AddressIndex;
|
||||
use bdk::{ConfirmationTime, Error, FeeRate, SignOptions, Wallet};
|
||||
use bdk::{BlockTime, Error, FeeRate, SignOptions, Wallet as BdkWallet};
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
@@ -22,8 +22,9 @@ uniffi_macros::include_scaffolding!("bdk");
|
||||
type BdkError = Error;
|
||||
|
||||
pub enum DatabaseConfig {
|
||||
Memory { junk: String },
|
||||
Memory,
|
||||
Sled { config: SledDbConfiguration },
|
||||
Sqlite { config: SqliteDbConfiguration },
|
||||
}
|
||||
|
||||
pub struct ElectrumConfig {
|
||||
@@ -48,17 +49,7 @@ pub enum BlockchainConfig {
|
||||
}
|
||||
|
||||
trait WalletHolder<B> {
|
||||
fn get_wallet(&self) -> MutexGuard<Wallet<B, AnyDatabase>>;
|
||||
}
|
||||
|
||||
struct OfflineWallet {
|
||||
wallet: Mutex<Wallet<(), AnyDatabase>>,
|
||||
}
|
||||
|
||||
impl WalletHolder<()> for OfflineWallet {
|
||||
fn get_wallet(&self) -> MutexGuard<Wallet<(), AnyDatabase>> {
|
||||
self.wallet.lock().unwrap()
|
||||
}
|
||||
fn get_wallet(&self) -> MutexGuard<BdkWallet<B, AnyDatabase>>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
@@ -66,11 +57,9 @@ pub struct TransactionDetails {
|
||||
pub fees: Option<u64>,
|
||||
pub received: u64,
|
||||
pub sent: u64,
|
||||
pub id: String,
|
||||
pub txid: String,
|
||||
}
|
||||
|
||||
type Confirmation = ConfirmationTime;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Transaction {
|
||||
Unconfirmed {
|
||||
@@ -78,7 +67,7 @@ pub enum Transaction {
|
||||
},
|
||||
Confirmed {
|
||||
details: TransactionDetails,
|
||||
confirmation: Confirmation,
|
||||
confirmation: BlockTime,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -86,7 +75,7 @@ impl From<&bdk::TransactionDetails> for TransactionDetails {
|
||||
fn from(x: &bdk::TransactionDetails) -> TransactionDetails {
|
||||
TransactionDetails {
|
||||
fees: x.fee,
|
||||
id: x.txid.to_string(),
|
||||
txid: x.txid.to_string(),
|
||||
received: x.received,
|
||||
sent: x.sent,
|
||||
}
|
||||
@@ -96,9 +85,9 @@ impl From<&bdk::TransactionDetails> for TransactionDetails {
|
||||
impl From<&bdk::TransactionDetails> for Transaction {
|
||||
fn from(x: &bdk::TransactionDetails) -> Transaction {
|
||||
match x.confirmation_time.clone() {
|
||||
Some(confirmation) => Transaction::Confirmed {
|
||||
Some(block_time) => Transaction::Confirmed {
|
||||
details: TransactionDetails::from(x),
|
||||
confirmation,
|
||||
confirmation: block_time,
|
||||
},
|
||||
None => Transaction::Unconfirmed {
|
||||
details: TransactionDetails::from(x),
|
||||
@@ -107,7 +96,7 @@ impl From<&bdk::TransactionDetails> for Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
trait OfflineWalletOperations<B>: WalletHolder<B> {
|
||||
trait WalletOperations<B>: WalletHolder<B> {
|
||||
fn get_new_address(&self) -> String {
|
||||
self.get_wallet()
|
||||
.get_address(AddressIndex::New)
|
||||
@@ -128,7 +117,7 @@ trait OfflineWalletOperations<B>: WalletHolder<B> {
|
||||
self.get_wallet().get_balance()
|
||||
}
|
||||
|
||||
fn sign<'a>(&self, psbt: &'a PartiallySignedBitcoinTransaction) -> Result<(), Error> {
|
||||
fn sign(&self, psbt: &PartiallySignedBitcoinTransaction) -> Result<(), Error> {
|
||||
let mut psbt = psbt.internal.lock().unwrap();
|
||||
let finalized = self.get_wallet().sign(&mut psbt, SignOptions::default())?;
|
||||
match finalized {
|
||||
@@ -146,26 +135,8 @@ trait OfflineWalletOperations<B>: WalletHolder<B> {
|
||||
}
|
||||
}
|
||||
|
||||
impl OfflineWallet {
|
||||
fn new(
|
||||
descriptor: String,
|
||||
network: Network,
|
||||
database_config: DatabaseConfig,
|
||||
) -> Result<Self, BdkError> {
|
||||
let any_database_config = match database_config {
|
||||
DatabaseConfig::Memory { .. } => AnyDatabaseConfig::Memory(()),
|
||||
DatabaseConfig::Sled { config } => AnyDatabaseConfig::Sled(config),
|
||||
};
|
||||
let database = AnyDatabase::from_config(&any_database_config)?;
|
||||
let wallet = Mutex::new(Wallet::new_offline(&descriptor, None, network, database)?);
|
||||
Ok(OfflineWallet { wallet })
|
||||
}
|
||||
}
|
||||
|
||||
impl OfflineWalletOperations<()> for OfflineWallet {}
|
||||
|
||||
struct OnlineWallet {
|
||||
wallet: Mutex<Wallet<AnyBlockchain, AnyDatabase>>,
|
||||
struct Wallet {
|
||||
wallet_mutex: Mutex<BdkWallet<AnyBlockchain, AnyDatabase>>,
|
||||
}
|
||||
|
||||
pub trait BdkProgress: Send + Sync {
|
||||
@@ -185,20 +156,19 @@ impl Progress for BdkProgressHolder {
|
||||
|
||||
struct PartiallySignedBitcoinTransaction {
|
||||
internal: Mutex<PartiallySignedTransaction>,
|
||||
details: bdk::TransactionDetails,
|
||||
}
|
||||
|
||||
impl PartiallySignedBitcoinTransaction {
|
||||
fn new(
|
||||
online_wallet: &OnlineWallet,
|
||||
wallet: &Wallet,
|
||||
recipient: String,
|
||||
amount: u64,
|
||||
fee_rate: Option<f32>, // satoshis per vbyte
|
||||
) -> Result<Self, Error> {
|
||||
let wallet = online_wallet.get_wallet();
|
||||
let wallet = wallet.get_wallet();
|
||||
match Address::from_str(&recipient) {
|
||||
Ok(address) => {
|
||||
let (psbt, details) = {
|
||||
let (psbt, _details) = {
|
||||
let mut builder = wallet.build_tx();
|
||||
builder.add_recipient(address.script_pubkey(), amount);
|
||||
if let Some(sat_per_vb) = fee_rate {
|
||||
@@ -208,7 +178,6 @@ impl PartiallySignedBitcoinTransaction {
|
||||
};
|
||||
Ok(PartiallySignedBitcoinTransaction {
|
||||
internal: Mutex::new(psbt),
|
||||
details,
|
||||
})
|
||||
}
|
||||
Err(..) => Err(BdkError::Generic(
|
||||
@@ -216,9 +185,29 @@ impl PartiallySignedBitcoinTransaction {
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize(psbt_base64: String) -> Result<Self, Error> {
|
||||
let psbt: PartiallySignedTransaction = PartiallySignedTransaction::from_str(&psbt_base64)?;
|
||||
Ok(PartiallySignedBitcoinTransaction {
|
||||
internal: Mutex::new(psbt),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> String {
|
||||
let psbt = self.internal.lock().unwrap().clone();
|
||||
psbt.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl OnlineWallet {
|
||||
impl WalletHolder<AnyBlockchain> for Wallet {
|
||||
fn get_wallet(&self) -> MutexGuard<BdkWallet<AnyBlockchain, AnyDatabase>> {
|
||||
self.wallet_mutex.lock().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletOperations<AnyBlockchain> for Wallet {}
|
||||
|
||||
impl Wallet {
|
||||
fn new(
|
||||
descriptor: String,
|
||||
change_descriptor: Option<String>,
|
||||
@@ -227,8 +216,9 @@ impl OnlineWallet {
|
||||
blockchain_config: BlockchainConfig,
|
||||
) -> Result<Self, BdkError> {
|
||||
let any_database_config = match database_config {
|
||||
DatabaseConfig::Memory { .. } => AnyDatabaseConfig::Memory(()),
|
||||
DatabaseConfig::Memory => AnyDatabaseConfig::Memory(()),
|
||||
DatabaseConfig::Sled { config } => AnyDatabaseConfig::Sled(config),
|
||||
DatabaseConfig::Sqlite { config } => AnyDatabaseConfig::Sqlite(config),
|
||||
};
|
||||
let any_blockchain_config = match blockchain_config {
|
||||
BlockchainConfig::Electrum { config } => {
|
||||
@@ -252,18 +242,18 @@ impl OnlineWallet {
|
||||
};
|
||||
let database = AnyDatabase::from_config(&any_database_config)?;
|
||||
let blockchain = AnyBlockchain::from_config(&any_blockchain_config)?;
|
||||
let wallet = Mutex::new(Wallet::new(
|
||||
let wallet_mutex = Mutex::new(BdkWallet::new(
|
||||
&descriptor,
|
||||
change_descriptor.to_owned().as_ref(),
|
||||
network,
|
||||
database,
|
||||
blockchain,
|
||||
)?);
|
||||
Ok(OnlineWallet { wallet })
|
||||
Ok(Wallet { wallet_mutex })
|
||||
}
|
||||
|
||||
fn get_network(&self) -> Network {
|
||||
self.wallet.lock().unwrap().network()
|
||||
self.get_wallet().network()
|
||||
}
|
||||
|
||||
fn sync(
|
||||
@@ -271,31 +261,18 @@ impl OnlineWallet {
|
||||
progress_update: Box<dyn BdkProgress>,
|
||||
max_address_param: Option<u32>,
|
||||
) -> Result<(), BdkError> {
|
||||
progress_update.update(21.0, Some("message".to_string()));
|
||||
self.wallet
|
||||
.lock()
|
||||
.unwrap()
|
||||
self.get_wallet()
|
||||
.sync(BdkProgressHolder { progress_update }, max_address_param)
|
||||
}
|
||||
|
||||
fn broadcast<'a>(
|
||||
&self,
|
||||
psbt: &'a PartiallySignedBitcoinTransaction,
|
||||
) -> Result<Transaction, Error> {
|
||||
fn broadcast(&self, psbt: &PartiallySignedBitcoinTransaction) -> Result<Transaction, Error> {
|
||||
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
|
||||
self.get_wallet().broadcast(tx)?;
|
||||
Ok(Transaction::from(&psbt.details))
|
||||
self.get_wallet().broadcast(&tx)?;
|
||||
let tx_details = self.get_wallet().get_tx(&tx.txid(), true)?;
|
||||
Ok(Transaction::from(&tx_details.unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletHolder<AnyBlockchain> for OnlineWallet {
|
||||
fn get_wallet(&self) -> MutexGuard<Wallet<AnyBlockchain, AnyDatabase>> {
|
||||
self.wallet.lock().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl OfflineWalletOperations<AnyBlockchain> for OnlineWallet {}
|
||||
|
||||
pub struct ExtendedKeyInfo {
|
||||
mnemonic: String,
|
||||
xprv: String,
|
||||
@@ -304,11 +281,11 @@ pub struct ExtendedKeyInfo {
|
||||
|
||||
fn generate_extended_key(
|
||||
network: Network,
|
||||
mnemonic_type: MnemonicType,
|
||||
word_count: WordCount,
|
||||
password: Option<String>,
|
||||
) -> Result<ExtendedKeyInfo, Error> {
|
||||
let mnemonic: GeneratedKey<_, BareCtx> =
|
||||
Mnemonic::generate((mnemonic_type, Language::English)).unwrap();
|
||||
Mnemonic::generate((word_count, Language::English)).unwrap();
|
||||
let mnemonic = mnemonic.into_key();
|
||||
let xkey: ExtendedKey = (mnemonic.clone(), password).into_extended_key()?;
|
||||
let xprv = xkey.into_xprv(network).unwrap();
|
||||
@@ -325,7 +302,7 @@ fn restore_extended_key(
|
||||
mnemonic: String,
|
||||
password: Option<String>,
|
||||
) -> Result<ExtendedKeyInfo, Error> {
|
||||
let mnemonic = Mnemonic::from_phrase(mnemonic.as_ref(), Language::English).unwrap();
|
||||
let mnemonic = Mnemonic::parse_in(Language::English, mnemonic).unwrap();
|
||||
let xkey: ExtendedKey = (mnemonic.clone(), password).into_extended_key()?;
|
||||
let xprv = xkey.into_xprv(network).unwrap();
|
||||
let fingerprint = xprv.fingerprint(&Secp256k1::new());
|
||||
@@ -336,5 +313,4 @@ fn restore_extended_key(
|
||||
})
|
||||
}
|
||||
|
||||
uniffi::deps::static_assertions::assert_impl_all!(OfflineWallet: Sync, Send);
|
||||
uniffi::deps::static_assertions::assert_impl_all!(OnlineWallet: Sync, Send);
|
||||
uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);
|
||||
|
||||
44
test.sh
44
test.sh
@@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
# functions
|
||||
|
||||
## help
|
||||
help()
|
||||
{
|
||||
# Display Help
|
||||
echo "Test bdk-uniffi and related libraries."
|
||||
echo
|
||||
echo "Syntax: build [-a|h|k]"
|
||||
echo "options:"
|
||||
echo "-a Android connected device tests."
|
||||
echo "-h Print this Help."
|
||||
echo "-k Kotlin tests."
|
||||
echo
|
||||
}
|
||||
|
||||
test_kotlin() {
|
||||
(cd bindings/bdk-kotlin && ./gradlew :jvm:test -Djna.debug_load=true)
|
||||
}
|
||||
|
||||
test_android() {
|
||||
(cd bindings/bdk-kotlin && ./gradlew :android:connectedDebugAndroidTest)
|
||||
}
|
||||
|
||||
if [ $1 = "-h" ]
|
||||
then
|
||||
help
|
||||
else
|
||||
cargo test
|
||||
|
||||
# optional tests
|
||||
while [ -n "$1" ]; do # while loop starts
|
||||
case "$1" in
|
||||
-a) test_android ;;
|
||||
-h) help ;;
|
||||
-k) test_kotlin ;;
|
||||
*) echo "Option $1 not recognized" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
fi
|
||||
Reference in New Issue
Block a user