Skip to content

Commit

Permalink
Add Pegin::derived_descriptor
Browse files Browse the repository at this point in the history
Allowing to generate a bunch of pegin addresses from a single pegin
descriptor
  • Loading branch information
RCasatta committed Dec 2, 2024
1 parent f77617b commit 2f1e07b
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
47 changes: 46 additions & 1 deletion src/descriptor/pegin/dynafed_pegin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use crate::extensions::{CovExtArgs, CovenantExt};
use crate::policy::{semantic, Liftable};
use crate::{
tweak_key, BtcDescriptor, BtcError, BtcFromTree, BtcLiftable, BtcPolicy, BtcSatisfier, BtcTree,
Descriptor, Error, MiniscriptKey, ToPublicKey,
Descriptor, DescriptorPublicKey, Error, MiniscriptKey, ToPublicKey,
};

/// New Pegin Descriptor with Miniscript support
Expand Down Expand Up @@ -61,6 +61,18 @@ impl<Pk: MiniscriptKey> Pegin<Pk> {
}
}

impl Pegin<DescriptorPublicKey> {
pub fn derived_descriptor<C: secp256k1_zkp::Verification>(
&self,
arg: u32,
secp: &secp256k1_zkp::Secp256k1<C>,
) -> Result<Pegin<PublicKey>, Error> {
let elem_desc = self.elem_desc.at_derivation_index(arg)?;
let elem_desc = elem_desc.derived_descriptor(&secp)?;
Ok(Pegin::new(self.fed_desc.clone(), elem_desc))
}
}

impl<Pk: MiniscriptKey> fmt::Debug for Pegin<Pk> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "pegin({:?},{:?})", self.fed_desc, self.elem_desc)
Expand Down Expand Up @@ -148,6 +160,7 @@ impl<Pk: MiniscriptKey> Pegin<Pk> {
{
// TODO
Ok(bitcoin::Address::p2shwsh(
// Should the address type taken from the top level user desc?
&self
.bitcoin_witness_script(secp)
.expect("DO this cleanly after TR. Pay to taproot pegins unspecified till now"),
Expand Down Expand Up @@ -365,4 +378,36 @@ mod tests {

assert_eq!(pegin.to_string(), "pegin(wsh(or_d(multi(11,020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261,02675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af99,02896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d48,029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c,02a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc4010,031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb,03079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b,03111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2,0318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa0840174,03230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de1,035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a6,03bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c,03cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d17546,03d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d424828,03ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a),and_v(v:older(4032),multi(2,03aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79,0291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807,0386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb)))),elwpkh(0321da398ca2ddc09be89caa26e6730ae84751b6ea3a1ca46aa365bb5e1c3d9620))#qp4fan9q");
}

#[test]
fn test_pegin_derive() {
let elem_desc = "ct(slip77(ab5824f4477b4ebb00a132adfd8eb0b7935cf24f6ac151add5d1913db374ce92),elwpkh([759db348/84'/1'/0']tpubDCRMaF33e44pcJj534LXVhFbHibPbJ5vuLhSSPFAw57kYURv4tzXFL6LSnd78bkjqdmE3USedkbpXJUPA1tdzKfuYSL7PianceqAhwL2UkA/0/*))";
let elem_desc: ConfidentialDescriptor<DescriptorPublicKey> = elem_desc.parse().unwrap();
let fed_peg_desc = fed_peg_desc();
let pegin = Pegin::new(fed_peg_desc, elem_desc.descriptor);
let secp = secp256k1::Secp256k1::new();

let witness_script_0 = pegin
.derived_descriptor(0, &secp)
.unwrap()
.bitcoin_witness_script(&secp)
.unwrap();
let address_0 = bitcoin::Address::p2wsh(&witness_script_0, bitcoin::Network::Bitcoin);
assert_eq!(
address_0.to_string(),
"bc1qqkq6czql4zqwsylgrfzttjrn5wjeqmwfq5yn80p39amxtnkng9lsn6c5qr"
);

let witness_script_1 = pegin
.derived_descriptor(1, &secp)
.unwrap()
.bitcoin_witness_script(&secp)
.unwrap();
let address_1 = bitcoin::Address::p2wsh(&witness_script_1, bitcoin::Network::Bitcoin);
assert_ne!(address_0, address_1);
assert_eq!(
address_1.to_string(),
"bc1qmevs3n40t394230lptclz55rmxkmr7dmnqhuflxf0cezdupsmvdsk25n3m"
);
}
}
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,9 @@ pub enum Error {
/// At least two BIP389 key expressions in the descriptor contain tuples of
/// derivation indexes of different lengths.
MultipathDescLenMismatch,

/// Conversion error in descriptor
Conversion(descriptor::ConversionError),
}

#[doc(hidden)]
Expand Down Expand Up @@ -449,6 +452,12 @@ impl From<bitcoin::address::ParseError> for Error {
}
}

impl From<descriptor::ConversionError> for Error {
fn from(e: descriptor::ConversionError) -> Error {
Error::Conversion(e)
}
}

fn errstr(s: &str) -> Error {
Error::Unexpected(s.to_owned())
}
Expand Down Expand Up @@ -530,6 +539,8 @@ impl fmt::Display for Error {
Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"),
Error::TrNoExplicitScript => write!(f, "No script code for Tr descriptors"),
Error::MultipathDescLenMismatch => write!(f, "At least two BIP389 key expressions in the descriptor contain tuples of derivation indexes of different lengths"),
Error::Conversion(ref e) => e.fmt(f),

}
}
}
Expand Down Expand Up @@ -584,6 +595,7 @@ impl error::Error for Error {
ContextError(e) => Some(e),
AnalysisError(e) => Some(e),
PubKeyCtxError(e, _) => Some(e),
Conversion(e) => Some(e),
}
}
}
Expand Down

0 comments on commit 2f1e07b

Please sign in to comment.