# 4.2: Integrating Addresses and Descriptors You now have an understanding of your descriptor wallet and the variety of addresses that it can create. You've even seen how your descriptor wallet contains ranged descriptors for four sorts of addresses. But you can also have _non-ranged_ descriptors for individual addresses. This section examines them. ## Examine an Address' Descriptor You created a set of three addresses in the previous section. You can see the details of any individual address with the `getaddressinfo` command, including its individual descriptor: ``` $ bitcoin-cli getaddressinfo tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4 { "address": "tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4", "scriptPubKey": "00142a4f27c78470206e1a5948b47478d5b37991aac4", "ismine": true, "solvable": true, "desc": "wpkh([e18dae20/84h/1h/0h/0/2]02040bf9b12e48bbbcbf72ef5197bc18067db378411ae6220f1d0a77da2ee7dbba)#dqt0983r", "parent_desc": "wpkh([e18dae20/84h/1h/0h]tpubDC4ujMbsd9REzpGk3gnTjkrfJFw1NnvCpx6QBbLj3CHBzcLmVzssTVP8meRAM1WW4pZnK6SCCPGyzi9eMfzSXoeFMNprqtgxG71VRXTmetu/0/*)#3658f8sn", "iswatchonly": false, "isscript": false, "iswitness": true, "witness_version": 0, "witness_program": "2a4f27c78470206e1a5948b47478d5b37991aac4", "pubkey": "02040bf9b12e48bbbcbf72ef5197bc18067db378411ae6220f1d0a77da2ee7dbba", "ischange": false, "timestamp": 1770329126, "hdkeypath": "m/84h/1h/0h/0/2", "hdseedid": "0000000000000000000000000000000000000000", "hdmasterfingerprint": "e18dae20", "labels": [ "" ] } ``` This reveals the descriptor for this individual address: ``` "desc": "wpkh([e18dae20/84h/1h/0h/0/2]02040bf9b12e48bbbcbf72ef5197bc18067db378411ae6220f1d0a77da2ee7dbba)#dqt0983r", ``` You can compare that to the `parent_desc`, which contains the ranged descriptor that this address descriptor is descended from (and that you also saw when you listed out all of your descriptors): ``` "parent_desc": "wpkh([e18dae20/84h/1h/0h]tpubDC4ujMbsd9REzpGk3gnTjkrfJFw1NnvCpx6QBbLj3CHBzcLmVzssTVP8meRAM1WW4pZnK6SCCPGyzi9eMfzSXoeFMNprqtgxG71VRXTmetu/0/*)#3658f8sn", ``` They're in slightly different formats as the non-ranged address has the derivation path all together rather than it being split in two. But other than that, there are just two changes: * The wallet descriptor has a range of addresses `0/*`, while the address descriptor displays one specific index in that range `0/2`. * The checksums are different, as you'd expect due to the differences in the index number. That's all that's different between a wallet descriptor and an address descriptor (and that similarity is how the one is used to derive hundreds or thousands of the other). ## Derive Addresses from a Descriptor In fact, you can derive addresses from a descriptor on your own, without having to use the `getnewaddress` command again and again. This is done with the `deriveaddresses` command: you give it a ranged descriptor, then tell it how far to derive to: ``` $ bitcoin-cli deriveaddresses "wpkh([e18dae20/84h/1h/0h]tpubDC4ujMbsd9REzpGk3gnTjkrfJFw1NnvCpx6QBbLj3CHBzcLmVzssTVP8meRAM1WW4pZnK6SCCPGyzi9eMfzSXoeFMNprqtgxG71VRXTmetu/0/*)#3658f8sn" 2 [ "tb1q05ua6g7njnjrtsjc0t9w3jc6g2leeznasf4ny9", "tb1q0psqqqgy0fv5928wmk86ntu7hlax8dva7nl82p", "tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4" ] ``` This example shows the derivation of addresses from the BIP-84 ranged descriptor up through index "2". If you check this against the addresses created in in the previous section, you'll see they're just the same. Which is of course the whole point of descriptors! They are deterministically derived in the same way every time. The main purpose of this function would be to export addresses to other services (for example, if you wanted to export watch-only addresses to another wallet-app of if you wanted to watch a multisig address, as we will in chapter 7). > 📖 ***What is a watch-only address?*** A watch-only address allows you to watch for transactions related to an address (or to a whole family of addresses if you used a ranged descriptor), but not to spend funds on those addresses. ## Import Descriptors As shown in [§3.4](03_4_Understanding_the_Descriptor_Wallet.md), you can also import descriptors from one wallet to the other using the `importdescriptors` command. ``` $ bitcoin-cli importdescriptors '[{ "desc": "wpkh(tprv8ZgxMBicQKsPd1dP4NpsFDpsLUCnZ7oyn4UEbYLw7if1EDVCxMgfSzAwP3aCr1YeRvX9GtGvHsCLdrM7zaDyh33jEj7joQoEeNEyJaSYm5p/84h/1h/0h/0/*)#grdqnase", "timestamp":1770329126, "active": true, "range": [0,10] }]' ``` This command takes a JSON object that you can [reformat](https://jsonformatter.curiousconcept.com/) for better clarity: ``` [ { "desc":"wpkh(tprv8ZgxMBicQKsPd1dP4NpsFDpsLUCnZ7oyn4UEbYLw7if1EDVCxMgfSzAwP3aCr1YeRvX9GtGvHsCLdrM7zaDyh33jEj7joQoEeNEyJaSYm5p/84h/1h/0h/0/*)#grdqnase", "timestamp":1770329126, "active":true, "range":[ 0, 10 ] } ] ``` As shown, it has four variables: * **`desc`** is the descriptor. * **`timestamp`** tells your server how far to go back looking for transactions related to this address. * **`active`** says that this descriptor should be used to generate new addresses of this type in your wallet. * **`range`** lists which addresses to import from this descriptor. This is just a step back, because afterward you can derive addresses from that descriptor: > import descriptor ➡️ deriveaddresses ## Create a Descriptor by Hand You can step even further back! You can create a descriptor by hand, then import it, then derive addresses from it: > create descriptor ➡️ import descriptor ➡️ deriveaddresses The creation of a descriptor is simple because there's a designated format for each type. The [Bitcoin Core GitHub](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md) has a listing of all them. Following are a few examples. When you import these descriptors, you'll make a few changes from the `importdescriptors` example above: * **`active`** will not be set if this is not a ranged descriptor meant to become one of the defaults for creating new addresses. * **`range`* will not be set if the descriptor is for a single address. ### Create a Watch-Only Wallet One thing before you get started: your default wallet (`""`) is set to hold private keys. You can use that if you're importing descriptors where you have the private key, like the example above. However, if you want to import descriptors without private keys, you need to create a special watchonly wallet: ``` $ bitcoin-cli createwallet "watchonly" true true { "name": "watchonly" } ``` The two `true`s in this command are the magic sauce as shown in the help file: ``` 1. wallet_name (string, required) The name for the new wallet. If this is a path, the wallet will be created at the path location. 2. disable_private_keys (boolean, optional, default=false) Disable the possibility of private keys (only watchonlys are possible in this mode). 3. blank (boolean, optional, default=false) Create a blank wallet. A blank wallet has no keys. ``` The first `true` disables the use of private keys, the second `true` tells the wallet not to create keys of its own. Remember that you're going to have to use `loadwallet` and `unloadwallet` to cycle to the right wallet, or else use a `-rpcwallet` flag with every command to make sure you're using the wallet. (We'll do the latter in the following examples.) ### Create an Address Descriptor An address descriptor takes the form: ``` addr(ADDR) ``` Using this address descriptor would allow you to import one of the addresses you'd already created into another wallet. Creating a descriptor and importing it into Bitcoin Core is always a three-step process: 1. Create the descriptor. ``` addr(tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4) ``` 2. Feed the descriptor into `getdescriptorinfo` to get a checksum. ``` $ bitcoin-cli getdescriptorinfo "addr(tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4)" { "descriptor": "addr(tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4)#4vmsvy3l", "checksum": "4vmsvy3l", "isrange": false, "issolvable": false, "hasprivatekeys": false } ``` 3. Import the descriptor with checksum. ``` $ bitcoin-cli -rpcwallet=watchonly importdescriptors '[{ "desc": "addr(tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4)#4vmsvy3l", "timestamp":1770329126 }]' [ { "success": true } ] ``` Looking at the newly imported address reveals that the metadata is somewhat different from what was in the original wallet: ``` $ bitcoin-cli -rpcwallet=watchonly getaddressinfo tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4 { "address": "tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4", "scriptPubKey": "00142a4f27c78470206e1a5948b47478d5b37991aac4", "ismine": true, "solvable": false, "parent_desc": "addr(tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4)#4vmsvy3l", "iswatchonly": false, "isscript": false, "iswitness": true, "witness_version": 0, "witness_program": "2a4f27c78470206e1a5948b47478d5b37991aac4", "ischange": false, "labels": [ "" ] } ``` For example, we no longer have the ranged `parent_desc` and this one is not `solvable` (we don't have the private key!). Nonetheless it's the same address, which means that it's unlocked in the same way (as shown by the identical `scriptPubKey`, a topic we'll return to). ### Create a Keyed Descriptor The `pk`, `pkh`, and `wpkh` descriptors are all equally easy to create, since they just the form of `function(key)`. If we go back to our original `getaddressinfo`, we can find that the public key for the address `tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4` is: ``` "pubkey": "02040bf9b12e48bbbcbf72ef5197bc18067db378411ae6220f1d0a77da2ee7dbba", ``` That means the wpkh descriptor would be: ``` wpkh(02040bf9b12e48bbbcbf72ef5197bc18067db378411ae6220f1d0a77da2ee7dbba) ``` We retrieve a checksum for it: ``` $ bitcoin-cli getdescriptorinfo "wpkh(02040bf9b12e48bbbcbf72ef5197bc18067db378411ae6220f1d0a77da2ee7dbba)" { "descriptor": "wpkh(02040bf9b12e48bbbcbf72ef5197bc18067db378411ae6220f1d0a77da2ee7dbba)#3303qrm5", "checksum": "3303qrm5", "isrange": false, "issolvable": true, "hasprivatekeys": false } ``` Then we import it: ``` bitcoin-cli -rpcwallet=watchonly importdescriptors '[{ "desc": "wpkh(02040bf9b12e48bbbcbf72ef5197bc18067db378411ae6220f1d0a77da2ee7dbba)#3303qrm5", "timestamp":1770329126 }]' [ { "success": true } ] ``` Voila, we have recreated our address using a descriptor and the public key: ``` $ bitcoin-cli -rpcwallet=watchonly getaddressesbylabel "" { "tb1q9f8j03uywqsxuxjefz68g7x4kduer2ky6shsf4": { "purpose": "receive" } } ``` > 📖 **Why didn't we supply a derivation path?** Derivation paths derive child keys from master keys. If we wanted to create a ranged descriptor we'd need a derivation path so that all the indexed keys could be created. Similarly, if we knew the master key but not the address key, we'd need a derivation path. In this case, we had the specific key for this specific address, and so no derivation path was needed. ## Create Other Descriptors This process could be repeated in a number of different ways. You could create a descriptor with a private key instead of a public key, and import it into regular (non-watchonly) wallet. You could create a ranged descriptor by hand and import a whole set of addresses. Although it's not best practice, you could even use the same key to create different types of addresses. (Try it out: just replace the "wpkh" above with "pkh", get a new checksum, and import and you'll have a P2PKH address instead of a P2WPKH address, unlocked by the same key.) The main purpose here is to show how descriptors work in practice, so that the link between descriptors and address is clear, and so you can easily create addresses from descriptors when it's helpful in the future, such as when we create multisigs in [§7.2](07_2_Creating_Multisig_Descriptors.md). ## Summary: Integrating Addresses and Descriptors In the modern Bitcoin ecosystem, addresses and descriptors go hand in hand—and it's not just that you use ranged descriptors to create sets of address. You can also step through a life cycle of descriptors: * You can create descriptors by hand. * You can import descriptors from other wallets. * You can derive addresses directly from descriptors. * You can view descriptors from individual addresses. These are powerful techniques that we may not use a lot on the command line, but which are crucial to an overall understand of how Bitcoin works. ## What's Next? Continue "Preparing Your Bitcoin Addresses" with [§4.3: Creating QR Codes for Address](04_3_Creating_QR_Codes_for_Addresses.md).