Compare commits

..

150 Commits

Author SHA1 Message Date
Steve Myers
89d58db02a Bump version to 0.3.1 2022-03-02 14:46:06 -08:00
Steve Myers
cda682b634 Remove hard coded sync progress value 2022-03-02 14:45:26 -08:00
Steve Myers
d17ea4b90c Bump version to 0.3.0 2022-02-27 21:18:05 -08:00
Steve Myers
76fa9b9521 Add CHANGELOG.md 2022-02-27 21:17:37 -08:00
Steve Myers
cafa8dacab Merge bitcoindevkit/bdk-ffi#104: Add PSBT deserialize and serialize functions, remove details
c039281ffc Add PSBT deserialize and serialize functions, remove details (Steve Myers)
1f0b053872 Fix bin/generate with no features (Steve Myers)

Pull request description:

  1. Fix bin/generate with no features
  2. Add `PartiallySignedBitcoinTransaction::deserialize` function as named constructor to decode from a string per [BIP 0174]
  3. Add `PartiallySignedBitcoinTransaction::serialize` function to encode to a string per [BIP 0174]
  4. Remove `PartiallySignedBitcoinTransaction.details` struct field

  [BIP 0174]:https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#encoding

  Fixes #103

Top commit has no ACKs.

Tree-SHA512: 0ba34d96625d71434d41573089a150d09fcfb6439648a7eed6e36dcdddd2682c969525b7c6efda898b2f979a7ca6ce51dc2158acf65da7f1f4c554d98b60f4ff
2022-02-25 14:47:47 -08:00
Steve Myers
c039281ffc Add PSBT deserialize and serialize functions, remove details 2022-02-24 20:49:59 -08:00
Steve Myers
1f0b053872 Fix bin/generate with no features 2022-02-24 17:17:05 -08:00
Alekos Filini
97f1011748 Add a binary to generate bindings 2022-02-08 22:15:10 +01:00
Alekos Filini
edfcde1cc6 Generate bindings for Python in build.rs 2022-02-08 21:04:12 +01:00
Sudarsan Balaji
15c0dac622 Rename field to wallet_mutex 2022-01-30 21:22:40 +00:00
Sudarsan Balaji
a99e022756 Rename OnlineWallet to Wallet
and remove OfflineWallet
2022-01-24 20:32:49 +00:00
Steve Myers
672131ca0f Fix uniffi_macros and uniffi_build versions 2022-01-24 10:58:48 -08:00
Steve Myers
72f90f1d63 Upgrade bdk to 0.14.0 2021-12-21 22:16:29 -08:00
Steve Myers
5240cd895e Update uniffi-rs to 0.16.0 2021-12-21 22:16:27 -08:00
Steve Myers
55462fb426 Remove bindings and examples, update README.md 2021-12-21 22:16:25 -08:00
Steve Myers
9188dec2f2 Remove swift related files and -s option in build.sh
Build script and files to create a bdkFFI binary xcframework and BitcoinDevKit swift package
have been moved to the bdk-swift repo.
2021-11-24 12:23:19 -08:00
Steve Myers
a9a01950ee Fix IOSBdkAppSample to work with git hosted BitcoinDevKit swift package 2021-11-23 10:05:19 -08:00
Steve Myers
39cc3b3bfa Update build.sh to create swift xcframework 2021-11-23 10:05:19 -08:00
Steve Myers
c08fe99ad6 Pin anyhow version to "=1.0.45"
This change can be removed after upgrading to the next version of uniffi.
See: https://github.com/mozilla/uniffi-rs/issues/1109
2021-11-22 15:59:12 -08:00
thunderbiscuit
d53eb793ea Refactor transaction 'id' property to 'txid' 2021-11-12 12:50:40 -05:00
Sudarsan Balaji
a68a8bee7d Merge pull request #75 from bitcoindevkit/update-readme-with-deployed-package-versions
Update README with latest published package information
2021-11-06 05:48:53 +05:30
Sudarsan Balaji
e250d4ae1f Update README with latest published package information 2021-11-06 05:48:27 +05:30
Sudarsan Balaji
3e0ae31890 Merge pull request #73 from bitcoindevkit/publish-a-package
Publish android and kotlin packages
2021-11-06 01:31:42 +05:30
Sudarsan Balaji
d197e17eaa Add some notes on consuming published packages 2021-11-06 01:30:36 +05:30
Sudarsan Balaji
63cbcb1aa3 Remove armv7 ABI target instead of i686 2021-11-06 00:45:03 +05:30
Sudarsan Balaji
be8b31684f Stop publishing on build 2021-11-06 00:23:06 +05:30
Sudarsan Balaji
862658ce96 Stop copying over i686 2021-11-06 00:22:58 +05:30
Sudarsan Balaji
6257911095 Ignore unnecessary files 2021-11-05 23:52:08 +05:30
Steve Myers
01da0137ef Merge pull request #70 from notmandatory/fix_build
Fix build.sh kotlin copy for android, also a rust fmt fix
2021-11-04 17:47:52 -07:00
Steve Myers
f86a9df594 Fix build.sh kotlin copy for android 2021-11-04 17:44:02 -07:00
Sudarsan Balaji
379cbe0b59 Merge pull request #69 from bitcoindevkit/return-transaction-details-on-broadcast
Return transaction details on broadcast
2021-11-05 01:19:04 +05:30
Sudarsan Balaji
4fd4a7ee6f Use From trait for conversion 2021-11-05 01:13:45 +05:30
Sudarsan Balaji
c6c4446092 Use From trait for conversion 2021-11-05 01:08:50 +05:30
Sudarsan Balaji
358cc35b60 Update Wallet::broadcast API 2021-11-05 00:45:40 +05:30
Sudarsan Balaji
c58a31f711 Return transaction on broadcast 2021-11-05 00:45:27 +05:30
Sudarsan Balaji
8a9e025e2f Simplify 2021-11-05 00:45:16 +05:30
Sudarsan Balaji
2ac26fa060 Add details to PSBT 2021-11-05 00:45:02 +05:30
Sudarsan Balaji
7e61659cb7 Add a way to convert TransactionDetails to Transaction 2021-11-05 00:44:40 +05:30
Sudarsan Balaji
947a5cb8e0 Allow cloning transaction 2021-11-05 00:43:26 +05:30
Sudarsan Balaji
f6b099aa76 Merge pull request #67 from bitcoindevkit/allow-passing-a-fee-rate-when-creating-a-transaction
Add optional fee rate to a transaction
2021-11-04 23:30:11 +05:30
Sudarsan Balaji
0467e12aae Add optional fee rate to a transaction 2021-11-04 23:29:22 +05:30
Sudarsan Balaji
94b07b9fb9 Merge pull request #65 from bitcoindevkit/allow-getting-last-unused-wallet-address
Allow getting last unused wallet address
2021-11-04 22:48:55 +05:30
Sudarsan Balaji
9ee31d97c7 Expose Wallet::getLastUnusedAddress 2021-11-04 22:45:00 +05:30
Sudarsan Balaji
2c30bdff56 Add a way to get last unused address 2021-11-04 22:44:38 +05:30
Sudarsan Balaji
97c59b4cad Merge pull request #52 from notmandatory/add-more-features-to-ios-example
Add more features to iOS example
2021-11-02 21:59:59 +05:30
Sudarsan Balaji
c5f18ca998 Ignore xc user data 2021-11-02 21:48:29 +05:30
Sudarsan Balaji
c79f1b6326 Ignore unnecessary files 2021-11-02 18:43:05 +05:30
Steve Myers
334bafcc7c Delete generated swift files, update lib name 2021-11-01 19:36:52 -07:00
Steve Myers
1148a2e6d7 Rename kotlin package to org.bitcoindevkit, rust lib to bdkffi 2021-11-01 19:07:27 -07:00
Sudarsan Balaji
80510381de Merge pull request #40 from notmandatory/add-documentation-for-swift-bindings
Add sections and more info to README
2021-10-30 00:29:24 +05:30
Sudarsan Balaji
a4370332df Fix heading levels 2021-10-30 00:28:26 +05:30
Sudarsan Balaji
693a75e6d1 Add sections and more info 2021-10-30 00:27:02 +05:30
Steve Myers
b6fa3539e4 Update README android setup 2021-10-28 15:34:17 -07:00
Steve Myers
5e7a42df07 Fix build.sh and test.sh help 2021-10-28 14:22:45 -07:00
Steve Myers
3b05c57794 Update bdk dependency to 0.13.0 2021-10-28 14:21:57 -07:00
Sudarsan Balaji
aabb09ccb8 Merge pull request #35 from notmandatory/add-swift-language-bindings
Add swift language bindings
2021-10-28 23:01:11 +05:30
Sudarsan Balaji
ab301f075b Update uniffi to 0.14.1
which supports callback interface in Swift
2021-10-28 23:00:23 +05:30
Sudarsan Balaji
9681f30e19 Revert "Remove callback interface"
This reverts commit 4ad9b89e25.
2021-10-28 01:51:16 +05:30
Sudarsan Balaji
ef73e38154 Add swiftmodule 2021-10-28 00:37:42 +05:30
Sudarsan Balaji
e98298090d Generate bindings for swift 2021-10-28 00:35:22 +05:30
Sudarsan Balaji
d1b24026e6 Copy kotlin libs only when building kotlin 2021-10-28 00:35:09 +05:30
Sudarsan Balaji
4ad9b89e25 Remove callback interface 2021-10-28 00:33:10 +05:30
Sudarsan Balaji
a8d9864825 Merge pull request #32 from notmandatory/fix-identifier-case-in-udl
Use snake_case for identifier
2021-10-21 23:43:28 +05:30
Sudarsan Balaji
71531b7abb Use snake_case for identifier 2021-10-21 23:42:38 +05:30
Sudarsan Balaji
a7a45a036c Merge pull request #31 from notmandatory/change-aar-outputs
Export source files with aar
2021-10-21 23:27:04 +05:30
Sudarsan Balaji
7e02dbc97a Export source files with aar 2021-10-21 23:26:34 +05:30
Sudarsan Balaji
1b30ce14a3 Merge pull request #30 from notmandatory/allow-creating-a-wallet-with-a-change-descriptor
Allow creating a wallet with a change descriptor
2021-10-21 14:54:21 +05:30
Sudarsan Balaji
e0937b73db Add change descriptor to Wallet 2021-10-21 14:50:52 +05:30
Sudarsan Balaji
a8b161569c Merge pull request #29 from notmandatory/allow-restoring-extended-key-from-mnemonic
Allow restoring extended key from mnemonic
2021-10-21 14:45:11 +05:30
Sudarsan Balaji
04eec7bf56 Allow restoring extended keys from mnemonic 2021-10-21 14:40:26 +05:30
Sudarsan Balaji
f2bbe668b1 Merge pull request #28 from notmandatory/allow-generating-key
Allow creating extended keys
2021-10-21 14:37:18 +05:30
Sudarsan Balaji
f1c2118b02 Allow generating extended keys 2021-10-21 14:35:40 +05:30
Sudarsan Balaji
f34e59e289 Merge pull request #21 from notmandatory/list-incomplete-transactions
List both confirmed and unconfirmed transactions
2021-10-18 17:35:14 +05:30
Sudarsan Balaji
892bfe868f List both confirmed and unconfirmed transactions 2021-10-18 15:48:30 +05:30
Steve Myers
fe251c12f3 Add android aar build and connected device test 2021-10-17 14:51:05 -07:00
Steve Myers
ee59dbe543 Remove and ignore generated code and binary libs 2021-10-17 14:51:02 -07:00
Sudarsan Balaji
2f83a9ed05 Merge pull request #18 from notmandatory/allow-listing-transactions
Allow listing confirmed transactions
2021-10-17 03:19:42 +05:30
Sudarsan Balaji
4a7d665f7c Return only confirmed transactions in Wallet::getTransactions 2021-10-17 02:36:43 +05:30
Sudarsan Balaji
25b8a8841d Allow listing confirmed transactions 2021-10-17 02:28:26 +05:30
Sudarsan Balaji
38b8589526 Merge pull request #14 from notmandatory/allow-signing-partially-signed-transactions
Allow signing partially signed transactions
2021-10-16 20:28:03 +05:30
Sudarsan Balaji
3693e99372 Share Wallet::getBalance and Wallet::sign 2021-10-16 20:25:58 +05:30
Sudarsan Balaji
d97a13d186 Fix formatting 2021-10-16 20:19:56 +05:30
Sudarsan Balaji
4e1c6bd62b Add sign and broadcast to wallet 2021-10-16 20:19:34 +05:30
Sudarsan Balaji
04eee046cb Merge pull request #13 from notmandatory/allow-creating-a-wallet-transaction
Allow creating partially signed bitcoin transactions
2021-10-16 16:44:49 +05:30
Sudarsan Balaji
69a676ba36 Allow creating partially signed bitcoin transactions 2021-10-16 16:42:35 +05:30
Sudarsan Balaji
a528a76c5d Merge pull request #12 from notmandatory/add-demo-application
Add demo application
2021-10-16 14:46:50 +05:30
Sudarsan Balaji
653773a638 Add demo application in kotlin 2021-10-16 14:45:32 +05:30
Sudarsan Balaji
857d99030b Merge pull request #11 from notmandatory/unify-offline-operations
Share OfflineWalletOperations
2021-10-16 14:22:37 +05:30
Sudarsan Balaji
2db59de659 Share OfflineWalletOperations 2021-10-16 14:19:29 +05:30
Steve Myers
c15993310d Reorganize bdk-kotlin into jvm sub-module 2021-10-14 22:05:21 -07:00
artfuldev
b2f2f9135d Add OnlineWallet::getBalance() 2021-10-15 03:40:33 +05:30
artfuldev
3a7e7baf51 Remove testdb before every test 2021-10-15 03:05:46 +05:30
artfuldev
d307b281d7 Remove unnecessary Mutex wrapper 2021-10-15 03:00:49 +05:30
artfuldev
41afeafcd3 Test a callback 2021-10-15 01:54:32 +05:30
artfuldev
47651f3681 Add OnlineWallet::getNetwork 2021-10-15 00:48:53 +05:30
artfuldev
9b7a9ded56 Add online wallet 2021-10-15 00:43:17 +05:30
Steve Myers
178fd6f010 Change order of Network param 2021-10-14 11:17:52 -07:00
Steve Myers
31710ac77b Add Network enum as wallet constructor param 2021-10-14 10:58:16 -07:00
Sudarsan Balaji
6d7939c88f Allow using configs for database 2021-10-14 04:23:17 +05:30
Sudarsan Balaji
598d08b3bc Use a thread-safe MemoryDatabase 2021-10-14 03:53:22 +05:30
Sudarsan Balaji
b6d6a0d092 Add name to authors 2021-10-14 00:15:25 +05:30
Sudarsan Balaji
6093a8750b Add JNA debug_load to gradle script 2021-10-14 00:06:05 +05:30
Sudarsan Balaji
279f304d5d Add a little bit of error handling 2021-10-14 00:05:50 +05:30
Sudarsan Balaji
64fbf60a6a Stop running gradle build
which also runs tests
2021-10-14 00:05:29 +05:30
Sudarsan Balaji
ce93e4e954 Ignore more files
mac-specific
local sled database
2021-10-14 00:05:04 +05:30
Sudarsan Balaji
cf56619157 Use settings from rust-fmt 2021-10-14 00:04:44 +05:30
Sudarsan Balaji
caff93c945 Add editorconfig 2021-10-13 13:42:55 +05:30
Steve Myers
01bfe5d10e Update README, build.sh and test.sh, rust fmt 2021-10-12 18:22:02 -07:00
Steve Myers
091c9994fa [WIP] reorganize and remove old stuff 2021-10-12 15:24:11 -07:00
Sudarsan Balaji
f30558d55c Ignore testdb 2021-10-13 03:06:49 +05:30
Sudarsan Balaji
4efbfc1e9c Add some more steps to run 2021-10-13 03:05:55 +05:30
Sudarsan Balaji
3491a4548d [WIP] kotlin tests work! 2021-10-13 03:02:49 +05:30
Sudarsan Balaji
0cc2f0a5be [WIP] Add generated and test files 2021-10-13 02:05:46 +05:30
Sudarsan Balaji
784f754cd9 [WIP] Add get new address API to Wallet 2021-10-13 01:45:22 +05:30
Steve Myers
8faba58cd4 wip compiles now 2021-10-12 11:53:11 -07:00
Steve Myers
0b265a7c26 WIP -- NOT WORKING 2021-10-12 10:27:33 -07:00
Steve Myers
f9e3bdfdb2 [wip] swift 2021-10-02 18:22:30 -07:00
Steve Myers
39e5efe5c0 Upgrade bdk dependency to 0.11 2021-09-28 17:03:25 -07:00
Steve Myers
342c4c4aa8 Remove local.properties and add to .gitignore 2021-07-07 10:42:42 -07:00
Steve Myers
bb9fdd35cf Update build.sh to install jvm darwin-x86-64 dylib 2021-07-05 14:25:09 -07:00
Steve Myers
a1aea54c53 Add Wallet.listTransactions() 2021-07-04 22:10:32 -07:00
Steve Myers
a33a09f2a3 Add Wallet.balance() 2021-07-04 15:54:23 -07:00
Steve Myers
6361b41f33 Return FfiResult errors as FfiError enum short values 2021-07-03 20:40:17 -07:00
Steve Myers
2abe7205cb Add FfiResultVoid type 2021-07-03 19:24:29 -07:00
Steve Myers
3e31e9aca3 Remove unneeded pointers from FfiResult types 2021-07-03 19:07:49 -07:00
Steve Myers
a056c0dd59 Reorganized code into wallet mod/package 2021-07-03 10:16:02 -07:00
Steve Myers
060e54a718 Refactor to return results by value, add wallet list_unspent and related types 2021-07-02 21:28:26 -07:00
Steve Myers
59fe24818a Add LibTest getTestDataDir to fix sled test on android 2021-06-26 18:55:49 -07:00
Steve Myers
91ae8dd537 Add kotlin BlockchainConfig and DatabaseConfig 2021-06-25 23:40:38 -07:00
Steve Myers
13e7217ffd Simplify Kotlin Wallet api 2021-06-24 15:00:00 -07:00
Steve Myers
af828efa93 Update build.sh to publish to local maven repo 2021-06-23 14:20:04 -07:00
Steve Myers
0f7a4aebf8 Fix Kotlin jar: native library path 2021-06-23 14:13:33 -07:00
Steve Myers
9f29eb0e86 Add classes to wrap LibJna native types 2021-06-22 11:53:09 -07:00
Steve Myers
3a5d4816ac Add jna lib to jvm jar resources 2021-06-21 15:08:39 -07:00
Steve Myers
2b40718875 Add kotlin test-fixtures module used by jvm and android 2021-06-20 20:26:13 -07:00
Steve Myers
36333b9fb7 Rename gradle modules to jvm and android 2021-06-20 18:48:48 -07:00
Steve Myers
f6c10da805 Return results as opaque structs from ffi calls 2021-06-20 15:48:06 -07:00
Steve Myers
76087b9aec Add kotlin/aar android device tests 2021-06-14 22:38:29 -07:00
Steve Myers
43ddf0a3b1 Execute bdk_ffi_test via valgrind 2021-06-14 14:18:16 -07:00
Steve Myers
5303de9593 Rename bdk-kotlin companion project, fix gradle warnings 2021-06-14 13:59:56 -07:00
Steve Myers
333f694d55 Remove unneeded test structs and functions, cleanup tests 2021-06-10 17:22:33 -07:00
Steve Myers
308d4af4f1 Fix kotlin wallet struct access via JNA opaque pointer 2021-06-10 13:41:46 -07:00
Steve Myers
2aad5d4428 Add missing kotlin files 2021-06-09 16:00:40 -07:00
Steve Myers
f31ebaa1e6 Test new, print, and free Config works 2021-06-08 18:15:20 -07:00
Steve Myers
43425c8875 Pass wallet by ref 2021-06-04 23:04:19 -07:00
Steve Myers
cb54405aed Fix bdk features 2021-06-04 23:01:28 -07:00
Steve Myers
49126a8943 Add strings example 2021-06-04 18:03:34 -07:00
Steve Myers
ec9d2ea284 Set safer-ffi version 2021-06-04 18:01:47 -07:00
Steve Myers
f07f0248ef Add build.sh 2021-06-04 18:00:55 -07:00
Steve Myers
d14ea9a059 Add WalletPtr 2021-06-04 11:07:51 -07:00
11 changed files with 693 additions and 63 deletions

