1#[cfg(test)]
30#[macro_use]
31extern crate serial_test;
32
33pub use interface::HWIClient;
34
35#[cfg(feature = "doctest")]
36pub mod doctest;
37pub mod error;
38pub mod interface;
39pub mod types;
40
41#[cfg(test)]
42mod tests {
43 use crate::types::{self, HWIDeviceType, TESTNET};
44 use crate::HWIClient;
45 use std::collections::BTreeMap;
46 use std::str::FromStr;
47
48 use bitcoin::util::bip32::{DerivationPath, KeySource};
49 use bitcoin::psbt::{Input, Output};
50 use bitcoin::{LockTime, secp256k1, Transaction};
51 use bitcoin::{Network, TxIn, TxOut};
52
53 #[cfg(feature = "miniscript")]
54 use miniscript::{Descriptor, DescriptorPublicKey};
55
56 #[test]
57 #[serial]
58 fn test_enumerate() {
59 let devices = HWIClient::enumerate().unwrap();
60 assert!(devices.len() > 0);
61 }
62
63 #[test]
64 #[serial]
65 #[ignore]
66 fn test_find_trezor_device() {
67 HWIClient::find_device(
68 None,
69 Some(HWIDeviceType::Trezor),
70 None,
71 false,
72 Network::Testnet,
73 )
74 .unwrap();
75 }
76
77 fn get_first_device() -> HWIClient {
78 let devices = HWIClient::enumerate().unwrap();
79 let device = devices
80 .first()
81 .expect("No devices found. Either plug in a hardware wallet, or start a simulator.")
82 .as_ref()
83 .expect("Error when opening the first device");
84 HWIClient::get_client(&device, true, TESTNET).unwrap()
85 }
86
87 #[test]
88 #[serial]
89 fn test_get_master_xpub() {
90 let client = get_first_device();
91 client
92 .get_master_xpub(types::HWIAddressType::Wit, 0)
93 .unwrap();
94 }
95
96 #[test]
97 #[serial]
98 fn test_get_xpub() {
99 let client = get_first_device();
100 let derivation_path = DerivationPath::from_str("m/44'/1'/0'/0/0").unwrap();
101 client.get_xpub(&derivation_path, false).unwrap();
102 }
103
104 #[test]
105 #[serial]
106 fn test_sign_message() {
107 let client = get_first_device();
108 let derivation_path = DerivationPath::from_str("m/44'/1'/0'/0/0").unwrap();
109 client
110 .sign_message("I love BDK wallet", &derivation_path)
111 .unwrap();
112 }
113
114 #[test]
115 #[serial]
116 fn test_get_string_descriptors() {
117 let client = get_first_device();
118 let account = Some(10);
119 let descriptor = client.get_descriptors::<String>(account).unwrap();
120 assert!(descriptor.internal.len() > 0);
121 assert!(descriptor.receive.len() > 0);
122 }
123
124 #[test]
125 #[serial]
126 fn test_display_address_with_string_desc() {
127 let client = get_first_device();
128 let descriptor = client.get_descriptors::<String>(None).unwrap();
129 let descriptor = descriptor.receive.first().unwrap();
130 client.display_address_with_desc(descriptor).unwrap();
131 }
132
133 #[test]
134 #[serial]
135 #[cfg(feature = "miniscript")]
136 fn test_get_miniscript_descriptors() {
137 let client = get_first_device();
138 let account = Some(10);
139 let descriptor = client
140 .get_descriptors::<Descriptor<DescriptorPublicKey>>(account)
141 .unwrap();
142 assert!(descriptor.internal.len() > 0);
143 assert!(descriptor.receive.len() > 0);
144 }
145
146 #[test]
147 #[serial]
148 #[cfg(feature = "miniscript")]
149 fn test_display_address_with_miniscript_desc() {
150 let client = get_first_device();
151 let descriptor = client
152 .get_descriptors::<Descriptor<DescriptorPublicKey>>(None)
153 .unwrap();
154 let descriptor = descriptor.receive.first().unwrap();
155 client.display_address_with_desc(descriptor).unwrap();
156 }
157
158 #[test]
159 #[serial]
160 fn test_display_address_with_path_legacy() {
161 let client = get_first_device();
162 let derivation_path = DerivationPath::from_str("m/44'/1'/0'/0/0").unwrap();
163 client
164 .display_address_with_path(&derivation_path, types::HWIAddressType::Legacy)
165 .unwrap();
166 }
167
168 #[test]
169 #[serial]
170 fn test_display_address_with_path_nested_segwit() {
171 let client = get_first_device();
172 let derivation_path = DerivationPath::from_str("m/49'/1'/0'/0/0").unwrap();
173
174 client
175 .display_address_with_path(&derivation_path, types::HWIAddressType::Sh_Wit)
176 .unwrap();
177 }
178
179 #[test]
180 #[serial]
181 fn test_display_address_with_path_native_segwit() {
182 let client = get_first_device();
183 let derivation_path = DerivationPath::from_str("m/84'/1'/0'/0/0").unwrap();
184
185 client
186 .display_address_with_path(&derivation_path, types::HWIAddressType::Wit)
187 .unwrap();
188 }
189
190 #[test]
196 #[serial]
197 fn test_sign_tx() {
198 let devices = HWIClient::enumerate().unwrap();
199 let device = devices.first().unwrap().as_ref().unwrap();
200 let client = HWIClient::get_client(&device, true, TESTNET).unwrap();
201 let derivation_path = DerivationPath::from_str("m/44'/1'/0'/0/0").unwrap();
202
203 let address = client
204 .display_address_with_path(&derivation_path, types::HWIAddressType::Legacy)
205 .unwrap();
206
207 let pk = client.get_xpub(&derivation_path, true).unwrap();
208 let mut hd_keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = Default::default();
209 hd_keypaths.insert(pk.public_key, (device.fingerprint, derivation_path));
211
212 let script_pubkey = address.address.script_pubkey();
213
214 let previous_tx = Transaction {
215 version: 1,
216 lock_time: LockTime::from_consensus(0).into(),
217 input: vec![TxIn::default()],
218 output: vec![TxOut {
219 value: 100,
220 script_pubkey: script_pubkey.clone(),
221 }],
222 };
223
224 let previous_txin = TxIn {
225 previous_output: bitcoin::OutPoint {
226 txid: previous_tx.txid(),
227 vout: Default::default(),
228 },
229 ..Default::default()
230 };
231 let psbt = bitcoin::psbt::PartiallySignedTransaction {
232 unsigned_tx: Transaction {
233 version: 1,
234 lock_time: LockTime::from_consensus(0).into(),
235 input: vec![previous_txin],
236 output: vec![TxOut {
237 value: 50,
238 script_pubkey: script_pubkey,
239 }],
240 },
241 xpub: Default::default(),
242 version: Default::default(),
243 proprietary: Default::default(),
244 unknown: Default::default(),
245
246 inputs: vec![Input {
247 non_witness_utxo: Some(previous_tx),
248 witness_utxo: None,
249 bip32_derivation: hd_keypaths,
250 ..Default::default()
251 }],
252 outputs: vec![Output::default()],
253 };
254 let client = get_first_device();
255 client.sign_tx(&psbt).unwrap();
256 }
257
258 #[test]
259 #[serial]
260 fn test_get_keypool() {
261 let client = get_first_device();
262 let keypool = true;
263 let internal = false;
264 let address_type = types::HWIAddressType::Legacy;
265 let account = Some(8);
266 let derivation_path = DerivationPath::from_str("m/44'/1'/0'").unwrap();
267 let start = 1;
268 let end = 5;
269 client
270 .get_keypool(
271 keypool,
272 internal,
273 address_type,
274 false,
275 account,
276 Some(&derivation_path),
277 start,
278 end,
279 )
280 .unwrap();
281
282 let keypool = true;
283 let internal = true;
284 let address_type = types::HWIAddressType::Wit;
285 let account = None;
286 let start = 1;
287 let end = 8;
288 client
289 .get_keypool(
290 keypool,
291 internal,
292 address_type,
293 false,
294 account,
295 None,
296 start,
297 end,
298 )
299 .unwrap();
300
301 let keypool = false;
302 let internal = true;
303 let address_type = types::HWIAddressType::Sh_Wit;
304 let account = Some(1);
305 let start = 0;
306 let end = 10;
307 client
308 .get_keypool(
309 keypool,
310 internal,
311 address_type,
312 false,
313 account,
314 Some(&derivation_path),
315 start,
316 end,
317 )
318 .unwrap();
319 }
320
321 #[test]
322 #[serial]
323 #[ignore]
324 fn test_install_udev_rules() {
325 if cfg!(target_os = "linux") {
326 HWIClient::install_udev_rules(None, None).unwrap()
327 }
328 }
329
330 #[test]
331 #[serial]
332 fn test_set_log_level() {
333 HWIClient::set_log_level(types::LogLevel::DEBUG).unwrap();
334 test_enumerate();
335 }
336
337 #[test]
338 #[serial]
339 fn test_toggle_passphrase() {
340 let devices = HWIClient::enumerate().unwrap();
341 let unsupported = [
342 HWIDeviceType::Ledger,
343 HWIDeviceType::BitBox01,
344 HWIDeviceType::Coldcard,
345 HWIDeviceType::Jade,
346 ];
347 for device in devices {
348 let device = device.unwrap();
349 if unsupported.contains(&device.device_type) {
350 continue;
352 }
353 let client = HWIClient::get_client(&device, true, TESTNET).unwrap();
354 client.toggle_passphrase().unwrap();
355 break;
356 }
357 }
358
359 #[test]
360 #[serial]
361 fn test_get_version() {
362 HWIClient::get_version().unwrap();
363 }
364
365 #[test]
366 #[serial]
367 #[ignore]
368 fn test_setup_trezor_device() {
370 let client = HWIClient::find_device(
371 None,
372 Some(HWIDeviceType::Trezor),
373 None,
374 false,
375 Network::Testnet,
376 )
377 .unwrap();
378 client.setup_device(Some("My Label"), None).unwrap();
379 }
380
381 #[test]
382 #[serial]
383 #[ignore]
384 fn test_restore_trezor_device() {
386 let client = HWIClient::find_device(
387 None,
388 Some(HWIDeviceType::Trezor),
389 None,
390 false,
391 Network::Testnet,
392 )
393 .unwrap();
394 client.restore_device(Some("My Label"), None).unwrap();
395 }
396
397 #[test]
398 #[serial]
399 fn test_backup_device() {
400 let devices = HWIClient::enumerate().unwrap();
401 let supported = [
402 HWIDeviceType::BitBox01,
403 HWIDeviceType::BitBox02,
404 HWIDeviceType::Coldcard,
405 ];
406 for device in devices {
407 let device = device.unwrap();
408 if supported.contains(&device.device_type) {
409 let client = HWIClient::get_client(&device, true, TESTNET).unwrap();
410 client.backup_device(Some("My Label"), None).unwrap();
411 }
412 }
413 }
414
415 #[test]
416 #[serial]
417 #[ignore]
418 fn test_wipe_device() {
419 let devices = HWIClient::enumerate().unwrap();
420 let unsupported = [
421 HWIDeviceType::Ledger,
422 HWIDeviceType::Coldcard,
423 HWIDeviceType::Jade,
424 ];
425 for device in devices {
426 let device = device.unwrap();
427 if unsupported.contains(&device.device_type) {
428 continue;
430 }
431 let client = HWIClient::get_client(&device, true, TESTNET).unwrap();
432 client.wipe_device().unwrap();
433 }
434 }
435
436 #[test]
437 #[serial]
438 #[ignore]
439 fn test_install_hwi() {
440 HWIClient::install_hwilib(Some("2.1.1")).unwrap();
441 }
442}