# Multi-Keychain Feature ## Short version 1. We modify a few wallet APIs that require specifying the keychain (e.g. `Wallet::reveal_next_address(johnnys_keychain)`). 2. We introduce a new type that helps us clean up the way we construct wallets, define keychains, set default keychains, choose the network, and ensure all of those are compatible with each other. <br> ## Part 1: Modified Wallet APIs Your wallet will now hold a map of keychain identifiers to public descriptors: ```rust descriptors: BTreeMap<K, Descriptor<DescriptorPublicKey>>, ``` In practice, you could use a [`DescriptorId`](https://docs.rs/bdk_chain/0.23.1/bdk_chain/struct.DescriptorId.html) for your keys, or something much more complex defined at the application layer ([see an example here](https://github.com/ValuedMammal/multi-keychain-wallet/blob/f34289624de5ba4d5fd5e380b7177a6ed3cf30c0/examples/custom_keychain_identifier.rs#L144C1-L149C2)). The important part is that this identifier is unique and can always be used to refer to a specific keychain, so you can tell a wallet to reveal addresses on this keychain, or send your change to it, or compute a balance just for that keychain, etc. **User-facing changes:** - The wallet APIs don't change much semantically. If you want to reveal an address, you still need to provide a keychain for that call. - Because we now have a default keychain (see #2 below), we can introduce methods like `Wallet::reveal_address_default_keychain()` which don't require arguments, or make the `Wallet::reveal_next_address()` method always run on the default keychain. - You could potentially ask your transaction builder to send your change outputs to specific keychains, or maybe use inputs from a given keychain. <br> ## Part 2: Using A Default Keychain To simplify working with a number of keychains, we define one as the default one. This is not required per se (every call that needs it could simply require the user provide a keychain identifier), but we expect most users to often work with a specific keychain (and maybe a default change keychain). For this reason, specifying a default keychain from the start simplifies these interactions with the `Wallet`. This opens up the possibility of methods like: ```rust // Run-of-the-mill "give me an address" on default keychain Wallet::reveal_next_address() // Reveal an address on a specific keychain Wallet::reveal_next_address_on_keychain(keychain: K) ``` <br> ## Part 3: The `KeyRing` Type Building a `Wallet` now goes through an intermediary step where users build what we call a `KeyRing`: ```rust pub struct KeyRing<K> { pub network: Network, pub descriptors: BTreeMap<K, Descriptor<DescriptorPublicKey>>, pub default_keychain: K, } ``` This keyring is useful because it front-loads the work and complexity behind what the wallet builder currently does. Things like checking that your descriptors and your network are compatible, ensuring your descriptors are actually valid descriptors, etc. are now done at the `KeyRing` layer; once a keyring is build (and therefore valid), you can always be sure that a `Wallet` can be built from it. This means the constructor on the wallet becomes very simple: `Wallet::new(keyring: KeyRing)`. You can work with this keyring in useful ways: add descriptors to it (any number of them), decide which one is your default one, query it, etc. **Now that's just gravy** Interesting features that follow from using this `KeyRing` idea is that the keyring is (1) potentially as simple as the current constructors are in the simple case: ```rust let keyring = KeyRing::new(network, desc_id, desc); let wallet = Wallet::new(keyring); ``` and (2) could handle more complex imports from other wallet backup data structures, for example like so: ```rust // Build a keyring from a bitcoin core export object KeyRing::from_core_backup(core_json_object) // Build a keyring from an Unchained Caravan export backup KeyRing::from_caravan_backup(caravan_backup_object) ``` This would of course be possible with new constructor on the Wallet type as well, but is a cleaner separation of concerns. The KeyRing is in charge of ensuring the data structure required for the creation of a BDK `Wallet` type is valid and ready for business before actually using it on the wallet constructor.