Compare commits

...

24 Commits

Author SHA1 Message Date
thunderbiscuit
726808f85d Merge pull request #191 from thunderbiscuit/release/0.8
Create patch `0.8.1` that pins the uniffi-bindgen dependency
2022-08-30 16:14:15 -04:00
thunderbiscuit
811405879d Bump version to 0.8.1 2022-08-30 11:58:22 -04:00
thunderbiscuit
bcc6c0f0e8 Pin version of uniffi-bindgen in bdk-ffi-bindgen tool (#189) 2022-08-30 11:56:52 -04:00
thunderbiscuit
138200db07 Bump version to 0.8.0 2022-07-29 13:59:59 -04:00
thunderbiscuit
f1eb8c678d Update changelog to reflect 0.8.0 additions 2022-07-29 13:37:47 -04:00
Steve Myers
7d95433c28 Merge bitcoindevkit/bdk-ffi#175: Set project MSRV to 1.57.0
6d53cbeb25 Fix fmt error (Steve Myers)
1a12f37a2f Set MSRV to 1.57.0 (Steve Myers)

Pull request description:

  ### Description

  The `master` branch is currently not passing the new github checks.

  A required dependency of `bdk-ffi-bindgen` is `uniffi_bindgen` and it depends on `os_str_bytes` v6.2.0 which has a MSRV of 1.57.0. I therefore had to make the MSRV of `bdk-ffi` also 1.57.0 and update the github actions. This PR also fixes a small `cargo fmt` warning.

  ### Notes to the reviewers

  ```shell
  % cargo +1.56.1 build
  error: package `os_str_bytes v6.2.0` cannot be built because it requires rustc 1.57.0 or newer, while the currently active rustc version is 1.56.1
  ```

  ```shell
  % cargo tree -i os_str_bytes
  os_str_bytes v6.2.0
  └── clap_lex v0.2.4
      └── clap v3.1.18
          └── uniffi_bindgen v0.19.3
              └── bdk-ffi-bindgen v0.2.0 (/Users/steve/git/notmandatory/bdk-ffi/bdk-ffi-bindgen)
  ```

  ### Checklists

  #### All Submissions:

  * [x] I've signed all my commits
  * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
  * [x] I ran `cargo fmt` and `cargo clippy` before committing

Top commit has no ACKs.

Tree-SHA512: 87ad4a02d91184b421871354b1f5c31d906bf7460fe992db15666da32a65f13d8fbaf4ae53928f410a7206b195c8dff76af07210c144a4d02854ceb6af265f7e
2022-07-29 09:43:16 -07:00
Steve Myers
6d53cbeb25 Fix fmt error 2022-07-26 12:36:07 -07:00
Steve Myers
1a12f37a2f Set MSRV to 1.57.0 2022-07-26 12:35:41 -07:00
Steve Myers
04022787c4 Merge bitcoindevkit/bdk-ffi#174: Add github workflows for audit, test and fmt
46850ed471 Add github issue templates and PR template (Steve Myers)
49da6fcbae Fix clippy warnings (Steve Myers)
075510d6e4 Add github workflows for audit, test and fmt (Steve Myers)

Pull request description:

  1. Copied and updated github workflows from BDK project.
  2. Fixed clippy warnings.
  3. Added github issue templates and PR templates from BDK project.

  Fixes #88

Top commit has no ACKs.

Tree-SHA512: 7aaca6be0f05d12f4561e165ebc45b52e40200b231b55326732756d45116f371f2da4c5d7cc590cd0af9450c344530f815a357fa979a34d0181efc2149ffccb3
2022-07-26 12:25:25 -07:00
Steve Myers
46850ed471 Add github issue templates and PR template 2022-07-25 13:17:52 -07:00
Steve Myers
49da6fcbae Fix clippy warnings 2022-07-25 13:17:52 -07:00
Steve Myers
075510d6e4 Add github workflows for audit, test and fmt 2022-07-25 13:17:38 -07:00
thunderbiscuit
fa5c67cd05 Bump uniffi-rs to 0.19.3 (#173) 2022-07-25 15:15:23 -04:00
thunderbiscuit
1a20d0a6c2 Merge pull request #164 from zoedberg/coin_selection
Add coin selection methods
2022-07-21 15:39:55 -04:00
Zoe Faltibà
a3ae4635eb Post review fixes 2022-07-21 21:04:57 +02:00
Zoe Faltibà
5f12900c6d Add TxBuilder coin selection methods 2022-07-21 16:59:16 +02:00
thunderbiscuit
1a5a628a5d Merge pull request #170 from thunderbiscuit/bump/bdk-0.20.0
Update BDK to version 0.20.0
2022-07-20 11:49:21 -04:00
thunderbiscuit
d8c8261e44 Update BDK to version 0.20.0 2022-07-15 12:03:19 -04:00
thunderbiscuit
692904df1e Merge pull request #158 from zoedberg/list_unspent
Add Wallet list_unspent method
2022-07-12 12:07:52 -04:00
thunderbiscuit
2ac42b3ae0 Add list_unspent and add_data methods to changelog 2022-07-12 12:05:31 -04:00
Pedro
6be22daf84 Add add_data method for txbuilder op_return (#163) 2022-06-23 07:20:02 -04:00
thunderbiscuit
fad5e3cefd Fix comment for NetworkLocalUtxo trait 2022-06-22 14:48:56 -03:00
Zoe Faltibà
28a9b302d5 Post review changes 2022-06-18 15:38:39 +02:00
Zoe Faltibà
8f5ca7f0fc Add Wallet list_unspent method 2022-06-18 15:37:40 +02:00
11 changed files with 450 additions and 22 deletions

26
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,26 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**To Reproduce**
<!-- Steps or code to reproduce the behavior. -->
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Build environment**
- BDK tag/commit: <!-- e.g. v0.13.0, 3a07614 -->
- OS+version: <!-- e.g. ubuntu 20.04.01, macOS 12.0.1, windows -->
- Rust/Cargo version: <!-- e.g. 1.56.0 -->
- Rust/Cargo target: <!-- e.g. x86_64-apple-darwin, x86_64-unknown-linux-gnu, etc. -->
**Additional context**
<!-- Add any other context about the problem here. -->

View File

@@ -0,0 +1,77 @@
---
name: Summer of Bitcoin Project
about: Template to suggest a new https://www.summerofbitcoin.org/ project.
title: ''
labels: 'summer-of-bitcoin'
assignees: ''
---
<!--
## Overview
Project ideas are scoped for a university-level student with a basic background in CS and bitcoin
fundamentals - achievable over 12-weeks. Below are just a few types of ideas:
- Low-hanging fruit: Relatively short projects with clear goals; requires basic technical knowledge
and minimal familiarity with the codebase.
- Core development: These projects derive from the ongoing work from the core of your development
team. The list of features and bugs is never-ending, and help is always welcome.
- Risky/Exploratory: These projects push the scope boundaries of your development effort. They
might require expertise in an area not covered by your current development team. They might take
advantage of a new technology. There is a reasonable chance that the project might be less
successful, but the potential rewards make it worth the attempt.
- Infrastructure/Automation: These projects are the code that your organization uses to get its
development work done; for example, projects that improve the automation of releases, regression
tests and automated builds. This is a category where a Summer of Bitcoin student can be really
helpful, doing work that the development team has been putting off while they focus on core
development.
- Quality Assurance/Testing: Projects that work on and test your project's software development
process. Additionally, projects that involve a thorough test and review of individual PRs.
- Fun/Peripheral: These projects might not be related to the current core development focus, but
create new innovations and new perspectives for your project.
-->
**Description**
<!-- Description: 3-7 sentences describing the project background and tasks to be done. -->
**Expected Outcomes**
<!-- Short bullet list describing what is to be accomplished -->
**Resources**
<!-- 2-3 reading materials for candidate to learn about the repo, project, scope etc -->
<!-- Recommended reading such as a developer/contributor guide -->
<!-- [Another example a paper citation](https://arxiv.org/pdf/1802.08091.pdf) -->
<!-- [Another example an existing issue](https://github.com/opencv/opencv/issues/11013) -->
<!-- [An existing related module](https://github.com/opencv/opencv_contrib/tree/master/modules/optflow) -->
**Skills Required**
<!-- 3-4 technical skills that the candidate should know -->
<!-- hands on experience with git -->
<!-- mastery plus experience coding in C++ -->
<!-- basic knowledge in matrix and tensor computations, college course work in cryptography -->
<!-- strong mathematical background -->
<!-- Bonus - has experience with React Native. Best if you have also worked with OSSFuzz -->
**Mentor(s)**
<!-- names of mentor(s) for this project go here -->
**Difficulty**
<!-- Easy, Medium, Hard -->
**Competency Test (optional)**
<!-- 2-3 technical tasks related to the project idea or repository youd like a candidate to
perform in order to demonstrate competency, good first bugs, warm-up exercises -->
<!-- ex. Read the instructions here to get Bitcoin core running on your machine -->
<!-- ex. pick an issue labeled as “newcomer” in the repository, and send a merge request to the
repository. You can also suggest some other improvement that we did not think of yet, or
something that you find interesting or useful -->
<!-- ex. fixes for coding style are usually easy to do, and are good issues for first time
contributions for those learning how to interact with the project. After you are done with the
coding style issue, try making a different contribution. -->
<!-- ex. setup a full Debian packaging development environment and learn the basics of Debian
packaging. Then identify and package the missing dependencies to package Specter Desktop -->
<!-- ex. write a pull parser for CSV files. You'll be judged by the decisions to store the parser
state and how flexible it is to wrap this parser in other scenarios. -->
<!-- ex. Stretch Goal: Implement some basic metaprogram/app to prove you're very familiar with BDK.
Be prepared to make adjustments as we judge your solution. -->

30
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,30 @@
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
<!-- Describe the purpose of this PR, what's being adding and/or fixed -->
### Notes to the reviewers
<!-- In this section you can include notes directed to the reviewers, like explaining why some parts
of the PR were done in a specific way -->
### Checklists
#### All Submissions:
* [ ] I've signed all my commits
* [ ] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
* [ ] I ran `cargo fmt` and `cargo clippy` before committing
#### New Features:
* [ ] I've added tests for the new feature
* [ ] I've added docs for the new feature
* [ ] I've updated `CHANGELOG.md`
#### Bugfixes:
* [ ] This pull request breaks the existing API
* [ ] I've added tests to reproduce the issue which are now passing
* [ ] I'm linking the issue being fixed by this PR

19
.github/workflows/audit.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Audit
on:
push:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
schedule:
- cron: '0 0 * * 0' # Once per week
jobs:
security_audit:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions-rs/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

61
.github/workflows/cont_integration.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
on: [push, pull_request]
name: CI
jobs:
build-test:
name: Build and test
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- version: 1.60.0 # STABLE
clippy: true
- version: 1.57.0 # MSRV
steps:
- name: checkout
uses: actions/checkout@v2
- name: Generate cache key
run: echo "${{ matrix.rust.version }} ${{ matrix.features }}" | tee .cache_key
- name: cache
uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('.cache_key') }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
- name: Set default toolchain
run: rustup default ${{ matrix.rust.version }}
- name: Set profile
run: rustup set profile minimal
- name: Add clippy
if: ${{ matrix.rust.clippy }}
run: rustup component add clippy
- name: Update toolchain
run: rustup update
- name: Build
run: cargo build
- name: Clippy
if: ${{ matrix.rust.clippy }}
run: cargo clippy --all-targets -- -D warnings
- name: Test
run: cargo test
fmt:
name: Rust fmt
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set default toolchain
run: rustup default nightly
- name: Set profile
run: rustup set profile minimal
- name: Add rustfmt
run: rustup component add rustfmt
- name: Update toolchain
run: rustup update
- name: Check fmt
run: cargo fmt --all -- --config format_code_in_doc_comments=true --check

View File

@@ -6,8 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [v0.7.0]
## [v0.8.0]
- Update BDK to version 0.20.0 [#169]
- APIs Added
- `TxBuilder.add_data(data: Vec<u8>)` [#163]
- `Wallet.list_unspent()` returns `Vec<LocalUtxo>` [#158]
- Add coin control methods on TxBuilder [#164]
[#163]: https://github.com/bitcoindevkit/bdk-ffi/pull/163
[#158]: https://github.com/bitcoindevkit/bdk-ffi/pull/158
[#164]: https://github.com/bitcoindevkit/bdk-ffi/pull/164
[#169]: https://github.com/bitcoindevkit/bdk-ffi/pull/169
## [v0.7.0]
- Update BDK to version 0.19.0
- fixes sqlite-db issue causing wrong balance
- adds experimental taproot descriptor and PSBT support
@@ -23,13 +34,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#161]: https://github.com/bitcoindevkit/bdk-ffi/pull/161
## [v0.6.0]
- Update BDK to version 0.18.0
- Add BumpFeeTxBuilder to bump the fee on an unconfirmed tx created by the Wallet
- Change TxBuilder.build() to TxBuilder.finish() to align with bdk function name
## [v0.5.0]
- Fix Wallet.broadcast function, now returns a tx id as a hex string
- Remove creating a new spending Transaction via the PartiallySignedBitcoinTransaction constructor
- Add TxBuilder for creating new spending PartiallySignedBitcoinTransaction
@@ -38,17 +47,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update generate cli tool to generate all binding languages and rename to bdk-ffi-bindgen
## [v0.4.0]
- Add dual license MIT and Apache 2.0
- Add sqlite database support
- Fix memory database configuration enum, remove junk field
## [v0.3.1]
- Remove hard coded sync progress value (was always returning 21.0)
## [v0.3.0]
- Move bdk-kotlin bindings and ios example to separate repos
- Add bin to generate Python bindings
- Add `PartiallySignedBitcoinTransaction::deserialize` function as named constructor to decode from a string per [BIP 0174]
@@ -59,7 +65,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [v0.2.0]
[unreleased]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.7.0...HEAD
[unreleased]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.8.0...HEAD
[v0.8.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.7.0...v0.8.0
[v0.7.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.6.0...v0.7.0
[v0.6.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.5.0...v0.6.0
[v0.5.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.4.0...v0.5.0

View File

@@ -1,6 +1,6 @@
[package]
name = "bdk-ffi"
version = "0.7.0"
version = "0.8.1"
authors = ["Steve Myers <steve@notmandatory.org>", "Sudarsan Balaji <sudarsan.balaji@artfuldev.com>"]
edition = "2018"
@@ -14,10 +14,10 @@ crate-type = ["staticlib", "cdylib"]
name = "bdkffi"
[dependencies]
bdk = { version = "0.19", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled"] }
bdk = { version = "0.20", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled"] }
uniffi_macros = { version = "0.16.0", features = ["builtin-bindgen"] }
uniffi = { version = "0.16.0", features = ["builtin-bindgen"] }
uniffi_macros = { version = "0.19.3", features = ["builtin-bindgen"] }
uniffi = { version = "0.19.3", features = ["builtin-bindgen"] }
[build-dependencies]
uniffi_build = { version = "0.16.0", features = ["builtin-bindgen"] }
uniffi_build = { version = "0.19.3", features = ["builtin-bindgen"] }

View File

@@ -3,9 +3,8 @@ name = "bdk-ffi-bindgen"
version = "0.2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "=1.0.45" # remove after upgrading to next version of uniffi
structopt = "0.3"
uniffi_bindgen = "0.16.0"
uniffi_bindgen = "=0.19.3"
camino = "1.0.9"

View File

@@ -1,3 +1,4 @@
use camino::Utf8Path;
use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;
@@ -44,11 +45,13 @@ impl FromStr for Language {
}
fn generate_bindings(opt: &Opt) -> anyhow::Result<(), anyhow::Error> {
let path: &Utf8Path = Utf8Path::from_path(&opt.udl_file).unwrap();
let out_dir: &Utf8Path = Utf8Path::from_path(&opt.out_dir).unwrap();
uniffi_bindgen::generate_bindings(
&opt.udl_file,
path,
None,
vec![opt.language.to_string().as_str()],
Some(&opt.out_dir),
Some(out_dir),
false,
)?;

View File

@@ -149,6 +149,28 @@ callback interface Progress {
void update(f32 progress, string? message);
};
dictionary OutPoint {
string txid;
u32 vout;
};
dictionary TxOut {
u64 value;
string address;
};
enum KeychainKind {
"External",
"Internal",
};
dictionary LocalUtxo {
OutPoint outpoint;
TxOut txout;
KeychainKind keychain;
boolean is_spent;
};
interface Wallet {
[Throws=BdkError]
constructor(string descriptor, string? change_descriptor, Network network, DatabaseConfig database_config);
@@ -169,6 +191,9 @@ interface Wallet {
[Throws=BdkError]
void sync([ByRef] Blockchain blockchain, Progress? progress);
[Throws=BdkError]
sequence<LocalUtxo> list_unspent();
};
interface PartiallySignedBitcoinTransaction {
@@ -185,8 +210,24 @@ interface TxBuilder {
TxBuilder add_recipient(string address, u64 amount);
TxBuilder add_unspendable(OutPoint unspendable);
TxBuilder add_utxo(OutPoint outpoint);
TxBuilder add_utxos(sequence<OutPoint> outpoints);
TxBuilder do_not_spend_change();
TxBuilder manually_selected_only();
TxBuilder only_spend_change();
TxBuilder unspendable(sequence<OutPoint> unspendable);
TxBuilder fee_rate(float sat_per_vbyte);
TxBuilder fee_absolute(u64 fee_amount);
TxBuilder drain_wallet();
TxBuilder drain_to(string address);
@@ -195,6 +236,8 @@ interface TxBuilder {
TxBuilder enable_rbf_with_sequence(u32 nsequence);
TxBuilder add_data(sequence<u8> data);
[Throws=BdkError]
PartiallySignedBitcoinTransaction finish([ByRef] Wallet wallet);
};

View File

@@ -1,7 +1,7 @@
use bdk::bitcoin::hashes::hex::ToHex;
use bdk::bitcoin::secp256k1::Secp256k1;
use bdk::bitcoin::util::psbt::PartiallySignedTransaction;
use bdk::bitcoin::{Address, Network, Script, Txid};
use bdk::bitcoin::{Address, Network, OutPoint as BdkOutPoint, Script, Txid};
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
use bdk::blockchain::{
electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain,
@@ -12,11 +12,14 @@ 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::tx_builder::ChangeSpendPolicy;
use bdk::wallet::AddressIndex as BdkAddressIndex;
use bdk::wallet::AddressInfo as BdkAddressInfo;
use bdk::{
BlockTime, Error, FeeRate, SignOptions, SyncOptions as BdkSyncOptions, Wallet as BdkWallet,
BlockTime, Error, FeeRate, KeychainKind, SignOptions, SyncOptions as BdkSyncOptions,
Wallet as BdkWallet,
};
use std::collections::HashSet;
use std::convert::{From, TryFrom};
use std::fmt;
use std::ops::Deref;
@@ -172,6 +175,61 @@ struct Wallet {
wallet_mutex: Mutex<BdkWallet<AnyDatabase>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OutPoint {
txid: String,
vout: u32,
}
impl From<&OutPoint> for BdkOutPoint {
fn from(x: &OutPoint) -> BdkOutPoint {
BdkOutPoint {
txid: Txid::from_str(&x.txid).unwrap(),
vout: x.vout,
}
}
}
pub struct TxOut {
value: u64,
address: String,
}
pub struct LocalUtxo {
outpoint: OutPoint,
txout: TxOut,
keychain: KeychainKind,
is_spent: bool,
}
// This trait is used to convert the bdk TxOut type with field `script_pubkey: Script`
// into the bdk-ffi TxOut type which has a field `address: String` instead
trait NetworkLocalUtxo {
fn from_utxo(x: &bdk::LocalUtxo, network: Network) -> LocalUtxo;
}
impl NetworkLocalUtxo for LocalUtxo {
fn from_utxo(x: &bdk::LocalUtxo, network: Network) -> LocalUtxo {
LocalUtxo {
outpoint: OutPoint {
txid: x.outpoint.txid.to_string(),
vout: x.outpoint.vout,
},
txout: TxOut {
value: x.txout.value,
address: bdk::bitcoin::util::address::Address::from_script(
&x.txout.script_pubkey,
network,
)
.unwrap()
.to_string(),
},
keychain: x.keychain,
is_spent: x.is_spent,
}
}
}
pub trait Progress: Send + Sync + 'static {
fn update(&self, progress: f32, message: Option<String>);
}
@@ -283,6 +341,14 @@ impl Wallet {
let transactions = self.get_wallet().list_transactions(true)?;
Ok(transactions.iter().map(Transaction::from).collect())
}
fn list_unspent(&self) -> Result<Vec<LocalUtxo>, Error> {
let unspents = self.get_wallet().list_unspent()?;
Ok(unspents
.iter()
.map(|u| LocalUtxo::from_utxo(u, self.get_network()))
.collect())
}
}
pub struct ExtendedKeyInfo {
@@ -340,20 +406,32 @@ enum RbfValue {
#[derive(Clone, Debug)]
struct TxBuilder {
recipients: Vec<(String, u64)>,
utxos: Vec<OutPoint>,
unspendable: HashSet<OutPoint>,
change_policy: ChangeSpendPolicy,
manually_selected_only: bool,
fee_rate: Option<f32>,
fee_absolute: Option<u64>,
drain_wallet: bool,
drain_to: Option<String>,
rbf: Option<RbfValue>,
data: Vec<u8>,
}
impl TxBuilder {
fn new() -> Self {
TxBuilder {
recipients: Vec::new(),
utxos: Vec::new(),
unspendable: HashSet::new(),
change_policy: ChangeSpendPolicy::ChangeAllowed,
manually_selected_only: false,
fee_rate: None,
fee_absolute: None,
drain_wallet: false,
drain_to: None,
rbf: None,
data: Vec::new(),
}
}
@@ -366,6 +444,56 @@ impl TxBuilder {
})
}
fn add_unspendable(&self, unspendable: OutPoint) -> Arc<Self> {
let mut unspendable_hash_set = self.unspendable.clone();
unspendable_hash_set.insert(unspendable);
Arc::new(TxBuilder {
unspendable: unspendable_hash_set,
..self.clone()
})
}
fn add_utxo(&self, outpoint: OutPoint) -> Arc<Self> {
self.add_utxos(vec![outpoint])
}
fn add_utxos(&self, mut outpoints: Vec<OutPoint>) -> Arc<Self> {
let mut utxos = self.utxos.to_vec();
utxos.append(&mut outpoints);
Arc::new(TxBuilder {
utxos,
..self.clone()
})
}
fn do_not_spend_change(&self) -> Arc<Self> {
Arc::new(TxBuilder {
change_policy: ChangeSpendPolicy::ChangeForbidden,
..self.clone()
})
}
fn manually_selected_only(&self) -> Arc<Self> {
Arc::new(TxBuilder {
manually_selected_only: true,
..self.clone()
})
}
fn only_spend_change(&self) -> Arc<Self> {
Arc::new(TxBuilder {
change_policy: ChangeSpendPolicy::OnlyChange,
..self.clone()
})
}
fn unspendable(&self, unspendable: Vec<OutPoint>) -> Arc<Self> {
Arc::new(TxBuilder {
unspendable: unspendable.into_iter().collect(),
..self.clone()
})
}
fn fee_rate(&self, sat_per_vb: f32) -> Arc<Self> {
Arc::new(TxBuilder {
fee_rate: Some(sat_per_vb),
@@ -373,6 +501,13 @@ impl TxBuilder {
})
}
fn fee_absolute(&self, fee_amount: u64) -> Arc<Self> {
Arc::new(TxBuilder {
fee_absolute: Some(fee_amount),
..self.clone()
})
}
fn drain_wallet(&self) -> Arc<Self> {
Arc::new(TxBuilder {
drain_wallet: true,
@@ -401,15 +536,39 @@ impl TxBuilder {
})
}
fn add_data(&self, data: Vec<u8>) -> Arc<Self> {
Arc::new(TxBuilder {
data,
..self.clone()
})
}
fn finish(&self, wallet: &Wallet) -> Result<Arc<PartiallySignedBitcoinTransaction>, Error> {
let wallet = wallet.get_wallet();
let mut tx_builder = wallet.build_tx();
for (address, amount) in &self.recipients {
tx_builder.add_recipient(to_script_pubkey(address)?, *amount);
}
tx_builder.change_policy(self.change_policy);
if !self.utxos.is_empty() {
let bdk_utxos: Vec<BdkOutPoint> = self.utxos.iter().map(BdkOutPoint::from).collect();
let utxos: &[BdkOutPoint] = &bdk_utxos;
tx_builder.add_utxos(utxos)?;
}
if !self.unspendable.is_empty() {
let bdk_unspendable: Vec<BdkOutPoint> =
self.unspendable.iter().map(BdkOutPoint::from).collect();
tx_builder.unspendable(bdk_unspendable);
}
if self.manually_selected_only {
tx_builder.manually_selected_only();
}
if let Some(sat_per_vb) = self.fee_rate {
tx_builder.fee_rate(FeeRate::from_sat_per_vb(sat_per_vb));
}
if let Some(fee_amount) = self.fee_absolute {
tx_builder.fee_absolute(fee_amount);
}
if self.drain_wallet {
tx_builder.drain_wallet();
}
@@ -426,6 +585,10 @@ impl TxBuilder {
}
}
}
if !&self.data.is_empty() {
tx_builder.add_data(self.data.as_slice());
}
tx_builder
.finish()
.map(|(psbt, _)| PartiallySignedBitcoinTransaction {
@@ -530,7 +693,7 @@ mod test {
.drain_wallet()
.drain_to(drain_to_address.clone());
//dbg!(&tx_builder);
assert_eq!(tx_builder.drain_wallet, true);
assert!(tx_builder.drain_wallet);
assert_eq!(tx_builder.drain_to, Some(drain_to_address));
let psbt = tx_builder.finish(&test_wallet).unwrap();
@@ -549,7 +712,7 @@ mod test {
.get(0)
.unwrap()
.value;
assert_eq!(input_value, 50_000 as u64);
assert_eq!(input_value, 50_000_u64);
// confirm one output to correct address with all sats - fee
assert_eq!(psbt.outputs.len(), 1);
@@ -569,6 +732,6 @@ mod test {
Address::from_str("tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt").unwrap()
);
let output_value = psbt.unsigned_tx.output.get(0).cloned().unwrap().value;
assert_eq!(output_value, 49_890 as u64); // input - fee
assert_eq!(output_value, 49_890_u64); // input - fee
}
}