Skip to content

Commit c4bd07c

Browse files
logosstonethunderbiscuit
authored andcommitted
Add bdk-cli basics multi-sig 2 of 3
1 parent 77a0837 commit c4bd07c

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed

docs/.vuepress/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const tutorialSidebar = [
6060
'/tutorials/using_bdk_with_hardware_wallets',
6161
'/tutorials/exploring_bdk_flutter',
6262
'/tutorials/bdk_cli_basics',
63+
'/tutorials/bdk-cli_basics_multisig_2of3'
6364
],
6465
}
6566
]
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
---
2+
title: "bdk-cli basics multi-sig 2 of 3 tutorial"
3+
description: "Tutorial using command-line to create a 2 of 3 multi-sig Wallet and Spend"
4+
authors:
5+
- waterstone
6+
date: "2022-10-17"
7+
tags: ["tutorial", "bdk-cli","multi-sig"]
8+
hidden: false
9+
draft: false
10+
---
11+
12+
## 2-of-3 Multi-Signature Descriptor Wallet using bdk-cli
13+
14+
## Overview of the tutorial
15+
- The purpose of this tutorial is to continue learning `bdk-cli` as our tool to manage a 2 of 3 multi-signature wallet.
16+
- Generate a receive address with a spending Policy of 2 out of 3 escrow aka multi-signature.
17+
- Intro to more complex but standard policies to create custom encumberances aka custom spending conditions for transactions.
18+
19+
Note that to complete this tutorial, you'll need to enable the `compiler` and `electrum` flags when installing or building bdk-cli, for example by installing using:
20+
```shell
21+
cargo install bdk-cli --features=compiler,electrum
22+
```
23+
24+
## Step 1: Generate the XPRVs (Extended-Keys) and Save to environment variables
25+
26+
> Create three private keys and each in their own environment variable
27+
28+
:arrow_forward: `export XPRV_00=$(bdk-cli key generate | jq -r '.xprv')`
29+
30+
:arrow_forward: `export XPRV_01=$(bdk-cli key generate | jq -r '.xprv')`
31+
32+
:arrow_forward: `export XPRV_02=$(bdk-cli key generate | jq -r '.xprv')`
33+
34+
35+
![](https://i.imgur.com/FwgUdwK.gif)
36+
37+
### 1a: Verify XPRV environment variables are Active
38+
39+
:arrow_forward: `env | grep XPRV`
40+
41+
![](https://i.imgur.com/ZerGPbO.gif)
42+
43+
44+
## Step 2: Generate XPUBs (Extended Public Keys) & Save to environment variables
45+
46+
> Generate the three individual Public Keys aka XPUBs using our Private key and descriptor path.
47+
48+
:arrow_forward: `export XPUB_00=$(bdk-cli key derive --xprv $XPRV_00 --path "m/84'/1'/0'/0" | jq -r ".xpub")`
49+
50+
:arrow_forward: `export XPUB_01=$(bdk-cli key derive --xprv $XPRV_01 --path "m/84'/1'/0'/0" | jq -r ".xpub")`
51+
52+
:arrow_forward: `export XPUB_02=$(bdk-cli key derive --xprv $XPRV_02 --path "m/84'/1'/0'/0" | jq -r ".xpub")`
53+
54+
55+
![](https://i.imgur.com/xT3KRh4.gif)
56+
57+
### 2a: Verify XPUB environment variables
58+
59+
:arrow_forward: `env | grep XPUB`
60+
61+
![](https://i.imgur.com/SzAip9E.gif)
62+
63+
***
64+
## Step 3: Create Single-Wallet Descriptors
65+
66+
> Create the wallet Descriptor for each wallet
67+
68+
:arrow_forward: `export DESCRIPTOR_00="$XPRV_00/84h/1h/0h/0/*"`
69+
70+
:arrow_forward: `export DESCRIPTOR_01="$XPRV_01/84h/1h/0h/0/*"`
71+
72+
:arrow_forward: `export DESCRIPTOR_02="$XPRV_02/84h/1h/0h/0/*"`
73+
74+
75+
![](https://i.imgur.com/mFrWt6b.png)
76+
77+
78+
## Step 4: Create Multi-Sig-Descriptor Wallets
79+
> This is how you create the 2-of-3 multi-sig output descriptor. You will need (one PrivateKey and two Xpubs) It consists of using the `compiler` function to parse `policy` to `mini-script` .
80+
81+
- When creating the descriptor the order matters so be aware of that when following tutorial if you are for any reason changing the order of the policy.
82+
#### Multi-Sig-Wallet 0
83+
- [ ] :arrow_forward: `export MULTI_DESCRIPTOR_00=$(bdk-cli compile "thresh(2,pk($DESCRIPTOR_00),pk($XPUB_01),pk($XPUB_02))" | jq -r '.descriptor')`
84+
85+
#### Multi-Sig-Wallet 1
86+
- [ ] :arrow_forward: `export MULTI_DESCRIPTOR_01=$(bdk-cli compile "thresh(2,pk($XPUB_00),pk($DESCRIPTOR_01),pk($XPUB_02))" | jq -r '.descriptor')`
87+
88+
#### Multi-Sig-Wallet 2
89+
- [ ] :arrow_forward: `export MULTI_DESCRIPTOR_02=$(bdk-cli compile "thresh(2,pk($XPUB_00),pk($XPUB_01),pk($DESCRIPTOR_02))" | jq -r '.descriptor')`
90+
91+
![](https://i.imgur.com/Yb8RmFS.gif)
92+
93+
#### multi-sig 2 of 3 policy gets compiled to miniscript
94+
```shell
95+
# policy
96+
thresh(2,pk(XPRV_A),pk(XPUB_B),pk(XPUB_C))
97+
98+
# miniscript
99+
wsh(multi(2,XPRV_KEY,PUBKEY_B,XPUB_C))
100+
```
101+
102+
103+
***
104+
105+
106+
### 4a: Verify Multi-Sig-Descriptor environment variables are active
107+
108+
:arrow_forward: `env | grep MULTI`
109+
110+
111+
![](https://i.imgur.com/aAgtlsi.gif)
112+
113+
***
114+
115+
## Step 5: Generate Receive Address by using Multi-Sig-Descriptor Wallets
116+
117+
:arrow_forward: `bdk-cli wallet --wallet wallet_name_msd00 --descriptor $MULTI_DESCRIPTOR_00 get_new_address`
118+
119+
:arrow_forward: `bdk-cli wallet --wallet wallet_name_msd01 --descriptor $MULTI_DESCRIPTOR_01 get_new_address`
120+
121+
:arrow_forward: `bdk-cli wallet --wallet wallet_name_msd02 --descriptor $MULTI_DESCRIPTOR_02 get_new_address`
122+
123+
![](https://i.imgur.com/w1fxPSn.gif)
124+
125+
126+
:red_circle: Did you generate the same address for all three? Good! Else, something might be incorrect.
127+
128+
## Step 6: Send Testnet Bitcoin to the newly created receive-address
129+
130+
[Bitcoin Testnet Faucet link:1](https://testnet-faucet.mempool.co)
131+
[Bitcoin Testnet Faucet link:2](https://bitcoinfaucet.uo1.net)
132+
133+
## Step 7: Sync one of the Multi-Sig Wallets
134+
135+
:arrow_forward: ` bdk-cli wallet --wallet wallet_name_msd00 --descriptor $MULTI_DESCRIPTOR_00 sync`
136+
137+
![](https://i.imgur.com/GuefgeI.gif)
138+
139+
140+
## Step 8: Check Balance Multi-Sig Wallets
141+
142+
143+
:arrow_forward: ` bdk-cli wallet --wallet wallet_name_msd00 --descriptor $MULTI_DESCRIPTOR_00 get_balance`
144+
145+
![](https://i.imgur.com/zNciCqF.gif)
146+
147+
148+
- Every wallet has access to sync and view balance.
149+
150+
## Step 9: Check Multi-Sig Policies on Descriptor Wallet
151+
:arrow_forward:` bdk-cli wallet --wallet wallet_name_msd00 --descriptor $MULTI_DESCRIPTOR_00 policies`
152+
153+
The output below confirms the command was successful.
154+
```shell
155+
{
156+
"external": {
157+
"contribution": {
158+
"conditions": {
159+
"0": [
160+
{}
161+
]
162+
},
163+
"items": [
164+
0
165+
],
166+
"m": 2,
167+
"n": 3,
168+
"sorted": false,
169+
"type": "PARTIAL"
170+
},
171+
"id": "seaxtqqn",
172+
"keys": [
173+
{
174+
"fingerprint": "7cdf2d46"
175+
},
176+
{
177+
"fingerprint": "fc7870cd"
178+
},
179+
{
180+
"fingerprint": "26b03333"
181+
}
182+
],
183+
"satisfaction": {
184+
"items": [],
185+
"m": 2,
186+
"n": 3,
187+
"sorted": false,
188+
"type": "PARTIAL"
189+
},
190+
"threshold": 2,
191+
"type": "MULTISIG"
192+
},
193+
"internal": null
194+
}
195+
196+
197+
```
198+
199+
### SpendingPolicyRequired for complex descriptors
200+
201+
```shell
202+
--external_policy "{\"seaxtqqn\": [0,1]}"
203+
<-rootnode-><children #0 and #1 of root node>
204+
```
205+
206+
> Save the "id": We will need to use this ''id'' later.
207+
208+
More info on [external policies here](https://bitcoindevkit.org/bdk-cli/interface/)
209+
210+
## Step 10: Create a Transaction (PSBT)
211+
- 1st Create a PSBT using the first wallet
212+
- 2nd Sign the PSBT with the first wallet
213+
- 3rd Sign PSBT with the second wallet
214+
- Broadcast PSBT
215+
216+
### Export UNSIGNED_PSBT to environment variable
217+
:arrow_forward: `export UNSIGNED_PSBT=$(bdk-cli wallet --wallet wallet_name_msd00 --descriptor $MULTI_DESCRIPTOR_00 create_tx --send_all --to mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt:0 --external_policy "{\"CHANGE_ID_HERE\": [0,1]}" | jq -r '.psbt')`
218+
219+
### Verify UNSIGNED_PSBT environment variable
220+
:arrow_forward: `env | grep UNSIGNED`
221+
![](https://i.imgur.com/djHaRDq.gif)
222+
223+
## Step 11: SIGN the Transaction
224+
225+
### 1st Wallet Signs the transaction
226+
227+
:arrow_forward: `bdk-cli wallet --wallet wallet_name_msd00 --descriptor $MULTI_DESCRIPTOR_00 sign --psbt $UNSIGNED_PSBT`
228+
229+
:arrow_forward: `export ONESIG_PSBT=$(bdk-cli wallet --wallet wallet_name_msd00 --descriptor $MULTI_DESCRIPTOR_00 sign --psbt $UNSIGNED_PSBT | jq -r '.psbt')`
230+
231+
:arrow_forward:`env | grep ONESIG`
232+
233+
```
234+
{
235+
"is_finalized": false,
236+
"psbt": "cHNidP8BAFUBAAAAAdYCtva/7Rkt+fgFu3mxAdaPh4uTbgBL3HmYZgcEKWygAAAAAAD/////AQqGAQAAAAAAGXapFDRKD0jKFQ7CuQOBdmC5tosTpnAmiKwAAAAAAAEA6gIAAAAAAQFLyGFJFK884DGBM1WgskRZ6gKp/7oZ+Z30u0+wF3pZYAEAAAAA/v///wKghgEAAAAAACIAINHcOQLE6GpJ3J+FOzn/be+HApxW8sZtGqfA3TBW+NYX91hoOAAAAAAWABTPQDZx2wYYIn+ug2pZBmWBn0Tu/gJHMEQCIHu6GmRMDgPZyTx+klFMA9VujR3qDA/Y08kSkRvOaChjAiBAtExtGAYLuQ/DDJzCqLlNZ1bMB3MV+nxsLfTdI9YcYwEhA0b8lz+kt0xHfR/tjUKOc2Nt2L61pDd5vJ/lsKi8pw9MmFUjAAEBK6CGAQAAAAAAIgAg0dw5AsToakncn4U7Of9t74cCnFbyxm0ap8DdMFb41hciAgIjUCIdnyr6rDtuNhVNt4ZBDcvYLawfoJbzbPyxc/WNDUgwRQIhAJdILr7G3UzYylyr2fA13MFsz/jG4+iZlKeEkX79d082AiA99UF0/uFyXBVNUmuGaxdHL7wlhzqfbgGLMREN0z/O6QEBBWlSIQIjUCIdnyr6rDtuNhVNt4ZBDcvYLawfoJbzbPyxc/WNDSEDzsDXexRPSxeXiLJoS0i2fQlOoOGHmo+Dhaeaq3oHV6YhAjGKA2Dqg+QeMICBAifYslQF2WrehLEQ0iEOpp/+eQ0NU64iBgIjUCIdnyr6rDtuNhVNt4ZBDcvYLawfoJbzbPyxc/WNDRh83y1GVAAAgAEAAIAAAACAAAAAAAAAAAAiBgIxigNg6oPkHjCAgQIn2LJUBdlq3oSxENIhDqaf/nkNDRgmsDMzVAAAgAEAAIAAAACAAAAAAAAAAAAiBgPOwNd7FE9LF5eIsmhLSLZ9CU6g4Yeaj4OFp5qregdXphj8eHDNVAAAgAEAAIAAAACAAAAAAAAAAAAAAA=="
237+
}
238+
```
239+
240+
![](https://i.imgur.com/0w4sK5y.gif)
241+
242+
### 2nd Wallet Signs the transaction
243+
:arrow_forward: `bdk-cli wallet --wallet wallet_name_msd01 --descriptor $MULTI_DESCRIPTOR_01 sign --psbt $ONESIG_PSBT`
244+
245+
:arrow_forward: `export SECONDSIG_PSBT=$(bdk-cli wallet --wallet wallet_name_msd01 --descriptor $MULTI_DESCRIPTOR_01 sign --psbt $ONESIG_PSBT | jq -r '.psbt')`
246+
247+
248+
:arrow_forward:`env | grep SECONDSIG`
249+
250+
```
251+
{
252+
"is_finalized": true,
253+
"psbt": "cHNidP8BAFUBAAAAAdYCtva/7Rkt+fgFu3mxAdaPh4uTbgBL3HmYZgcEKWygAAAAAAD/////AQqGAQAAAAAAGXapFDRKD0jKFQ7CuQOBdmC5tosTpnAmiKwAAAAAAAEA6gIAAAAAAQFLyGFJFK884DGBM1WgskRZ6gKp/7oZ+Z30u0+wF3pZYAEAAAAA/v///wKghgEAAAAAACIAINHcOQLE6GpJ3J+FOzn/be+HApxW8sZtGqfA3TBW+NYX91hoOAAAAAAWABTPQDZx2wYYIn+ug2pZBmWBn0Tu/gJHMEQCIHu6GmRMDgPZyTx+klFMA9VujR3qDA/Y08kSkRvOaChjAiBAtExtGAYLuQ/DDJzCqLlNZ1bMB3MV+nxsLfTdI9YcYwEhA0b8lz+kt0xHfR/tjUKOc2Nt2L61pDd5vJ/lsKi8pw9MmFUjAAEBK6CGAQAAAAAAIgAg0dw5AsToakncn4U7Of9t74cCnFbyxm0ap8DdMFb41hciAgIjUCIdnyr6rDtuNhVNt4ZBDcvYLawfoJbzbPyxc/WNDUgwRQIhAJdILr7G3UzYylyr2fA13MFsz/jG4+iZlKeEkX79d082AiA99UF0/uFyXBVNUmuGaxdHL7wlhzqfbgGLMREN0z/O6QEiAgPOwNd7FE9LF5eIsmhLSLZ9CU6g4Yeaj4OFp5qregdXpkgwRQIhAO2aRERcublhAzToshkZRMg2I8GaE7mM2ECr0vYyuscmAiB5KK4ETlvrLqL0QbcRbGqrSwIa9lVuOqP3f5qCnGRMaQEBBWlSIQIjUCIdnyr6rDtuNhVNt4ZBDcvYLawfoJbzbPyxc/WNDSEDzsDXexRPSxeXiLJoS0i2fQlOoOGHmo+Dhaeaq3oHV6YhAjGKA2Dqg+QeMICBAifYslQF2WrehLEQ0iEOpp/+eQ0NU64iBgIjUCIdnyr6rDtuNhVNt4ZBDcvYLawfoJbzbPyxc/WNDRh83y1GVAAAgAEAAIAAAACAAAAAAAAAAAAiBgIxigNg6oPkHjCAgQIn2LJUBdlq3oSxENIhDqaf/nkNDRgmsDMzVAAAgAEAAIAAAACAAAAAAAAAAAAiBgPOwNd7FE9LF5eIsmhLSLZ9CU6g4Yeaj4OFp5qregdXphj8eHDNVAAAgAEAAIAAAACAAAAAAAAAAAABBwABCP3+AAQASDBFAiEAl0guvsbdTNjKXKvZ8DXcwWzP+Mbj6JmUp4SRfv13TzYCID31QXT+4XJcFU1Sa4ZrF0cvvCWHOp9uAYsxEQ3TP87pAUgwRQIhAO2aRERcublhAzToshkZRMg2I8GaE7mM2ECr0vYyuscmAiB5KK4ETlvrLqL0QbcRbGqrSwIa9lVuOqP3f5qCnGRMaQFpUiECI1AiHZ8q+qw7bjYVTbeGQQ3L2C2sH6CW82z8sXP1jQ0hA87A13sUT0sXl4iyaEtItn0JTqDhh5qPg4Wnmqt6B1emIQIxigNg6oPkHjCAgQIn2LJUBdlq3oSxENIhDqaf/nkNDVOuAAA="
254+
}
255+
```
256+
257+
![](https://i.imgur.com/OdLHnJ3.gif)
258+
259+
## Step 12: Broadcast Transaction
260+
261+
:arrow_forward: `bdk-cli wallet --wallet wallet_name_msd01 --descriptor $MULTI_DESCRIPTOR_01 broadcast --psbt $SECONDSIG_PSBT`
262+
263+
```
264+
{
265+
"txid": "61da2451874a483aa8d1d0787c7680d157639f284840de8885098cac43f6cc2f"
266+
}
267+
```
268+
269+
![](https://i.imgur.com/M7s0Fd6.gif)
270+
271+
### Verify Transaction
272+
Verify transcation in the memory pool on testnet [Mempool-testnet!](https://mempool.space/testnet)

0 commit comments

Comments
 (0)