Compare commits
1 Commits
v0.11.0
...
release/0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6cf423721 |
2
.github/workflows/cont_integration.yml
vendored
2
.github/workflows/cont_integration.yml
vendored
@@ -41,7 +41,7 @@ jobs:
|
|||||||
if: ${{ matrix.rust.clippy }}
|
if: ${{ matrix.rust.clippy }}
|
||||||
run: cargo clippy --all-targets -- -D warnings
|
run: cargo clippy --all-targets -- -D warnings
|
||||||
- name: Test
|
- name: Test
|
||||||
run: CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test
|
run: cargo test
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
name: Rust fmt
|
name: Rust fmt
|
||||||
|
|||||||
14
Cargo.toml
14
Cargo.toml
@@ -1,31 +1,23 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bdk-ffi"
|
name = "bdk-ffi"
|
||||||
version = "0.11.0"
|
version = "0.10.0"
|
||||||
authors = ["Steve Myers <steve@notmandatory.org>", "Sudarsan Balaji <sudarsan.balaji@artfuldev.com>"]
|
authors = ["Steve Myers <steve@notmandatory.org>", "Sudarsan Balaji <sudarsan.balaji@artfuldev.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT OR Apache-2.0"
|
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [".","bdk-ffi-bindgen"]
|
members = [".","bdk-ffi-bindgen"]
|
||||||
default-members = [".", "bdk-ffi-bindgen"]
|
default-members = [".", "bdk-ffi-bindgen"]
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["staticlib", "cdylib"]
|
crate-type = ["staticlib", "cdylib"]
|
||||||
name = "bdkffi"
|
name = "bdkffi"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bdk = { version = "0.24", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled"] }
|
bdk = { version = "0.23", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled"] }
|
||||||
|
|
||||||
uniffi_macros = { version = "0.21.0", features = ["builtin-bindgen"] }
|
uniffi_macros = { version = "0.21.0", features = ["builtin-bindgen"] }
|
||||||
uniffi = { version = "0.21.0", features = ["builtin-bindgen"] }
|
uniffi = { version = "0.21.0", features = ["builtin-bindgen"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
uniffi_build = { version = "0.21.0", features = ["builtin-bindgen"] }
|
uniffi_build = { version = "0.21.0", features = ["builtin-bindgen"] }
|
||||||
|
|
||||||
[profile.release-smaller]
|
|
||||||
inherits = "release"
|
|
||||||
opt-level = 'z' # Optimize for size.
|
|
||||||
lto = true # Enable Link Time Optimization
|
|
||||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
|
||||||
panic = 'abort' # Abort on panic
|
|
||||||
strip = true # Strip symbols from binary*
|
|
||||||
|
|||||||
43
src/bdk.udl
43
src/bdk.udl
@@ -1,5 +1,6 @@
|
|||||||
namespace bdk {
|
namespace bdk {
|
||||||
|
[Throws=BdkError]
|
||||||
|
string generate_mnemonic(WordCount word_count);
|
||||||
};
|
};
|
||||||
|
|
||||||
[Error]
|
[Error]
|
||||||
@@ -32,9 +33,9 @@ enum BdkError {
|
|||||||
"ProgressUpdateError",
|
"ProgressUpdateError",
|
||||||
"InvalidOutpoint",
|
"InvalidOutpoint",
|
||||||
"Descriptor",
|
"Descriptor",
|
||||||
|
"AddressValidator",
|
||||||
"Encode",
|
"Encode",
|
||||||
"Miniscript",
|
"Miniscript",
|
||||||
"MiniscriptPsbt",
|
|
||||||
"Bip32",
|
"Bip32",
|
||||||
"Secp256k1",
|
"Secp256k1",
|
||||||
"Json",
|
"Json",
|
||||||
@@ -137,7 +138,7 @@ interface Blockchain {
|
|||||||
constructor(BlockchainConfig config);
|
constructor(BlockchainConfig config);
|
||||||
|
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
void broadcast([ByRef] PartiallySignedTransaction psbt);
|
void broadcast([ByRef] PartiallySignedBitcoinTransaction psbt);
|
||||||
|
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
u32 get_height();
|
u32 get_height();
|
||||||
@@ -188,7 +189,7 @@ interface Wallet {
|
|||||||
Balance get_balance();
|
Balance get_balance();
|
||||||
|
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
boolean sign([ByRef] PartiallySignedTransaction psbt);
|
boolean sign([ByRef] PartiallySignedBitcoinTransaction psbt);
|
||||||
|
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
sequence<TransactionDetails> list_transactions();
|
sequence<TransactionDetails> list_transactions();
|
||||||
@@ -202,14 +203,7 @@ interface Wallet {
|
|||||||
sequence<LocalUtxo> list_unspent();
|
sequence<LocalUtxo> list_unspent();
|
||||||
};
|
};
|
||||||
|
|
||||||
interface FeeRate {
|
interface PartiallySignedBitcoinTransaction {
|
||||||
[Name=from_sat_per_vb]
|
|
||||||
constructor(float sat_per_vb);
|
|
||||||
|
|
||||||
float as_sat_per_vb();
|
|
||||||
};
|
|
||||||
|
|
||||||
interface PartiallySignedTransaction {
|
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
constructor(string psbt_base64);
|
constructor(string psbt_base64);
|
||||||
|
|
||||||
@@ -220,15 +214,11 @@ interface PartiallySignedTransaction {
|
|||||||
sequence<u8> extract_tx();
|
sequence<u8> extract_tx();
|
||||||
|
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
PartiallySignedTransaction combine(PartiallySignedTransaction other);
|
PartiallySignedBitcoinTransaction combine(PartiallySignedBitcoinTransaction other);
|
||||||
|
|
||||||
u64? fee_amount();
|
|
||||||
|
|
||||||
FeeRate? fee_rate();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary TxBuilderResult {
|
dictionary TxBuilderResult {
|
||||||
PartiallySignedTransaction psbt;
|
PartiallySignedBitcoinTransaction psbt;
|
||||||
TransactionDetails transaction_details;
|
TransactionDetails transaction_details;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -281,19 +271,7 @@ interface BumpFeeTxBuilder {
|
|||||||
BumpFeeTxBuilder enable_rbf_with_sequence(u32 nsequence);
|
BumpFeeTxBuilder enable_rbf_with_sequence(u32 nsequence);
|
||||||
|
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
PartiallySignedTransaction finish([ByRef] Wallet wallet);
|
PartiallySignedBitcoinTransaction finish([ByRef] Wallet wallet);
|
||||||
};
|
|
||||||
|
|
||||||
interface Mnemonic {
|
|
||||||
constructor(WordCount word_count);
|
|
||||||
|
|
||||||
[Name=from_string, Throws=BdkError]
|
|
||||||
constructor(string mnemonic);
|
|
||||||
|
|
||||||
[Name=from_entropy, Throws=BdkError]
|
|
||||||
constructor(sequence<u8> entropy);
|
|
||||||
|
|
||||||
string as_string();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface DerivationPath {
|
interface DerivationPath {
|
||||||
@@ -302,7 +280,8 @@ interface DerivationPath {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface DescriptorSecretKey {
|
interface DescriptorSecretKey {
|
||||||
constructor(Network network, Mnemonic mnemonic, string? password);
|
[Throws=BdkError]
|
||||||
|
constructor(Network network, string mnemonic, string? password);
|
||||||
|
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
DescriptorSecretKey derive(DerivationPath path);
|
DescriptorSecretKey derive(DerivationPath path);
|
||||||
|
|||||||
147
src/lib.rs
147
src/lib.rs
@@ -3,8 +3,7 @@ use bdk::bitcoin::hashes::hex::ToHex;
|
|||||||
use bdk::bitcoin::secp256k1::Secp256k1;
|
use bdk::bitcoin::secp256k1::Secp256k1;
|
||||||
use bdk::bitcoin::util::bip32::DerivationPath as BdkDerivationPath;
|
use bdk::bitcoin::util::bip32::DerivationPath as BdkDerivationPath;
|
||||||
use bdk::bitcoin::util::psbt::serialize::Serialize;
|
use bdk::bitcoin::util::psbt::serialize::Serialize;
|
||||||
use bdk::bitcoin::util::psbt::PartiallySignedTransaction as BdkPartiallySignedTransaction;
|
use bdk::bitcoin::util::psbt::PartiallySignedTransaction;
|
||||||
use bdk::bitcoin::Sequence;
|
|
||||||
use bdk::bitcoin::{Address as BdkAddress, Network, OutPoint as BdkOutPoint, Txid};
|
use bdk::bitcoin::{Address as BdkAddress, Network, OutPoint as BdkOutPoint, Txid};
|
||||||
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
|
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
|
||||||
use bdk::blockchain::GetBlockHash;
|
use bdk::blockchain::GetBlockHash;
|
||||||
@@ -16,13 +15,12 @@ use bdk::blockchain::{Blockchain as BdkBlockchain, Progress as BdkProgress};
|
|||||||
use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration};
|
use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration};
|
||||||
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
|
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
|
||||||
use bdk::descriptor::DescriptorXKey;
|
use bdk::descriptor::DescriptorXKey;
|
||||||
use bdk::keys::bip39::{Language, Mnemonic as BdkMnemonic, WordCount};
|
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
|
||||||
use bdk::keys::{
|
use bdk::keys::{
|
||||||
DerivableKey, DescriptorPublicKey as BdkDescriptorPublicKey,
|
DerivableKey, DescriptorPublicKey as BdkDescriptorPublicKey,
|
||||||
DescriptorSecretKey as BdkDescriptorSecretKey, ExtendedKey, GeneratableKey, GeneratedKey,
|
DescriptorSecretKey as BdkDescriptorSecretKey, ExtendedKey, GeneratableKey, GeneratedKey,
|
||||||
};
|
};
|
||||||
use bdk::miniscript::BareCtx;
|
use bdk::miniscript::BareCtx;
|
||||||
use bdk::psbt::PsbtUtils;
|
|
||||||
use bdk::wallet::tx_builder::ChangeSpendPolicy;
|
use bdk::wallet::tx_builder::ChangeSpendPolicy;
|
||||||
use bdk::wallet::AddressIndex as BdkAddressIndex;
|
use bdk::wallet::AddressIndex as BdkAddressIndex;
|
||||||
use bdk::wallet::AddressInfo as BdkAddressInfo;
|
use bdk::wallet::AddressInfo as BdkAddressInfo;
|
||||||
@@ -211,7 +209,7 @@ impl Blockchain {
|
|||||||
self.blockchain_mutex.lock().expect("blockchain")
|
self.blockchain_mutex.lock().expect("blockchain")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn broadcast(&self, psbt: &PartiallySignedTransaction) -> Result<(), BdkError> {
|
fn broadcast(&self, psbt: &PartiallySignedBitcoinTransaction) -> Result<(), BdkError> {
|
||||||
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
|
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
|
||||||
self.get_blockchain().broadcast(&tx)
|
self.get_blockchain().broadcast(&tx)
|
||||||
}
|
}
|
||||||
@@ -342,15 +340,14 @@ impl fmt::Debug for ProgressHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PartiallySignedTransaction {
|
pub struct PartiallySignedBitcoinTransaction {
|
||||||
internal: Mutex<BdkPartiallySignedTransaction>,
|
internal: Mutex<PartiallySignedTransaction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartiallySignedTransaction {
|
impl PartiallySignedBitcoinTransaction {
|
||||||
fn new(psbt_base64: String) -> Result<Self, BdkError> {
|
fn new(psbt_base64: String) -> Result<Self, BdkError> {
|
||||||
let psbt: BdkPartiallySignedTransaction =
|
let psbt: PartiallySignedTransaction = PartiallySignedTransaction::from_str(&psbt_base64)?;
|
||||||
BdkPartiallySignedTransaction::from_str(&psbt_base64)?;
|
Ok(PartiallySignedBitcoinTransaction {
|
||||||
Ok(PartiallySignedTransaction {
|
|
||||||
internal: Mutex::new(psbt),
|
internal: Mutex::new(psbt),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -381,30 +378,16 @@ impl PartiallySignedTransaction {
|
|||||||
/// In accordance with BIP 174 this function is commutative i.e., `A.combine(B) == B.combine(A)`
|
/// In accordance with BIP 174 this function is commutative i.e., `A.combine(B) == B.combine(A)`
|
||||||
fn combine(
|
fn combine(
|
||||||
&self,
|
&self,
|
||||||
other: Arc<PartiallySignedTransaction>,
|
other: Arc<PartiallySignedBitcoinTransaction>,
|
||||||
) -> Result<Arc<PartiallySignedTransaction>, BdkError> {
|
) -> Result<Arc<PartiallySignedBitcoinTransaction>, BdkError> {
|
||||||
let other_psbt = other.internal.lock().unwrap().clone();
|
let other_psbt = other.internal.lock().unwrap().clone();
|
||||||
let mut original_psbt = self.internal.lock().unwrap().clone();
|
let mut original_psbt = self.internal.lock().unwrap().clone();
|
||||||
|
|
||||||
original_psbt.combine(other_psbt)?;
|
original_psbt.combine(other_psbt)?;
|
||||||
Ok(Arc::new(PartiallySignedTransaction {
|
Ok(Arc::new(PartiallySignedBitcoinTransaction {
|
||||||
internal: Mutex::new(original_psbt),
|
internal: Mutex::new(original_psbt),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The total transaction fee amount, sum of input amounts minus sum of output amounts, in Sats.
|
|
||||||
/// If the PSBT is missing a TxOut for an input returns None.
|
|
||||||
fn fee_amount(&self) -> Option<u64> {
|
|
||||||
self.internal.lock().unwrap().fee_amount()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The transaction's fee rate. This value will only be accurate if calculated AFTER the
|
|
||||||
/// `PartiallySignedTransaction` is finalized and all witness/signature data is added to the
|
|
||||||
/// transaction.
|
|
||||||
/// If the PSBT is missing a TxOut for an input returns None.
|
|
||||||
fn fee_rate(&self) -> Option<Arc<FeeRate>> {
|
|
||||||
self.internal.lock().unwrap().fee_rate().map(Arc::new)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Bitcoin wallet.
|
/// A Bitcoin wallet.
|
||||||
@@ -476,7 +459,7 @@ impl Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sign a transaction with all the wallet’s signers.
|
/// Sign a transaction with all the wallet’s signers.
|
||||||
fn sign(&self, psbt: &PartiallySignedTransaction) -> Result<bool, BdkError> {
|
fn sign(&self, psbt: &PartiallySignedBitcoinTransaction) -> Result<bool, BdkError> {
|
||||||
let mut psbt = psbt.internal.lock().unwrap();
|
let mut psbt = psbt.internal.lock().unwrap();
|
||||||
self.get_wallet().sign(&mut psbt, SignOptions::default())
|
self.get_wallet().sign(&mut psbt, SignOptions::default())
|
||||||
}
|
}
|
||||||
@@ -548,7 +531,7 @@ enum RbfValue {
|
|||||||
/// The result after calling the TxBuilder finish() function. Contains unsigned PSBT and
|
/// The result after calling the TxBuilder finish() function. Contains unsigned PSBT and
|
||||||
/// transaction details.
|
/// transaction details.
|
||||||
pub struct TxBuilderResult {
|
pub struct TxBuilderResult {
|
||||||
pub psbt: Arc<PartiallySignedTransaction>,
|
pub psbt: Arc<PartiallySignedBitcoinTransaction>,
|
||||||
pub transaction_details: TransactionDetails,
|
pub transaction_details: TransactionDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -775,7 +758,7 @@ impl TxBuilder {
|
|||||||
tx_builder.enable_rbf();
|
tx_builder.enable_rbf();
|
||||||
}
|
}
|
||||||
RbfValue::Value(nsequence) => {
|
RbfValue::Value(nsequence) => {
|
||||||
tx_builder.enable_rbf_with_sequence(Sequence(nsequence));
|
tx_builder.enable_rbf_with_sequence(nsequence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -786,7 +769,7 @@ impl TxBuilder {
|
|||||||
tx_builder
|
tx_builder
|
||||||
.finish()
|
.finish()
|
||||||
.map(|(psbt, tx_details)| TxBuilderResult {
|
.map(|(psbt, tx_details)| TxBuilderResult {
|
||||||
psbt: Arc::new(PartiallySignedTransaction {
|
psbt: Arc::new(PartiallySignedBitcoinTransaction {
|
||||||
internal: Mutex::new(psbt),
|
internal: Mutex::new(psbt),
|
||||||
}),
|
}),
|
||||||
transaction_details: TransactionDetails::from(&tx_details),
|
transaction_details: TransactionDetails::from(&tx_details),
|
||||||
@@ -844,7 +827,7 @@ impl BumpFeeTxBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish building the transaction. Returns the BIP174 PSBT.
|
/// Finish building the transaction. Returns the BIP174 PSBT.
|
||||||
fn finish(&self, wallet: &Wallet) -> Result<Arc<PartiallySignedTransaction>, BdkError> {
|
fn finish(&self, wallet: &Wallet) -> Result<Arc<PartiallySignedBitcoinTransaction>, BdkError> {
|
||||||
let wallet = wallet.get_wallet();
|
let wallet = wallet.get_wallet();
|
||||||
let txid = Txid::from_str(self.txid.as_str())?;
|
let txid = Txid::from_str(self.txid.as_str())?;
|
||||||
let mut tx_builder = wallet.build_fee_bump(txid)?;
|
let mut tx_builder = wallet.build_fee_bump(txid)?;
|
||||||
@@ -861,53 +844,23 @@ impl BumpFeeTxBuilder {
|
|||||||
tx_builder.enable_rbf();
|
tx_builder.enable_rbf();
|
||||||
}
|
}
|
||||||
RbfValue::Value(nsequence) => {
|
RbfValue::Value(nsequence) => {
|
||||||
tx_builder.enable_rbf_with_sequence(Sequence(nsequence));
|
tx_builder.enable_rbf_with_sequence(nsequence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tx_builder
|
tx_builder
|
||||||
.finish()
|
.finish()
|
||||||
.map(|(psbt, _)| PartiallySignedTransaction {
|
.map(|(psbt, _)| PartiallySignedBitcoinTransaction {
|
||||||
internal: Mutex::new(psbt),
|
internal: Mutex::new(psbt),
|
||||||
})
|
})
|
||||||
.map(Arc::new)
|
.map(Arc::new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mnemonic phrases are a human-readable version of the private keys.
|
fn generate_mnemonic(word_count: WordCount) -> Result<String, BdkError> {
|
||||||
/// Supported number of words are 12, 15, 18, 21 and 24.
|
let mnemonic: GeneratedKey<_, BareCtx> =
|
||||||
struct Mnemonic {
|
Mnemonic::generate((word_count, Language::English)).unwrap();
|
||||||
internal: BdkMnemonic,
|
Ok(mnemonic.to_string())
|
||||||
}
|
|
||||||
|
|
||||||
impl Mnemonic {
|
|
||||||
/// Generates Mnemonic with a random entropy
|
|
||||||
fn new(word_count: WordCount) -> Self {
|
|
||||||
let generated_key: GeneratedKey<_, BareCtx> =
|
|
||||||
BdkMnemonic::generate((word_count, Language::English)).unwrap();
|
|
||||||
let mnemonic = BdkMnemonic::parse_in(Language::English, generated_key.to_string()).unwrap();
|
|
||||||
Mnemonic { internal: mnemonic }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a Mnemonic with given string
|
|
||||||
fn from_string(mnemonic: String) -> Result<Self, BdkError> {
|
|
||||||
BdkMnemonic::from_str(&mnemonic)
|
|
||||||
.map(|m| Mnemonic { internal: m })
|
|
||||||
.map_err(|e| BdkError::Generic(e.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new Mnemonic in the specified language from the given entropy.
|
|
||||||
/// Entropy must be a multiple of 32 bits (4 bytes) and 128-256 bits in length.
|
|
||||||
fn from_entropy(entropy: Vec<u8>) -> Result<Self, BdkError> {
|
|
||||||
BdkMnemonic::from_entropy(entropy.as_slice())
|
|
||||||
.map(|m| Mnemonic { internal: m })
|
|
||||||
.map_err(|e| BdkError::Generic(e.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns Mnemonic as string
|
|
||||||
fn as_string(&self) -> String {
|
|
||||||
self.internal.to_string()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DerivationPath {
|
struct DerivationPath {
|
||||||
@@ -929,18 +882,19 @@ struct DescriptorSecretKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DescriptorSecretKey {
|
impl DescriptorSecretKey {
|
||||||
fn new(network: Network, mnemonic: Arc<Mnemonic>, password: Option<String>) -> Self {
|
fn new(network: Network, mnemonic: String, password: Option<String>) -> Result<Self, BdkError> {
|
||||||
let mnemonic = mnemonic.internal.clone();
|
let mnemonic = Mnemonic::parse_in(Language::English, mnemonic)
|
||||||
let xkey: ExtendedKey = (mnemonic, password).into_extended_key().unwrap();
|
.map_err(|e| BdkError::Generic(e.to_string()))?;
|
||||||
|
let xkey: ExtendedKey = (mnemonic, password).into_extended_key()?;
|
||||||
let descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
|
let descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
|
||||||
origin: None,
|
origin: None,
|
||||||
xkey: xkey.into_xprv(network).unwrap(),
|
xkey: xkey.into_xprv(network).unwrap(),
|
||||||
derivation_path: BdkDerivationPath::master(),
|
derivation_path: BdkDerivationPath::master(),
|
||||||
wildcard: bdk::descriptor::Wildcard::Unhardened,
|
wildcard: bdk::descriptor::Wildcard::Unhardened,
|
||||||
});
|
});
|
||||||
Self {
|
Ok(Self {
|
||||||
descriptor_secret_key_mutex: Mutex::new(descriptor_secret_key),
|
descriptor_secret_key_mutex: Mutex::new(descriptor_secret_key),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
|
fn derive(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
|
||||||
@@ -964,7 +918,7 @@ impl DescriptorSecretKey {
|
|||||||
descriptor_secret_key_mutex: Mutex::new(derived_descriptor_secret_key),
|
descriptor_secret_key_mutex: Mutex::new(derived_descriptor_secret_key),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
BdkDescriptorSecretKey::Single(_) => {
|
BdkDescriptorSecretKey::SinglePriv(_) => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -986,7 +940,7 @@ impl DescriptorSecretKey {
|
|||||||
descriptor_secret_key_mutex: Mutex::new(extended_descriptor_secret_key),
|
descriptor_secret_key_mutex: Mutex::new(extended_descriptor_secret_key),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
BdkDescriptorSecretKey::Single(_) => {
|
BdkDescriptorSecretKey::SinglePriv(_) => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -998,7 +952,7 @@ impl DescriptorSecretKey {
|
|||||||
.descriptor_secret_key_mutex
|
.descriptor_secret_key_mutex
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_public(&secp)
|
.as_public(&secp)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Arc::new(DescriptorPublicKey {
|
Arc::new(DescriptorPublicKey {
|
||||||
descriptor_public_key_mutex: Mutex::new(descriptor_public_key),
|
descriptor_public_key_mutex: Mutex::new(descriptor_public_key),
|
||||||
@@ -1012,7 +966,7 @@ impl DescriptorSecretKey {
|
|||||||
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
|
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
|
||||||
descriptor_x_key.xkey.private_key.secret_bytes().to_vec()
|
descriptor_x_key.xkey.private_key.secret_bytes().to_vec()
|
||||||
}
|
}
|
||||||
BdkDescriptorSecretKey::Single(_) => {
|
BdkDescriptorSecretKey::SinglePriv(_) => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1052,7 +1006,7 @@ impl DescriptorPublicKey {
|
|||||||
descriptor_public_key_mutex: Mutex::new(derived_descriptor_public_key),
|
descriptor_public_key_mutex: Mutex::new(derived_descriptor_public_key),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
BdkDescriptorPublicKey::Single(_) => {
|
BdkDescriptorPublicKey::SinglePub(_) => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1074,7 +1028,7 @@ impl DescriptorPublicKey {
|
|||||||
descriptor_public_key_mutex: Mutex::new(extended_descriptor_public_key),
|
descriptor_public_key_mutex: Mutex::new(extended_descriptor_public_key),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
BdkDescriptorPublicKey::Single(_) => {
|
BdkDescriptorPublicKey::SinglePub(_) => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1164,8 +1118,9 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_descriptor_secret_key() -> DescriptorSecretKey {
|
fn get_descriptor_secret_key() -> DescriptorSecretKey {
|
||||||
let mnemonic = Mnemonic::from_string("chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect".to_string()).unwrap();
|
let mnemonic =
|
||||||
DescriptorSecretKey::new(Testnet, Arc::new(mnemonic), None)
|
"chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect".to_string();
|
||||||
|
DescriptorSecretKey::new(Testnet, mnemonic, None).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_dsk(
|
fn derive_dsk(
|
||||||
@@ -1262,32 +1217,4 @@ mod test {
|
|||||||
"e93315d6ce401eb4db803a56232f0ed3e69b053774e6047df54f1bd00e5ea936"
|
"e93315d6ce401eb4db803a56232f0ed3e69b053774e6047df54f1bd00e5ea936"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_psbt_fee() {
|
|
||||||
let test_wpkh = "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)";
|
|
||||||
let (funded_wallet, _, _) = get_funded_wallet(test_wpkh);
|
|
||||||
let test_wallet = Wallet {
|
|
||||||
wallet_mutex: Mutex::new(funded_wallet),
|
|
||||||
};
|
|
||||||
let drain_to_address = "tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt".to_string();
|
|
||||||
let tx_builder = TxBuilder::new()
|
|
||||||
.fee_rate(2.0)
|
|
||||||
.drain_wallet()
|
|
||||||
.drain_to(drain_to_address.clone());
|
|
||||||
//dbg!(&tx_builder);
|
|
||||||
assert!(tx_builder.drain_wallet);
|
|
||||||
assert_eq!(tx_builder.drain_to, Some(drain_to_address));
|
|
||||||
|
|
||||||
let tx_builder_result = tx_builder.finish(&test_wallet).unwrap();
|
|
||||||
|
|
||||||
assert!(tx_builder_result.psbt.fee_rate().is_some());
|
|
||||||
assert_eq!(
|
|
||||||
tx_builder_result.psbt.fee_rate().unwrap().as_sat_per_vb(),
|
|
||||||
2.682927
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(tx_builder_result.psbt.fee_amount().is_some());
|
|
||||||
assert_eq!(tx_builder_result.psbt.fee_amount().unwrap(), 220);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
# Integration tests for bdk-ffi
|
|
||||||
|
|
||||||
This contains simple tests to make sure bdk-ffi can be used as a dependency for each of the
|
|
||||||
supported bindings languages.
|
|
||||||
|
|
||||||
To skip integration tests and only run unit tests use `cargo test --lib`.
|
|
||||||
|
|
||||||
To run all tests including integration tests use `CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test`.
|
|
||||||
|
|
||||||
Before running integration tests you must install the following development tools:
|
|
||||||
|
|
||||||
1. [Java](https://openjdk.org/) and [Kotlin](https://kotlinlang.org/),
|
|
||||||
[sdkman](https://sdkman.io/) can help:
|
|
||||||
```shell
|
|
||||||
sdk install java 11.0.16.1-zulu
|
|
||||||
sdk install kotlin 1.7.20`
|
|
||||||
```
|
|
||||||
|
|
||||||
2. [Swift](https://www.swift.org/)
|
|
||||||
|
|
||||||
3. [Python](https://www.python.org/)
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
/*
|
|
||||||
* This is a basic test kotlin program that does nothing but confirm that the kotlin bindings compile
|
|
||||||
* and that a program that depends on them will run.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import org.bitcoindevkit.*
|
|
||||||
|
|
||||||
val network = Network.TESTNET
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import unittest
|
|
||||||
from bdk import *
|
|
||||||
|
|
||||||
class TestBdk(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_some_enum(self):
|
|
||||||
network = Network.TESTNET
|
|
||||||
|
|
||||||
def test_some_dict(self):
|
|
||||||
a = AddressInfo(index=42, address="testaddress")
|
|
||||||
self.assertEqual(42, a.index)
|
|
||||||
self.assertEqual("testaddress", a.address)
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
|
||||||
unittest.main()
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/*
|
|
||||||
* This is a basic test swift program that does nothing but confirm that the swift bindings compile
|
|
||||||
* and that a program that depends on them will run.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import bdk
|
|
||||||
|
|
||||||
let network = Network.testnet
|
|
||||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
|||||||
uniffi_macros::build_foreign_language_testcases!(
|
|
||||||
["src/bdk.udl",],
|
|
||||||
[
|
|
||||||
"tests/bindings/test.kts",
|
|
||||||
"tests/bindings/test.swift",
|
|
||||||
"tests/bindings/test.py"
|
|
||||||
]
|
|
||||||
);
|
|
||||||
Reference in New Issue
Block a user