beginn keyspend collaborative payout tx/psbt assembly, test for getting escrow utxo from descriptor

This commit is contained in:
fbock
2024-08-13 18:15:33 +02:00
parent 805ee865fa
commit ead749b7e7
4 changed files with 81 additions and 7 deletions

View File

@ -117,7 +117,7 @@ pub fn build_escrow_transaction_output_descriptor(
let descriptor = Descriptor::<XOnlyPublicKey>::new_tr(internal_agg_musig_key, Some(tap_root))
.context("Error assembling escrow output descriptor")?;
descriptor.sanity_check()?;
debug!("Escrow descriptor: {:#?}", descriptor);
debug!("Escrow descriptor: {:#?}", descriptor.to_string());
Ok(descriptor) // then spend to descriptor.address(Network::Regtest)
}

View File

@ -1,4 +1,5 @@
pub mod escrow_psbt;
pub mod payout_tx;
pub mod wallet_utils;
// pub mod verify_tx;
#[cfg(test)]

View File

@ -0,0 +1,38 @@
use std::ops::Add;
/// construction of the transaction spending the escrow output after a successfull trade as keyspend transaction
use super::*;
use bdk::bitcoin::psbt::PartiallySignedTransaction;
use bdk::bitcoin::OutPoint;
fn get_tx_fees_abs_sat(blockchain_backend: &RpcBlockchain) -> Result<(u64, u64)> {
let feerate = blockchain_backend.estimate_fee(6)?;
let keyspend_payout_tx_size_vb = 140; // ~, always 1 input, 2 outputs
let tx_fee_abs = feerate.fee_vb(keyspend_payout_tx_size_vb);
Ok((tx_fee_abs, tx_fee_abs / 2))
}
impl<D: bdk::database::BatchDatabase> CoordinatorWallet<D> {
pub async fn assemble_keyspend_payout_psbt(
&self,
escrow_output: OutPoint,
payout_addresses: HashMap<Address, u64>,
) -> Result<PartiallySignedTransaction> {
let (payout_psbt, _) = {
let wallet = self.wallet.lock().await;
let mut builder = wallet.build_tx();
let (tx_fee_abs, tx_fee_abs_sat_per_user) = get_tx_fees_abs_sat(&self.backend)?;
builder.add_utxo(escrow_output)?;
for (address, amount) in payout_addresses {
builder.add_recipient(address.script_pubkey(), amount - tx_fee_abs_sat_per_user);
}
builder.fee_absolute(tx_fee_abs);
builder.finish()?
};
Ok(payout_psbt)
}
}

View File

@ -8,14 +8,9 @@ use bdk::{
bitcoin::{psbt::Input, Network},
blockchain::RpcBlockchain,
database::MemoryDatabase,
miniscript::{
descriptor::{self},
policy::Concrete,
Descriptor, Tap,
},
miniscript::{policy::Concrete, Descriptor, Tap},
Wallet,
};
use sha2::digest::XofReader;
async fn new_test_wallet(wallet_xprv: &str) -> CoordinatorWallet<MemoryDatabase> {
dotenv().ok();
@ -324,3 +319,43 @@ fn test_miniscript_compilation() {
Descriptor::<XOnlyPublicKey>::new_tr(internal_key, Some(tap_tree_root)).unwrap();
dbg!(descriptor.address(bdk::bitcoin::Network::Regtest).unwrap());
}
#[test]
fn test_create_escrow_spending_psbt() {
dotenv().ok();
let test_descriptor = "tr(f00949d6dd1ce99a03f88a1a4f59117d553b0da51728bb7fd5b98fbf541337fb,{{and_v(v:pk(4987f3de20a9b1fa6f76c6758934953a8d615e415f1a656f0f6563694b53107d),pk(8f808f457423ff5e4e20a36d317ce9426f9da2fde875e74e15a04481b94bec06)),and_v(v:pk(f1f1db08126af105974cde6021096525ed390cf9b7cde5fedb17a0b16ed31151),pk(8f808f457423ff5e4e20a36d317ce9426f9da2fde875e74e15a04481b94bec06))},{and_v(v:and_v(v:pk(4987f3de20a9b1fa6f76c6758934953a8d615e415f1a656f0f6563694b53107d),pk(f1f1db08126af105974cde6021096525ed390cf9b7cde5fedb17a0b16ed31151)),after(2048)),and_v(v:pk(4987f3de20a9b1fa6f76c6758934953a8d615e415f1a656f0f6563694b53107d),after(12228))}})#0edq24m2";
let escrow_output_wallet = Wallet::new(
test_descriptor,
None,
Network::Regtest,
MemoryDatabase::new(),
)
.unwrap();
let secp_context = secp256k1::Secp256k1::new();
let rpc_config = RpcConfig {
url: env::var("BITCOIN_RPC_ADDRESS_PORT").unwrap().to_string(),
auth: Auth::UserPass {
username: env::var("BITCOIN_RPC_USER").unwrap(),
password: env::var("BITCOIN_RPC_PASSWORD").unwrap(),
},
network: Regtest,
// wallet_name: env::var("BITCOIN_RPC_WALLET_NAME")?,
wallet_name: bdk::wallet::wallet_name_from_descriptor(
test_descriptor,
None,
Network::Regtest,
&secp_context,
)
.unwrap(),
sync_params: None,
};
let backend = RpcBlockchain::from_config(&rpc_config).unwrap();
escrow_output_wallet
.sync(&backend, SyncOptions::default())
.unwrap();
let escrow_utxo = escrow_output_wallet.list_unspent().unwrap();
dbg!(&escrow_utxo);
assert!(escrow_utxo.len() > 0);
}