|
| 1 | +use bdk_wallet::keyring::KeyRing; |
| 2 | +use bdk_wallet::Wallet; |
| 3 | +use bitcoin::Network; |
| 4 | +use miniscript::descriptor::DescriptorType; |
| 5 | + |
| 6 | +// The KeyRing holds a map of keychain identifiers (`K`) to public descriptors. These keychain |
| 7 | +// identifiers can be simple (something like the `DescriptorId` or the `KeychainKind` types work |
| 8 | +// well, e.g. see the `simple_keyring.rs` example), but they can also be more complex if required by |
| 9 | +// the application. This example shows how the keychain identifier can be used to carry metadata |
| 10 | +// about the descriptors, which could be used to select which keychain to use in different scenarios |
| 11 | +// when calling methods like `Wallet::reveal_next_address`. |
| 12 | + |
| 13 | +// In this example, Johnny has a lot of keychains he keeps track of in his wallet. The map of |
| 14 | +// KeychainIdentifier -> Descriptor uses keys that are custom-made at the application layer, and |
| 15 | +// useful for its business logic (for example, choose a weekend keychain when Johnny is out partying |
| 16 | +// on the weekend). |
| 17 | + |
| 18 | +const DESC_1: &str = "tr([5bc5d243/86'/1'/0']tpubDC72NVP1RK5qwy2QdEfWphDsUBAfBu7oiV6jEFooHP8tGQGFVUeFxhgZxuk1j6EQRJ1YsS3th2RyDgReRqCL4zqp4jtuV2z7gbiqDH2iyUS/0/*)#xh44xwsp"; |
| 19 | +const DESC_2: &str = "wpkh([5bc5d243/84'/1'/0']tpubDCA4DcMLVSDifbfUxyJaVVAx57ztsVjke6DRYF95jFFgJqvzA9oENovVd7n34NNURmZxFNRB1VLGyDEqxvaZNXie3ZroEGFbeTS2xLYuaN1/0/*)#q8afsa3z"; |
| 20 | +const DESC_3: &str = "pkh([5bc5d243/44'/1'/0']tpubDDNQtvd8Sg1mXtSGtxRWEcgg7PbPwUSAyAmBonDSL3HLuutthe54Yih4XDYcywVdcduwqaQonpbTAGjjSh5kcLeCj5MTjYooa9ve2Npx6ho/1/*)#g73kgtdn"; |
| 21 | +const DESC_4: &str = "tr([5bc5d243/86'/1'/0']tpubDC72NVP1RK5qwy2QdEfWphDsUBAfBu7oiV6jEFooHP8tGQGFVUeFxhgZxuk1j6EQRJ1YsS3th2RyDgReRqCL4zqp4jtuV2z7gbiqDH2iyUS/42/42)"; |
| 22 | +const DESC_5: &str = "sh(wpkh([5bc5d243/49'/1'/0']tpubDDd6eupua2nhRp2egUAgYGjkxHeh5jPrBDaKLExeySwRvUb1hU7s8osoeACRhXs2w1UGZSMmEpZ1FkjYJ2Pxvfsy7w6XRqYYW7Vw89Unrzr/0/*))#svvvc6el"; |
| 23 | + |
| 24 | +fn main() { |
| 25 | + let keychain_1 = KeychainId { |
| 26 | + number: 1, |
| 27 | + nickname: "Johnny's favorite keychain", |
| 28 | + script_type: DescriptorType::Tr, |
| 29 | + color: Color::Blue, |
| 30 | + time_of_week_keychain: DayType::WeekDay, |
| 31 | + }; |
| 32 | + let keychain_2 = KeychainId { |
| 33 | + number: 2, |
| 34 | + nickname: "Johnny's party keychain", |
| 35 | + script_type: DescriptorType::Wpkh, |
| 36 | + color: Color::Green, |
| 37 | + time_of_week_keychain: DayType::WeekEnd, |
| 38 | + }; |
| 39 | + let keychain_3 = KeychainId { |
| 40 | + number: 3, |
| 41 | + nickname: "Johnny's old P2PKH keychain", |
| 42 | + script_type: DescriptorType::Pkh, |
| 43 | + color: Color::Blue, |
| 44 | + time_of_week_keychain: DayType::AnyDay, |
| 45 | + }; |
| 46 | + let keychain_4 = KeychainId { |
| 47 | + number: 4, |
| 48 | + nickname: "Johnny's project donations keychain", |
| 49 | + script_type: DescriptorType::Tr, |
| 50 | + color: Color::Yellow, |
| 51 | + time_of_week_keychain: DayType::AnyDay, |
| 52 | + }; |
| 53 | + let keychain_5 = KeychainId { |
| 54 | + number: 5, |
| 55 | + nickname: "The secret keychain", |
| 56 | + script_type: DescriptorType::ShWpkh, |
| 57 | + color: Color::Blue, |
| 58 | + time_of_week_keychain: DayType::AnyDay, |
| 59 | + }; |
| 60 | + |
| 61 | + let mut keyring: KeyRing<KeychainId> = KeyRing::new(Network::Signet, keychain_1, DESC_1); |
| 62 | + keyring.add_descriptor(keychain_2, DESC_2, false); |
| 63 | + keyring.add_descriptor(keychain_3, DESC_3, false); |
| 64 | + keyring.add_descriptor(keychain_4, DESC_4, false); |
| 65 | + keyring.add_descriptor(keychain_5, DESC_5, false); |
| 66 | + |
| 67 | + // DESC_1 is the default keychain (the first one added to the keyring is automatically the |
| 68 | + // default keychain), but this can also be changed later on with the |
| 69 | + // KeyRing::set_default_keychain API. This default keychain is useful because you can use |
| 70 | + // APIs like `Wallet::reveal_next_default_address()` which will always work with your |
| 71 | + // default keychain. |
| 72 | + |
| 73 | + let mut wallet = Wallet::new(keyring); |
| 74 | + |
| 75 | + let address1 = wallet.reveal_next_default_address(); |
| 76 | + println!("Default keychain address: {}", address1.address); |
| 77 | + |
| 78 | + let party_address = wallet.reveal_next_address(keychain_2).unwrap(); |
| 79 | + println!("Party address: {}", party_address.address); |
| 80 | + |
| 81 | + let donation_address = wallet.reveal_next_address(keychain_4).unwrap(); |
| 82 | + println!("Donation address: {}", donation_address.address); |
| 83 | +} |
| 84 | + |
| 85 | +#[allow(dead_code)] |
| 86 | +#[derive(Debug, Clone, Copy)] |
| 87 | +struct KeychainId { |
| 88 | + number: u32, |
| 89 | + nickname: &'static str, |
| 90 | + script_type: DescriptorType, |
| 91 | + color: Color, |
| 92 | + time_of_week_keychain: DayType, |
| 93 | +} |
| 94 | + |
| 95 | +impl PartialEq for KeychainId { |
| 96 | + fn eq(&self, other: &Self) -> bool { |
| 97 | + self.number == other.number |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +impl Eq for KeychainId {} |
| 102 | + |
| 103 | +impl PartialOrd for KeychainId { |
| 104 | + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { |
| 105 | + Some(self.cmp(other)) |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +impl Ord for KeychainId { |
| 110 | + fn cmp(&self, other: &Self) -> std::cmp::Ordering { |
| 111 | + self.number.cmp(&other.number) |
| 112 | + } |
| 113 | +} |
| 114 | + |
| 115 | +#[derive(Debug, Clone, Copy)] |
| 116 | +enum Color { |
| 117 | + Blue, |
| 118 | + Green, |
| 119 | + Yellow, |
| 120 | +} |
| 121 | + |
| 122 | +#[derive(Debug, Clone, Copy)] |
| 123 | +enum DayType { |
| 124 | + AnyDay, |
| 125 | + WeekDay, |
| 126 | + WeekEnd, |
| 127 | +} |
0 commit comments