use std::io::{self, Write}; use bitcoin::{ bip32, blockdata::script::Builder, consensus::encode::Decodable, network::constants::Network, psbt, Address, Sequence, Transaction, TxIn, TxOut, }; use trezor_client::{Error, SignTxProgress, TrezorMessage, TrezorResponse}; fn handle_interaction(resp: TrezorResponse) -> T { match resp { TrezorResponse::Ok(res) => res, // assering ok() returns the failure error TrezorResponse::Failure(_) => resp.ok().unwrap(), TrezorResponse::ButtonRequest(req) => handle_interaction(req.ack().unwrap()), TrezorResponse::PinMatrixRequest(req) => { println!("Enter PIN"); let mut pin = String::new(); if io::stdin().read_line(&mut pin).unwrap() != 5 { println!("must enter pin, received: {}", pin); } // trim newline handle_interaction(req.ack_pin(pin[..4].to_owned()).unwrap()) } TrezorResponse::PassphraseRequest(req) => { println!("Enter passphrase"); let mut pass = String::new(); io::stdin().read_line(&mut pass).unwrap(); // trim newline handle_interaction(req.ack_passphrase(pass[..pass.len() - 1].to_owned()).unwrap()) } } } fn tx_progress( psbt: &mut psbt::PartiallySignedTransaction, progress: SignTxProgress, raw_tx: &mut Vec, ) -> Result<(), Error> { if let Some(part) = progress.get_serialized_tx_part() { raw_tx.write_all(part).unwrap(); } if !progress.finished() { let progress = handle_interaction(progress.ack_psbt(psbt, Network::Testnet).unwrap()); tx_progress(psbt, progress, raw_tx) } else { Ok(()) } } fn main() { tracing_subscriber::fmt().with_max_level(tracing::Level::TRACE).init(); // init with debugging let mut trezor = trezor_client::unique(false).unwrap(); trezor.init_device(None).unwrap(); let pubkey = handle_interaction( trezor .get_public_key( &vec![ bip32::ChildNumber::from_hardened_idx(0).unwrap(), bip32::ChildNumber::from_hardened_idx(0).unwrap(), bip32::ChildNumber::from_hardened_idx(1).unwrap(), ] .into(), trezor_client::protos::InputScriptType::SPENDADDRESS, Network::Testnet, true, ) .unwrap(), ); let addr = Address::p2pkh(&pubkey.to_pub(), Network::Testnet); println!("address: {}", addr); let mut psbt = psbt::PartiallySignedTransaction { unsigned_tx: Transaction { version: 1, lock_time: bitcoin::absolute::LockTime::from_consensus(0), input: vec![TxIn { previous_output: "c5bdb27907b78ce03f94e4bf2e94f7a39697b9074b79470019e3dbc76a10ecb6:0".parse().unwrap(), sequence: Sequence(0xffffffff), script_sig: Builder::new().into_script(), witness: Default::default(), }], output: vec![TxOut { value: 14245301, script_pubkey: addr.script_pubkey(), }], }, inputs: vec![psbt::Input { non_witness_utxo: Some(Transaction::consensus_decode(&mut &hex::decode("020000000001011eb5a3e65946f88b00d67b321e5fd980b32a2316fb1fc9b712baa6a1033a04e30100000017160014f0f81ee77d552b4c81497451d1abf5c22ce8e352feffffff02b55dd900000000001976a9142c3cf5686f47c1de9cc90b4255cc2a1ef8c01b3188acfb0391ae6800000017a914a3a79e37ad366d9bf9471b28a9a8f64b50de0c968702483045022100c0aa7b262967fc2803c8a9f38f26682edba7cafb7d4870ebdc116040ad5338b502205dfebd08e993af2e6aa3118a438ad70ed9f6e09bc6abfd21f8f2957af936bc070121031f4e69fcf110bb31f019321834c0948b5487f2782489f370f66dc20f7ac767ca8bf81500").unwrap()[..]).unwrap()), ..Default::default() }], outputs: vec![ psbt::Output { ..Default::default() }, ], proprietary: Default::default(), unknown: Default::default(), version: 0, xpub: Default::default(), }; println!("psbt before: {:?}", psbt); println!("unsigned txid: {}", psbt.unsigned_tx.txid()); println!( "unsigned tx: {}", hex::encode(bitcoin::consensus::encode::serialize(&psbt.unsigned_tx)) ); let mut raw_tx = Vec::new(); let progress = handle_interaction(trezor.sign_tx(&psbt, Network::Testnet).unwrap()); tx_progress(&mut psbt, progress, &mut raw_tx).unwrap(); println!("signed tx: {}", hex::encode(raw_tx)); }