use crate::scripts::{
DerivedCpfpDescriptor, DerivedDepositDescriptor, DerivedUnvaultDescriptor, EmergencyAddress,
};
use miniscript::{
bitcoin::{
util::{bip32, psbt::Output as PsbtOut},
Amount, PublicKey, Script, TxOut,
},
DescriptorTrait,
};
use std::{collections::BTreeMap, fmt};
pub type Bip32Deriv = BTreeMap<PublicKey, (bip32::Fingerprint, bip32::DerivationPath)>;
pub trait RevaultTxOut: fmt::Debug + Clone + PartialEq {
fn txout(&self) -> &TxOut;
fn into_txout(self) -> TxOut;
fn psbtout(&self) -> PsbtOut;
}
pub trait RevaultInternalTxOut: fmt::Debug + Clone + PartialEq + RevaultTxOut {
fn witness_script(&self) -> &Script;
fn into_witness_script(self) -> Script;
fn bip32_derivation(&self) -> &Bip32Deriv;
fn into_bip32_derivation(self) -> Bip32Deriv;
fn max_sat_weight(&self) -> usize {
miniscript::descriptor::Wsh::new(
miniscript::Miniscript::parse(self.witness_script())
.expect("The witness_script is always created from a Miniscript"),
)
.expect("The witness_script is always a P2WSH")
.max_satisfaction_weight()
.expect("It's a sane Script, derived from a Miniscript")
}
}
macro_rules! implem_revault_txout {
( $struct_name:ident, $doc_comment:meta ) => {
#[$doc_comment]
#[derive(Debug, Clone, PartialEq, Default)]
pub struct $struct_name {
txout: TxOut,
witness_script: Script,
bip32_derivation: Bip32Deriv,
}
impl RevaultTxOut for $struct_name {
fn txout(&self) -> &TxOut {
&self.txout
}
fn into_txout(self) -> TxOut {
self.txout
}
fn psbtout(&self) -> PsbtOut {
PsbtOut {
bip32_derivation: self.bip32_derivation().clone(),
..PsbtOut::default()
}
}
}
impl RevaultInternalTxOut for $struct_name {
fn witness_script(&self) -> &Script {
&self.witness_script
}
fn into_witness_script(self) -> Script {
self.witness_script
}
fn bip32_derivation(&self) -> &Bip32Deriv {
&self.bip32_derivation
}
fn into_bip32_derivation(self) -> Bip32Deriv {
self.bip32_derivation
}
}
};
}
implem_revault_txout!(
DepositTxOut,
doc = "A deposit transaction output. Used by the [Deposit](crate::transactions::DepositTransaction), \
the [Cancel](crate::transactions::CancelTransaction), and the \
[Spend](crate::transactions::SpendTransaction)."
);
impl DepositTxOut {
pub fn new(value: Amount, script_descriptor: &DerivedDepositDescriptor) -> DepositTxOut {
DepositTxOut {
txout: TxOut {
value: value.as_sat(),
script_pubkey: script_descriptor.inner().script_pubkey(),
},
witness_script: script_descriptor.inner().explicit_script(),
bip32_derivation: script_descriptor
.keys()
.into_iter()
.map(|k| {
(
k.key,
(k.origin.0, bip32::DerivationPath::from(&[k.origin.1][..])),
)
})
.collect(),
}
}
}
implem_revault_txout!(UnvaultTxOut, doc = "*The* Unvault transaction output.");
impl UnvaultTxOut {
pub fn new(value: Amount, script_descriptor: &DerivedUnvaultDescriptor) -> UnvaultTxOut {
UnvaultTxOut {
txout: TxOut {
value: value.as_sat(),
script_pubkey: script_descriptor.inner().script_pubkey(),
},
witness_script: script_descriptor.inner().explicit_script(),
bip32_derivation: script_descriptor
.keys()
.into_iter()
.map(|k| {
(
k.key,
(k.origin.0, bip32::DerivationPath::from(&[k.origin.1][..])),
)
})
.collect(),
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct EmergencyTxOut(TxOut);
impl EmergencyTxOut {
pub fn new(address: EmergencyAddress, value: Amount) -> EmergencyTxOut {
EmergencyTxOut(TxOut {
script_pubkey: address.address().script_pubkey(),
value: value.as_sat(),
})
}
}
impl RevaultTxOut for EmergencyTxOut {
fn txout(&self) -> &TxOut {
&self.0
}
fn into_txout(self) -> TxOut {
self.0
}
fn psbtout(&self) -> PsbtOut {
PsbtOut::default()
}
}
implem_revault_txout!(
CpfpTxOut,
doc = "The output attached to the [Unvault](crate::transactions::UnvaultTransaction) \
so that the fund managers can fee-bump it."
);
impl CpfpTxOut {
pub fn new(value: Amount, script_descriptor: &DerivedCpfpDescriptor) -> CpfpTxOut {
CpfpTxOut {
txout: TxOut {
value: value.as_sat(),
script_pubkey: script_descriptor.inner().script_pubkey(),
},
witness_script: script_descriptor.inner().explicit_script(),
bip32_derivation: script_descriptor
.keys()
.into_iter()
.map(|k| {
(
k.key,
(k.origin.0, bip32::DerivationPath::from(&[k.origin.1][..])),
)
})
.collect(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SpendTxOut(TxOut);
impl SpendTxOut {
pub fn new(txo: TxOut) -> Self {
SpendTxOut(txo)
}
}
impl RevaultTxOut for SpendTxOut {
fn txout(&self) -> &TxOut {
&self.0
}
fn into_txout(self) -> TxOut {
self.0
}
fn psbtout(&self) -> PsbtOut {
PsbtOut::default()
}
}