Skip to content

Commit 2f1e07b

Browse files
committed
Add Pegin::derived_descriptor
Allowing to generate a bunch of pegin addresses from a single pegin descriptor
1 parent f77617b commit 2f1e07b

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

src/descriptor/pegin/dynafed_pegin.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::extensions::{CovExtArgs, CovenantExt};
3333
use crate::policy::{semantic, Liftable};
3434
use crate::{
3535
tweak_key, BtcDescriptor, BtcError, BtcFromTree, BtcLiftable, BtcPolicy, BtcSatisfier, BtcTree,
36-
Descriptor, Error, MiniscriptKey, ToPublicKey,
36+
Descriptor, DescriptorPublicKey, Error, MiniscriptKey, ToPublicKey,
3737
};
3838

3939
/// New Pegin Descriptor with Miniscript support
@@ -61,6 +61,18 @@ impl<Pk: MiniscriptKey> Pegin<Pk> {
6161
}
6262
}
6363

64+
impl Pegin<DescriptorPublicKey> {
65+
pub fn derived_descriptor<C: secp256k1_zkp::Verification>(
66+
&self,
67+
arg: u32,
68+
secp: &secp256k1_zkp::Secp256k1<C>,
69+
) -> Result<Pegin<PublicKey>, Error> {
70+
let elem_desc = self.elem_desc.at_derivation_index(arg)?;
71+
let elem_desc = elem_desc.derived_descriptor(&secp)?;
72+
Ok(Pegin::new(self.fed_desc.clone(), elem_desc))
73+
}
74+
}
75+
6476
impl<Pk: MiniscriptKey> fmt::Debug for Pegin<Pk> {
6577
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6678
write!(f, "pegin({:?},{:?})", self.fed_desc, self.elem_desc)
@@ -148,6 +160,7 @@ impl<Pk: MiniscriptKey> Pegin<Pk> {
148160
{
149161
// TODO
150162
Ok(bitcoin::Address::p2shwsh(
163+
// Should the address type taken from the top level user desc?
151164
&self
152165
.bitcoin_witness_script(secp)
153166
.expect("DO this cleanly after TR. Pay to taproot pegins unspecified till now"),
@@ -365,4 +378,36 @@ mod tests {
365378

366379
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");
367380
}
381+
382+
#[test]
383+
fn test_pegin_derive() {
384+
let elem_desc = "ct(slip77(ab5824f4477b4ebb00a132adfd8eb0b7935cf24f6ac151add5d1913db374ce92),elwpkh([759db348/84'/1'/0']tpubDCRMaF33e44pcJj534LXVhFbHibPbJ5vuLhSSPFAw57kYURv4tzXFL6LSnd78bkjqdmE3USedkbpXJUPA1tdzKfuYSL7PianceqAhwL2UkA/0/*))";
385+
let elem_desc: ConfidentialDescriptor<DescriptorPublicKey> = elem_desc.parse().unwrap();
386+
let fed_peg_desc = fed_peg_desc();
387+
let pegin = Pegin::new(fed_peg_desc, elem_desc.descriptor);
388+
let secp = secp256k1::Secp256k1::new();
389+
390+
let witness_script_0 = pegin
391+
.derived_descriptor(0, &secp)
392+
.unwrap()
393+
.bitcoin_witness_script(&secp)
394+
.unwrap();
395+
let address_0 = bitcoin::Address::p2wsh(&witness_script_0, bitcoin::Network::Bitcoin);
396+
assert_eq!(
397+
address_0.to_string(),
398+
"bc1qqkq6czql4zqwsylgrfzttjrn5wjeqmwfq5yn80p39amxtnkng9lsn6c5qr"
399+
);
400+
401+
let witness_script_1 = pegin
402+
.derived_descriptor(1, &secp)
403+
.unwrap()
404+
.bitcoin_witness_script(&secp)
405+
.unwrap();
406+
let address_1 = bitcoin::Address::p2wsh(&witness_script_1, bitcoin::Network::Bitcoin);
407+
assert_ne!(address_0, address_1);
408+
assert_eq!(
409+
address_1.to_string(),
410+
"bc1qmevs3n40t394230lptclz55rmxkmr7dmnqhuflxf0cezdupsmvdsk25n3m"
411+
);
412+
}
368413
}

src/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ pub enum Error {
373373
/// At least two BIP389 key expressions in the descriptor contain tuples of
374374
/// derivation indexes of different lengths.
375375
MultipathDescLenMismatch,
376+
377+
/// Conversion error in descriptor
378+
Conversion(descriptor::ConversionError),
376379
}
377380

378381
#[doc(hidden)]
@@ -449,6 +452,12 @@ impl From<bitcoin::address::ParseError> for Error {
449452
}
450453
}
451454

455+
impl From<descriptor::ConversionError> for Error {
456+
fn from(e: descriptor::ConversionError) -> Error {
457+
Error::Conversion(e)
458+
}
459+
}
460+
452461
fn errstr(s: &str) -> Error {
453462
Error::Unexpected(s.to_owned())
454463
}
@@ -530,6 +539,8 @@ impl fmt::Display for Error {
530539
Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"),
531540
Error::TrNoExplicitScript => write!(f, "No script code for Tr descriptors"),
532541
Error::MultipathDescLenMismatch => write!(f, "At least two BIP389 key expressions in the descriptor contain tuples of derivation indexes of different lengths"),
542+
Error::Conversion(ref e) => e.fmt(f),
543+
533544
}
534545
}
535546
}
@@ -584,6 +595,7 @@ impl error::Error for Error {
584595
ContextError(e) => Some(e),
585596
AnalysisError(e) => Some(e),
586597
PubKeyCtxError(e, _) => Some(e),
598+
Conversion(e) => Some(e),
587599
}
588600
}
589601
}

0 commit comments

Comments
 (0)