Remove non-kotlin related files, add bdk-ffi as submodule, update build.sh
This commit is contained in:
parent
09ce971708
commit
0f42ba7590
2
.gitignore
vendored
2
.gitignore
vendored
@ -14,3 +14,5 @@ testdb
|
|||||||
xcuserdata
|
xcuserdata
|
||||||
.lsp
|
.lsp
|
||||||
.clj-kondo
|
.clj-kondo
|
||||||
|
.idea
|
||||||
|
bdk.kt
|
||||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "bdk-ffi"]
|
||||||
|
path = bdk-ffi
|
||||||
|
url = git@github.com:bitcoindevkit/bdk-ffi.git
|
20
Cargo.toml
20
Cargo.toml
@ -1,20 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "bdk-ffi"
|
|
||||||
version = "0.1.0"
|
|
||||||
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", "cdylib"]
|
|
||||||
name = "bdkffi"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bdk = { version = "0.13", features = ["all-keys", "use-esplora-ureq"] }
|
|
||||||
uniffi_macros = "0.14.1"
|
|
||||||
uniffi = "0.14.1"
|
|
||||||
thiserror = "1.0"
|
|
||||||
anyhow = "=1.0.45" # remove after upgrading to next version of uniffi
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
uniffi_build = "0.14.1"
|
|
1
bdk-ffi
Submodule
1
bdk-ffi
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit e4d53b5e4b213e484bf4b76a4bf33884dd68f086
|
7
bindings/bdk-kotlin/.gitignore
vendored
7
bindings/bdk-kotlin/.gitignore
vendored
@ -1,7 +0,0 @@
|
|||||||
.idea
|
|
||||||
.gradle
|
|
||||||
local.properties
|
|
||||||
build
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
bdk.kt
|
|
3
build.rs
3
build.rs
@ -1,3 +0,0 @@
|
|||||||
fn main() {
|
|
||||||
uniffi_build::generate_scaffolding("src/bdk.udl").unwrap();
|
|
||||||
}
|
|
154
build.sh
154
build.sh
@ -1,107 +1,65 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
# functions
|
echo "Build and test bdk-ffi library for local platform (darwin or linux)"
|
||||||
|
pushd bdk-ffi
|
||||||
|
|
||||||
## help
|
cargo fmt
|
||||||
help()
|
cargo build --release
|
||||||
{
|
cargo test
|
||||||
# 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
|
|
||||||
}
|
|
||||||
|
|
||||||
## rust
|
|
||||||
build_rust() {
|
|
||||||
echo "Build Rust library"
|
|
||||||
cargo fmt
|
|
||||||
cargo build --release
|
|
||||||
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/release/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/release/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
|
|
||||||
}
|
|
||||||
|
|
||||||
## 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 --release --target=aarch64-linux-android
|
|
||||||
cp target/aarch64-linux-android/release/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 --release --target=x86_64-linux-android
|
|
||||||
cp target/x86_64-linux-android/release/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 --release --target=i686-linux-android
|
|
||||||
cp target/i686-linux-android/release/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)
|
OS=$(uname)
|
||||||
|
echo -n "Copy "
|
||||||
|
case $OS in
|
||||||
|
"Darwin")
|
||||||
|
echo -n "darwin "
|
||||||
|
mkdir -p ../jvm/src/main/resources/darwin-x86-64
|
||||||
|
cp target/release/libbdkffi.dylib ../jvm/src/main/resources/darwin-x86-64
|
||||||
|
;;
|
||||||
|
"Linux")
|
||||||
|
echo -n "linux "
|
||||||
|
mkdir -p ../jvm/src/main/resources/linux-x86-64
|
||||||
|
cp target/release/libbdkffi.so ../jvm/src/main/resources/linux-x86-64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "libs to jvm subproject"
|
||||||
|
|
||||||
if [ "$1" == "-h" ]
|
echo "Generate kotlin bindings from bdk.udl to jvm subproject"
|
||||||
then
|
uniffi-bindgen generate src/bdk.udl --no-format --out-dir ../jvm/src/main/kotlin --language kotlin
|
||||||
help
|
|
||||||
else
|
|
||||||
build_rust
|
|
||||||
|
|
||||||
while [ -n "$1" ]; do # while loop starts
|
## android
|
||||||
case "$1" in
|
|
||||||
-a) build_android ;;
|
# If ANDROID_NDK_HOME is not set then set it to github actions default
|
||||||
-k) build_kotlin ;;
|
[ -z "$ANDROID_NDK_HOME" ] && export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle
|
||||||
-h) help ;;
|
|
||||||
*) echo "Option $1 not recognized" ;;
|
# Update this line accordingly if you are not building *from* darwin-x86_64 or linux-x86_64
|
||||||
esac
|
export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/`uname | tr '[:upper:]' '[:lower:]'`-x86_64/bin
|
||||||
shift
|
|
||||||
done
|
# 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 ../android/src/main/jniLibs/arm64-v8a ../android/src/main/jniLibs/x86_64 ../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 --release --target=aarch64-linux-android
|
||||||
|
cp target/aarch64-linux-android/release/libbdkffi.so ../android/src/main/jniLibs/arm64-v8a
|
||||||
fi
|
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 --release --target=x86_64-linux-android
|
||||||
|
cp target/x86_64-linux-android/release/libbdkffi.so ../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 --release --target=i686-linux-android
|
||||||
|
cp target/i686-linux-android/release/libbdkffi.so ../android/src/main/jniLibs/x86
|
||||||
|
fi
|
||||||
|
|
||||||
|
popd
|
||||||
|
|
||||||
|
# copy bdk-ffi kotlin binding sources from jvm to android
|
||||||
|
cp -R jvm/src/main/kotlin android/src/main
|
||||||
|
|
||||||
|
# bdk-kotlin build jar and aar subprojects
|
||||||
|
./gradlew build
|
||||||
|
0
bindings/bdk-kotlin/gradlew → gradlew
vendored
0
bindings/bdk-kotlin/gradlew → gradlew
vendored
178
bindings/bdk-kotlin/gradlew.bat → gradlew.bat
vendored
178
bindings/bdk-kotlin/gradlew.bat → gradlew.bat
vendored
@ -1,89 +1,89 @@
|
|||||||
@rem
|
@rem
|
||||||
@rem Copyright 2015 the original author or authors.
|
@rem Copyright 2015 the original author or authors.
|
||||||
@rem
|
@rem
|
||||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@rem you may not use this file except in compliance with the License.
|
@rem you may not use this file except in compliance with the License.
|
||||||
@rem You may obtain a copy of the License at
|
@rem You may obtain a copy of the License at
|
||||||
@rem
|
@rem
|
||||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
@rem
|
@rem
|
||||||
@rem Unless required by applicable law or agreed to in writing, software
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
@if "%DEBUG%" == "" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem Gradle startup script for Windows
|
||||||
@rem
|
@rem
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables with windows NT shell
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto execute
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
echo.
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation.
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
echo.
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation.
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
rem the _cmd.exe /c_ return code!
|
rem the _cmd.exe /c_ return code!
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
exit /b 1
|
exit /b 1
|
||||||
|
|
||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
:omega
|
:omega
|
167
src/bdk.udl
167
src/bdk.udl
@ -1,167 +0,0 @@
|
|||||||
namespace bdk {
|
|
||||||
[Throws=BdkError]
|
|
||||||
ExtendedKeyInfo generate_extended_key(Network network, MnemonicType mnemonic_type, 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 Confirmation {
|
|
||||||
u32 height;
|
|
||||||
u64 timestamp;
|
|
||||||
};
|
|
||||||
|
|
||||||
[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();
|
|
||||||
};
|
|
||||||
|
|
||||||
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 OnlineWallet {
|
|
||||||
[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]
|
|
||||||
u64 get_balance();
|
|
||||||
[Throws=BdkError]
|
|
||||||
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);
|
|
||||||
[Throws=BdkError]
|
|
||||||
Transaction broadcast([ByRef] PartiallySignedBitcoinTransaction psbt);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface PartiallySignedBitcoinTransaction {
|
|
||||||
[Throws=BdkError]
|
|
||||||
constructor([ByRef] OnlineWallet wallet, string recipient, u64 amount, float? fee_rate);
|
|
||||||
};
|
|
||||||
|
|
||||||
dictionary ExtendedKeyInfo {
|
|
||||||
string mnemonic;
|
|
||||||
string xprv;
|
|
||||||
string fingerprint;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum MnemonicType {
|
|
||||||
"Words12",
|
|
||||||
"Words15",
|
|
||||||
"Words18",
|
|
||||||
"Words21",
|
|
||||||
"Words24",
|
|
||||||
};
|
|
340
src/lib.rs
340
src/lib.rs
@ -1,340 +0,0 @@
|
|||||||
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, MnemonicType};
|
|
||||||
use bdk::keys::{DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey};
|
|
||||||
use bdk::miniscript::BareCtx;
|
|
||||||
use bdk::wallet::AddressIndex;
|
|
||||||
use bdk::{ConfirmationTime, Error, FeeRate, SignOptions, Wallet};
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::sync::{Mutex, MutexGuard};
|
|
||||||
|
|
||||||
uniffi_macros::include_scaffolding!("bdk");
|
|
||||||
|
|
||||||
type BdkError = Error;
|
|
||||||
|
|
||||||
pub enum DatabaseConfig {
|
|
||||||
Memory { junk: String },
|
|
||||||
Sled { config: SledDbConfiguration },
|
|
||||||
}
|
|
||||||
|
|
||||||
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<Wallet<B, AnyDatabase>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OfflineWallet {
|
|
||||||
wallet: Mutex<Wallet<(), AnyDatabase>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WalletHolder<()> for OfflineWallet {
|
|
||||||
fn get_wallet(&self) -> MutexGuard<Wallet<(), AnyDatabase>> {
|
|
||||||
self.wallet.lock().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
|
||||||
pub struct TransactionDetails {
|
|
||||||
pub fees: Option<u64>,
|
|
||||||
pub received: u64,
|
|
||||||
pub sent: u64,
|
|
||||||
pub txid: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Confirmation = ConfirmationTime;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Transaction {
|
|
||||||
Unconfirmed {
|
|
||||||
details: TransactionDetails,
|
|
||||||
},
|
|
||||||
Confirmed {
|
|
||||||
details: TransactionDetails,
|
|
||||||
confirmation: Confirmation,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
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(confirmation) => Transaction::Confirmed {
|
|
||||||
details: TransactionDetails::from(x),
|
|
||||||
confirmation,
|
|
||||||
},
|
|
||||||
None => Transaction::Unconfirmed {
|
|
||||||
details: TransactionDetails::from(x),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait OfflineWalletOperations<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<'a>(&self, psbt: &'a 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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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>,
|
|
||||||
details: bdk::TransactionDetails,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartiallySignedBitcoinTransaction {
|
|
||||||
fn new(
|
|
||||||
online_wallet: &OnlineWallet,
|
|
||||||
recipient: String,
|
|
||||||
amount: u64,
|
|
||||||
fee_rate: Option<f32>, // satoshis per vbyte
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let wallet = online_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),
|
|
||||||
details,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(..) => Err(BdkError::Generic(
|
|
||||||
"failed to read wallet address".to_string(),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OnlineWallet {
|
|
||||||
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::new(Wallet::new(
|
|
||||||
&descriptor,
|
|
||||||
change_descriptor.to_owned().as_ref(),
|
|
||||||
network,
|
|
||||||
database,
|
|
||||||
blockchain,
|
|
||||||
)?);
|
|
||||||
Ok(OnlineWallet { wallet })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_network(&self) -> Network {
|
|
||||||
self.wallet.lock().unwrap().network()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync(
|
|
||||||
&self,
|
|
||||||
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()
|
|
||||||
.sync(BdkProgressHolder { progress_update }, max_address_param)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn broadcast<'a>(
|
|
||||||
&self,
|
|
||||||
psbt: &'a PartiallySignedBitcoinTransaction,
|
|
||||||
) -> Result<Transaction, Error> {
|
|
||||||
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
|
|
||||||
self.get_wallet().broadcast(tx)?;
|
|
||||||
Ok(Transaction::from(&psbt.details))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
fingerprint: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_extended_key(
|
|
||||||
network: Network,
|
|
||||||
mnemonic_type: MnemonicType,
|
|
||||||
password: Option<String>,
|
|
||||||
) -> Result<ExtendedKeyInfo, Error> {
|
|
||||||
let mnemonic: GeneratedKey<_, BareCtx> =
|
|
||||||
Mnemonic::generate((mnemonic_type, 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(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn restore_extended_key(
|
|
||||||
network: Network,
|
|
||||||
mnemonic: String,
|
|
||||||
password: Option<String>,
|
|
||||||
) -> Result<ExtendedKeyInfo, Error> {
|
|
||||||
let mnemonic = Mnemonic::from_phrase(mnemonic.as_ref(), Language::English).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(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
uniffi::deps::static_assertions::assert_impl_all!(OfflineWallet: Sync, Send);
|
|
||||||
uniffi::deps::static_assertions::assert_impl_all!(OnlineWallet: 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
|
|
12
uniffi.toml
12
uniffi.toml
@ -1,12 +0,0 @@
|
|||||||
[bindings.kotlin]
|
|
||||||
package_name = "org.bitcoindevkit"
|
|
||||||
cdylib_name = "bdkffi"
|
|
||||||
|
|
||||||
[bindings.python]
|
|
||||||
cdylib_name = "bdkffi"
|
|
||||||
|
|
||||||
[bindings.ruby]
|
|
||||||
cdylib_name = "bdkffi"
|
|
||||||
|
|
||||||
[bindings.swift]
|
|
||||||
cdylib_name = "bdkffi"
|
|
Loading…
x
Reference in New Issue
Block a user