29
.editorconfig Normal file
View File

@@ -0,0 +1,29 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.rs]
indent_size = 4
[*.kt]
indent_size = 4
[*.gradle]
indent_size = 4
[tests/**/*.rs]
charset = utf-8
end_of_line = unset
indent_size = unset
indent_style = unset
trim_trailing_whitespace = unset
insert_final_newline = unset

20
.gitignore vendored
View File

@@ -1,4 +1,16 @@
/target
*.h
/main
/Cargo.lock
target
build
Cargo.lock
/bindings/bdk-kotlin/local.properties
.gradle
wallet_db
bdk_ffi_test
local.properties
*.log
*.dylib
*.so
.DS_Store
testdb
xcuserdata
.lsp
.clj-kondo

23
CHANGELOG.md Normal file
View File

@@ -0,0 +1,23 @@
# 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.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]
[v0.2.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.0.0...v0.2.0
[v0.3.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.2.0...v0.3.0
[unreleased]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.3.0...HEAD

View File

@@ -1,16 +1,28 @@
[package]
name = "bdk_ffi"
version = "0.1.0"
authors = ["Steve Myers <steve@notmandatory.org>"]
name = "bdk-ffi"
version = "0.3.1"
authors = ["Steve Myers <steve@notmandatory.org>", "Sudarsan Balaji <sudarsan.balaji@artfuldev.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["staticlib"]
crate-type = ["staticlib", "cdylib"]
name = "bdkffi"
[dependencies]
bdk = { version = "^0.7", feature = ["all-keys"] }
safer-ffi = { version = "*", features = ["proc_macros"]}
bdk = { version = "0.14", features = ["all-keys", "use-esplora-ureq"] }
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 = { version = "0.16.0", features = ["builtin-bindgen"] }
[features]
c-headers = ["safer-ffi/headers"]
generate-python = ["uniffi_bindgen"]
[[bin]]
name = "generate"

67
README.md Normal file
View File

@@ -0,0 +1,67 @@
# Native language bindings for BDK
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
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] |
[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
[bdk-kotlin]: https://github.com/bitcoindevkit/bdk-kotlin
[bdk-swift]: https://github.com/bitcoindevkit/bdk-swift
[bdk-python]: https://github.com/thunderbiscuit/bdk-python
## Contributing
### Install uniffi-bindgen cli tool
Install the uniffi-bindgen binary on your system using:
`cargo install uniffi_bindgen`
The version must be the same as the `uniffi` dependency in `Cargo.toml`.
### Adding new structs and functions
See the [UniFFI User Guide](https://mozilla.github.io/uniffi-rs/)
#### For pass by value objects
1. create new rust struct with only fields that are supported UniFFI types
1. update mapping `bdk.udl` file with new `dictionary`
#### For pass by reference values
1. create wrapper rust struct/impl with only fields that are `Sync + Send`
1. update mapping `bdk.udl` file with new `interface`
## Goals
1. Language bindings should feel idiomatic in target languages/platforms
1. Adding new targets should be easy
1. Getting up and running should be easy
1. Contributing should be easy
1. Get it right, then automate
## Thanks
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

3
build.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
uniffi_build::generate_scaffolding("src/bdk.udl").unwrap();
}

13
main.c
View File

@@ -1,13 +0,0 @@
#include <stdlib.h>
#include "bdk_ffi.h"
int main (int argc, char const * const argv[])
{
Point_t * a = new_point(84,45);
Point_t * b = new_point(0.0,39.0);
Point_t * m = mid_point(a, b);
print_point(m);
print_point(NULL);
return EXIT_SUCCESS;
}

151
src/bdk.udl Normal file
View File

@@ -0,0 +1,151 @@
namespace bdk {
[Throws=BdkError]
ExtendedKeyInfo generate_extended_key(Network network, WordCount word_count, string? password);
[Throws=BdkError]
ExtendedKeyInfo restore_extended_key(Network network, string mnemonic, string? password);
};
[Error]
enum BdkError {
"InvalidU32Bytes",
"Generic",
"ScriptDoesntHaveAddressForm",
"NoRecipients",
"NoUtxosSelected",
"OutputBelowDustLimit",
"InsufficientFunds",
"BnBTotalTriesExceeded",
"BnBNoExactMatch",
"UnknownUtxo",
"TransactionNotFound",
"TransactionConfirmed",
"IrreplaceableTransaction",
"FeeRateTooLow",
"FeeTooLow",
"FeeRateUnavailable",
"MissingKeyOrigin",
"Key",
"ChecksumMismatch",
"SpendingPolicyRequired",
"InvalidPolicyPathError",
"Signer",
"InvalidNetwork",
"InvalidProgressValue",
"ProgressUpdateError",
"InvalidOutpoint",
"Descriptor",
"AddressValidator",
"Encode",
"Miniscript",
"Bip32",
"Secp256k1",
"Json",
"Hex",
"Psbt",
"PsbtParse",
"Electrum",
"Esplora",
"Sled",
};
enum Network {
"Bitcoin",
"Testnet",
"Signet",
"Regtest",
};
dictionary SledDbConfiguration {
string path;
string tree_name;
};
[Enum]
interface DatabaseConfig {
Memory(string junk);
Sled(SledDbConfiguration config);
};
dictionary TransactionDetails {
u64? fees;
u64 received;
u64 sent;
string txid;
};
dictionary BlockTime {
u32 height;
u64 timestamp;
};
[Enum]
interface Transaction {
Unconfirmed(TransactionDetails details);
Confirmed(TransactionDetails details, BlockTime confirmation);
};
dictionary ElectrumConfig {
string url;
string? socks5;
u8 retry;
u8? timeout;
u64 stop_gap;
};
dictionary EsploraConfig {
string base_url;
string? proxy;
u64 timeout_read;
u64 timeout_write;
u64 stop_gap;
};
[Enum]
interface BlockchainConfig {
Electrum(ElectrumConfig config);
Esplora(EsploraConfig config);
};
callback interface BdkProgress {
void update(f32 progress, string? message);
};
interface Wallet {
[Throws=BdkError]
constructor(string descriptor, string? change_descriptor, Network network, DatabaseConfig database_config, BlockchainConfig blockchain_config);
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();
Network get_network();
[Throws=BdkError]
void sync(BdkProgress progress_update, u32? max_address_param);
[Throws=BdkError]
Transaction broadcast([ByRef] PartiallySignedBitcoinTransaction psbt);
};
interface PartiallySignedBitcoinTransaction {
[Throws=BdkError]
constructor([ByRef] Wallet wallet, string recipient, u64 amount, float? fee_rate);
[Name=deserialize,Throws=BdkError]
constructor(string psbt_base64);
string serialize();
};
dictionary ExtendedKeyInfo {
string mnemonic;
string xprv;
string fingerprint;
};
enum WordCount {
"Words12",
"Words15",
"Words18",
"Words21",
"Words24",
};

67
src/bin/generate.rs Normal file
View 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(())
}

View File

@@ -1,47 +1,314 @@
use ::safer_ffi::prelude::*;
use bdk::bitcoin::secp256k1::Secp256k1;
use bdk::bitcoin::util::psbt::PartiallySignedTransaction;
use bdk::bitcoin::{Address, Network};
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
use bdk::blockchain::Progress;
use bdk::blockchain::{
electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain,
};
use bdk::database::any::{AnyDatabase, SledDbConfiguration};
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
use bdk::keys::{DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey};
use bdk::miniscript::BareCtx;
use bdk::wallet::AddressIndex;
use bdk::{BlockTime, Error, FeeRate, SignOptions, Wallet as BdkWallet};
use std::convert::TryFrom;
use std::str::FromStr;
use std::sync::{Mutex, MutexGuard};
/// A `struct` usable from both Rust and C
#[derive_ReprC]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Point {
x: f64,
y: f64,
uniffi_macros::include_scaffolding!("bdk");
type BdkError = Error;
pub enum DatabaseConfig {
Memory { junk: String },
Sled { config: SledDbConfiguration },
}
/* Export a Rust function to the C world. */
/// Returns the middle point of `[a, b]`.
#[ffi_export]
fn mid_point(a: Option<repr_c::Box<Point>>, b: Option<repr_c::Box<Point>>) -> repr_c::Box<Point> {
let a = a.unwrap();
let b = b.unwrap();
repr_c::Box::new(Point {
x: (a.x + b.x) / 2.,
y: (a.y + b.y) / 2.,
pub struct ElectrumConfig {
pub url: String,
pub socks5: Option<String>,
pub retry: u8,
pub timeout: Option<u8>,
pub stop_gap: u64,
}
pub struct EsploraConfig {
pub base_url: String,
pub proxy: Option<String>,
pub timeout_read: u64,
pub timeout_write: u64,
pub stop_gap: u64,
}
pub enum BlockchainConfig {
Electrum { config: ElectrumConfig },
Esplora { config: EsploraConfig },
}
trait WalletHolder<B> {
fn get_wallet(&self) -> MutexGuard<BdkWallet<B, AnyDatabase>>;
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct TransactionDetails {
pub fees: Option<u64>,
pub received: u64,
pub sent: u64,
pub txid: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Transaction {
Unconfirmed {
details: TransactionDetails,
},
Confirmed {
details: TransactionDetails,
confirmation: BlockTime,
},
}
impl From<&bdk::TransactionDetails> for TransactionDetails {
fn from(x: &bdk::TransactionDetails) -> TransactionDetails {
TransactionDetails {
fees: x.fee,
txid: x.txid.to_string(),
received: x.received,
sent: x.sent,
}
}
}
impl From<&bdk::TransactionDetails> for Transaction {
fn from(x: &bdk::TransactionDetails) -> Transaction {
match x.confirmation_time.clone() {
Some(block_time) => Transaction::Confirmed {
details: TransactionDetails::from(x),
confirmation: block_time,
},
None => Transaction::Unconfirmed {
details: TransactionDetails::from(x),
},
}
}
}
trait WalletOperations<B>: WalletHolder<B> {
fn get_new_address(&self) -> String {
self.get_wallet()
.get_address(AddressIndex::New)
.unwrap()
.address
.to_string()
}
fn get_last_unused_address(&self) -> String {
self.get_wallet()
.get_address(AddressIndex::LastUnused)
.unwrap()
.address
.to_string()
}
fn get_balance(&self) -> Result<u64, Error> {
self.get_wallet().get_balance()
}
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 {
true => Ok(()),
false => Err(BdkError::Generic(format!(
"transaction signing not finalized {:?}",
psbt
))),
}
}
fn get_transactions(&self) -> Result<Vec<Transaction>, Error> {
let transactions = self.get_wallet().list_transactions(true)?;
Ok(transactions.iter().map(Transaction::from).collect())
}
}
struct Wallet {
wallet_mutex: Mutex<BdkWallet<AnyBlockchain, AnyDatabase>>,
}
pub trait BdkProgress: Send + Sync {
fn update(&self, progress: f32, message: Option<String>);
}
struct BdkProgressHolder {
progress_update: Box<dyn BdkProgress>,
}
impl Progress for BdkProgressHolder {
fn update(&self, progress: f32, message: Option<String>) -> Result<(), Error> {
self.progress_update.update(progress, message);
Ok(())
}
}
struct PartiallySignedBitcoinTransaction {
internal: Mutex<PartiallySignedTransaction>,
}
impl PartiallySignedBitcoinTransaction {
fn new(
wallet: &Wallet,
recipient: String,
amount: u64,
fee_rate: Option<f32>, // satoshis per vbyte
) -> Result<Self, Error> {
let wallet = wallet.get_wallet();
match Address::from_str(&recipient) {
Ok(address) => {
let (psbt, _details) = {
let mut builder = wallet.build_tx();
builder.add_recipient(address.script_pubkey(), amount);
if let Some(sat_per_vb) = fee_rate {
builder.fee_rate(FeeRate::from_sat_per_vb(sat_per_vb));
}
builder.finish()?
};
Ok(PartiallySignedBitcoinTransaction {
internal: Mutex::new(psbt),
})
}
Err(..) => Err(BdkError::Generic(
"failed to read wallet address".to_string(),
)),
}
}
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 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>,
network: Network,
database_config: DatabaseConfig,
blockchain_config: BlockchainConfig,
) -> Result<Self, BdkError> {
let any_database_config = match database_config {
DatabaseConfig::Memory { .. } => AnyDatabaseConfig::Memory(()),
DatabaseConfig::Sled { config } => AnyDatabaseConfig::Sled(config),
};
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(),
})
}
BlockchainConfig::Esplora { config } => {
AnyBlockchainConfig::Esplora(EsploraBlockchainConfig {
base_url: config.base_url,
proxy: config.proxy,
timeout_read: config.timeout_read,
timeout_write: config.timeout_write,
stop_gap: usize::try_from(config.stop_gap).unwrap(),
})
}
};
let database = AnyDatabase::from_config(&any_database_config)?;
let blockchain = AnyBlockchain::from_config(&any_blockchain_config)?;
let wallet_mutex = Mutex::new(BdkWallet::new(
&descriptor,
change_descriptor.to_owned().as_ref(),
network,
database,
blockchain,
)?);
Ok(Wallet { wallet_mutex })
}
fn get_network(&self) -> Network {
self.get_wallet().network()
}
fn sync(
&self,
progress_update: Box<dyn BdkProgress>,
max_address_param: Option<u32>,
) -> Result<(), BdkError> {
self.get_wallet()
.sync(BdkProgressHolder { progress_update }, max_address_param)
}
fn broadcast(&self, psbt: &PartiallySignedBitcoinTransaction) -> Result<Transaction, Error> {
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
self.get_wallet().broadcast(&tx)?;
let tx_details = self.get_wallet().get_tx(&tx.txid(), true)?;
Ok(Transaction::from(&tx_details.unwrap()))
}
}
pub struct ExtendedKeyInfo {
mnemonic: String,
xprv: String,
fingerprint: String,
}
fn generate_extended_key(
network: Network,
word_count: WordCount,
password: Option<String>,
) -> Result<ExtendedKeyInfo, Error> {
let mnemonic: GeneratedKey<_, BareCtx> =
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();
let fingerprint = xprv.fingerprint(&Secp256k1::new());
Ok(ExtendedKeyInfo {
mnemonic: mnemonic.to_string(),
xprv: xprv.to_string(),
fingerprint: fingerprint.to_string(),
})
}
/// Pretty-prints a point using Rust's formatting logic.
#[ffi_export]
fn print_point(point: Option<repr_c::Box<Point>>) {
println!("{:?}", point);
fn restore_extended_key(
network: Network,
mnemonic: String,
password: Option<String>,
) -> Result<ExtendedKeyInfo, Error> {
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());
Ok(ExtendedKeyInfo {
mnemonic: mnemonic.to_string(),
xprv: xprv.to_string(),
fingerprint: fingerprint.to_string(),
})
}
#[ffi_export]
fn new_point(x: f64, y: f64) -> repr_c::Box<Point> {
repr_c::Box::new(Point { x, y })
}
#[ffi_export]
fn free_point(point: Option<repr_c::Box<Point>>) {
drop(point)
}
/// The following test function is necessary for the header generation.
#[::safer_ffi::cfg_headers]
#[test]
fn generate_headers() -> ::std::io::Result<()> {
::safer_ffi::headers::builder()
.to_file("bdk_ffi.h")?
.generate()
}
uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);

12
uniffi.toml Normal file
View File

@@ -0,0 +1,12 @@
[bindings.kotlin]
package_name = "org.bitcoindevkit"
cdylib_name = "bdkffi"
[bindings.python]
cdylib_name = "bdkffi"
[bindings.ruby]
cdylib_name = "bdkffi"
[bindings.swift]
cdylib_name = "bdkffi"