use std::str::FromStr; use bdk_wallet::miniscript::descriptor::Wsh; use bdk_wallet::miniscript::policy::{self, Concrete, Liftable}; use bitcoin::Address; /// A hash time locked contract between two parties. /// /// If the hash preimage of the hashlock is revealed, the value is sent to the redeem_identity. /// /// Alternately, if the refund timelock expires, the value can be refunded to the refund_identity. pub(crate) struct Htlc { value: u64, redeem_identity: Address, hashlock: String, refund_timelock: u64, refund_indentiy: Address, } impl Htlc { /// Create a new HTLC. pub(crate) fn new( value: u64, redeem_identity: Address, hashlock: String, refund_timelock: u64, refund_indentiy: Address, ) -> Self { Self { value, redeem_identity, hashlock, refund_timelock, refund_indentiy, } } pub(crate) fn to_miniscript_policy(&self) -> policy::Concrete { Concrete::::from_str(&format!( "or(10@and(sha256({secret_hash}),pk({redeem_identity})),1@and(older({expiry}),pk({refund_identity})))", secret_hash = self.hashlock, redeem_identity = self.redeem_identity, refund_identity = self.refund_indentiy, expiry = self.refund_timelock )).expect("Policy compilation only fails on resource limits or mixed timelocks") } pub(crate) fn to_miniscript_descriptor(&self) -> Wsh { Wsh::new( self.to_miniscript_policy() .compile() .expect("Policy compilation only fails on resource limits or mixed timelocks"), ) .expect("Resource limits") } /// Translate the HTLC to Bitcoin op_codes. pub(crate) fn to_script(&self) -> String { format!( "OP_IF OP_SHA256 {} OP_EQUALVERIFY OP_DUP OP_HASH160 {} OP_ELSE {} OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 {} OP_ENDIF OP_EQUALVERIFY OP_CHECKSIG", self.hashlock, self.redeem_identity, self.refund_timelock, self.refund_indentiy ) } }