Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Spending Policy API #612

Closed
wants to merge 12 commits into from
9 changes: 9 additions & 0 deletions bdk-ffi/src/bdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,9 @@ interface Wallet {

string descriptor_checksum(KeychainKind keychain);

[Throws=DescriptorError]
Policy? policies(KeychainKind keychain);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Balance balance();

[Throws=CannotConnectError]
Expand Down Expand Up @@ -441,6 +444,10 @@ interface Wallet {

interface Update {};

interface Policy {
string id();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the only field you need/want for your use case? Just curious really, since we can expose other fields later if needed obv.

Regardless, looks good https://docs.rs/bdk_wallet/latest/bdk_wallet/descriptor/policy/struct.Policy.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other fields have been exposed now.

};

interface TxBuilder {
constructor();

Expand All @@ -456,6 +463,8 @@ interface TxBuilder {

TxBuilder add_utxo(OutPoint outpoint);

TxBuilder policy_path(record<string, sequence<u64>> policy_path, KeychainKind keychain);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks!


TxBuilder change_policy(ChangeSpendPolicy change_policy);

TxBuilder do_not_spend_change();
Expand Down
1 change: 1 addition & 0 deletions bdk-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use crate::types::FullScanRequestBuilder;
use crate::types::FullScanScriptInspector;
use crate::types::KeychainAndIndex;
use crate::types::LocalOutput;
use crate::types::Policy;
use crate::types::ScriptAmount;
use crate::types::SentAndReceivedValues;
use crate::types::SyncRequest;
Expand Down
25 changes: 25 additions & 0 deletions bdk-ffi/src/tx_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::error::CreateTxError;
use crate::types::ScriptAmount;
use crate::wallet::Wallet;

use bdk_wallet::KeychainKind;
use bitcoin_ffi::{Amount, FeeRate, Script};

use bdk_wallet::bitcoin::amount::Amount as BdkAmount;
Expand All @@ -11,6 +12,8 @@ use bdk_wallet::bitcoin::ScriptBuf as BdkScriptBuf;
use bdk_wallet::bitcoin::{OutPoint, Sequence, Txid};
use bdk_wallet::ChangeSpendPolicy;

use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::HashSet;
use std::str::FromStr;
use std::sync::Arc;
Expand All @@ -21,6 +24,7 @@ pub struct TxBuilder {
pub(crate) recipients: Vec<(BdkScriptBuf, BdkAmount)>,
pub(crate) utxos: Vec<OutPoint>,
pub(crate) unspendable: HashSet<OutPoint>,
pub(crate) policy_path: (HashMap<String, Vec<u64>>, KeychainKind),
pub(crate) change_policy: ChangeSpendPolicy,
pub(crate) manually_selected_only: bool,
pub(crate) fee_rate: Option<FeeRate>,
Expand All @@ -37,6 +41,7 @@ impl TxBuilder {
recipients: Vec::new(),
utxos: Vec::new(),
unspendable: HashSet::new(),
policy_path: (HashMap::new(), KeychainKind::External),
change_policy: ChangeSpendPolicy::ChangeAllowed,
manually_selected_only: false,
fee_rate: None,
Expand Down Expand Up @@ -104,6 +109,17 @@ impl TxBuilder {
})
}

pub(crate) fn policy_path(
&self,
policy_path: HashMap<String, Vec<u64>>,
keychain: KeychainKind,
) -> Arc<Self> {
Arc::new(TxBuilder {
policy_path: (policy_path, keychain),
..self.clone()
})
}

pub(crate) fn change_policy(&self, change_policy: ChangeSpendPolicy) -> Arc<Self> {
Arc::new(TxBuilder {
change_policy,
Expand Down Expand Up @@ -177,6 +193,15 @@ impl TxBuilder {
for (script, amount) in &self.recipients {
tx_builder.add_recipient(script.clone(), *amount);
}
tx_builder.policy_path(
self.policy_path
.0
.clone()
.into_iter()
.map(|(key, value)| (key, value.into_iter().map(|x| x as usize).collect()))
.collect::<BTreeMap<String, Vec<usize>>>(),
self.policy_path.1,
);
tx_builder.change_policy(self.change_policy);
if !self.utxos.is_empty() {
tx_builder
Expand Down
21 changes: 20 additions & 1 deletion bdk-ffi/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ use bdk_wallet::chain::tx_graph::CanonicalTx as BdkCanonicalTx;
use bdk_wallet::chain::{
ChainPosition as BdkChainPosition, ConfirmationBlockTime as BdkConfirmationBlockTime,
};
use bdk_wallet::descriptor::Policy as BdkPolicy;
use bdk_wallet::AddressInfo as BdkAddressInfo;
use bdk_wallet::Balance as BdkBalance;
use bdk_wallet::KeychainKind;
use bdk_wallet::LocalOutput as BdkLocalOutput;
use bdk_wallet::Update as BdkUpdate;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think we can keep this blank line since we seem to break these use in groups

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

use std::sync::{Arc, Mutex};

#[derive(Debug)]
Expand Down Expand Up @@ -237,3 +237,22 @@ pub struct KeychainAndIndex {
pub keychain: KeychainKind,
pub index: u32,
}

/// Descriptor spending policy
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Policy(BdkPolicy);
impl From<BdkPolicy> for Policy {
fn from(value: BdkPolicy) -> Self {
Policy(value)
}
}
impl From<Policy> for BdkPolicy {
fn from(value: Policy) -> Self {
value.0
}
}
impl Policy {
pub fn id(&self) -> String {
self.0.id.clone()
}
}
16 changes: 11 additions & 5 deletions bdk-ffi/src/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::bitcoin::{Psbt, Transaction};
use crate::descriptor::Descriptor;
use crate::error::{
CalculateFeeError, CannotConnectError, CreateWithPersistError, LoadWithPersistError,
SignerError, SqliteError, TxidParseError,
CalculateFeeError, CannotConnectError, CreateWithPersistError, DescriptorError,
LoadWithPersistError, SignerError, SqliteError, TxidParseError,
};
use crate::store::Connection;
use crate::types::{
AddressInfo, Balance, CanonicalTx, FullScanRequestBuilder, KeychainAndIndex, LocalOutput,
SentAndReceivedValues, SyncRequestBuilder, Update,
Policy, SentAndReceivedValues, SyncRequestBuilder, Update,
};

use bitcoin_ffi::{Amount, FeeRate, OutPoint, Script};
Expand Down Expand Up @@ -139,6 +139,13 @@ impl Wallet {
self.get_wallet().descriptor_checksum(keychain)
}

pub fn policies(&self, keychain: KeychainKind) -> Result<Option<Arc<Policy>>, DescriptorError> {
self.get_wallet()
.policies(keychain)
.map_err(DescriptorError::from)
.map(|e| e.map(|p| Arc::new(p.into())))
}

pub fn network(&self) -> Network {
self.get_wallet().network()
}
Expand All @@ -154,8 +161,7 @@ impl Wallet {

pub(crate) fn sign(
&self,
psbt: Arc<Psbt>,
// sign_options: Option<SignOptions>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: might be nice to keep this on a separate line, but at the same time not any sort of blocker to approving this PR (and we might just remove the whole commented line before 1.0 beta anyway on bdk-ffi)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

psbt: Arc<Psbt>, // sign_options: Option<SignOptions>,
) -> Result<bool, SignerError> {
let mut psbt = psbt.0.lock().unwrap();
self.get_wallet()
Expand Down
Loading